Программный способ получения всех доступных языков (в сборках спутников)
Я разрабатываю многоязычное приложение, использующее файлы .resx.
У меня есть несколько файлов, таких как GlobalStrings.resx, GlobalStrings.es.resx, GlobalStrings.en.resx и т.д.
Когда я хочу использовать это, мне просто нужно установить Thread.CurrentThread.CurrentCulture.
Проблема:
У меня есть combobox со всеми доступными языками, но я загружаю это вручную:
comboLanguage.Items.Add(CultureInfo.GetCultureInfo("en"));
comboLanguage.Items.Add(CultureInfo.GetCultureInfo("es"));
Я пробовал с
cmbLanguage.Items.AddRange(CultureInfo.GetCultures(CultureTypes.UserCustomCulture));
без каких-либо успехов. Также попробовали со всеми элементами в CultureTypes, но я получаю только большой список с большим количеством языков, которые я не использую, или пустой список.
Есть ли способ получить только поддерживаемые языки?
Ответы
Ответ 1
Используя то, что сказал Руне Гримстад, я в итоге:
string executablePath = Path.GetDirectoryName(Application.ExecutablePath);
string[] directories = Directory.GetDirectories(executablePath);
foreach (string s in directories)
{
try
{
DirectoryInfo langDirectory = new DirectoryInfo(s);
cmbLanguage.Items.Add(CultureInfo.GetCultureInfo(langDirectory.Name));
}
catch (Exception)
{
}
}
или другим способом
int pathLenght = executablePath.Length + 1;
foreach (string s in directories)
{
try
{
cmbLanguage.Items.Add(CultureInfo.GetCultureInfo(s.Remove(0, pathLenght)));
}
catch (Exception)
{
}
}
Я все еще не думаю, что это хорошая идея...
Ответ 2
Вы можете запрограммировать список культур, доступных в вашем приложении
// Pass the class name of your resources as a parameter e.g. MyResources for MyResources.resx
ResourceManager rm = new ResourceManager(typeof(MyResources));
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (CultureInfo culture in cultures)
{
try
{
ResourceSet rs = rm.GetResourceSet(culture, true, false);
// or ResourceSet rs = rm.GetResourceSet(new CultureInfo(culture.TwoLetterISOLanguageName), true, false);
string isSupported = (rs == null) ? " is not supported" : " is supported";
Console.WriteLine(culture + isSupported);
}
catch (CultureNotFoundException exc)
{
Console.WriteLine(culture + " is not available on the machine or is an invalid culture identifier.");
}
}
Ответ 3
основанный на ответе @hans-holzbart, но исправленный, чтобы не возвращать InvariantCulture и не был завершен в метод многократного использования:
public static IEnumerable<CultureInfo> GetAvailableCultures()
{
List<CultureInfo> result = new List<CultureInfo>();
ResourceManager rm = new ResourceManager(typeof(Resources));
CultureInfo[] cultures = CultureInfo.GetCultures(CultureTypes.AllCultures);
foreach (CultureInfo culture in cultures)
{
try
{
if (culture.Equals(CultureInfo.InvariantCulture)) continue; //do not use "==", won't work
ResourceSet rs = rm.GetResourceSet(culture, true, false);
if (rs != null)
result.Add(culture);
}
catch (CultureNotFoundException)
{
//NOP
}
}
return result;
}
с помощью этого метода вы можете получить список строк для добавления в некоторый ComboBox со следующим:
public static ObservableCollection<string> GetAvailableLanguages()
{
var languages = new ObservableCollection<string>();
var cultures = GetAvailableCultures();
foreach (CultureInfo culture in cultures)
languages.Add(culture.NativeName + " (" + culture.EnglishName + " [" + culture.TwoLetterISOLanguageName + "])");
return languages;
}
Ответ 4
Это будет одно из решений на основе следующего утверждения:
Каждая спутниковая сборка для определенного языка называется одинаковой, но находится в подпапке, названной в честь конкретной культуры, например. fr или fr-CA.
public IEnumerable<CultureInfo> GetSupportedCulture()
{
//Get all culture
CultureInfo[] culture = CultureInfo.GetCultures(CultureTypes.AllCultures);
//Find the location where application installed.
string exeLocation = Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(Assembly.GetExecutingAssembly().CodeBase).Path));
//Return all culture for which satellite folder found with culture code.
return culture.Where(cultureInfo => Directory.Exists(Path.Combine(exeLocation, cultureInfo.Name)));
}
Ответ 5
Я не уверен в получении языков, возможно, вы можете сканировать папку установки для dll файлов, но установка языка на неподдерживаемый язык не должна быть проблемой.
.NET вернется к нейтральным ресурсам культуры, если не будут найдены файлы определенной культуры, чтобы вы могли безопасно выбирать неподдерживаемые языки.
Пока вы сами управляете приложением, вы можете просто сохранить доступные языки в настройках приложения. Достаточно просто разделенная запятыми строка с именами культур: "en, es"
Ответ 6
@ "Ankush Madankar" представляет интересную отправную точку, но у нее есть две проблемы:
1) Находит также папки ресурсов для ресурсов оконечных сборок
2) Не найти ресурс для языка базовой сборки
Я не буду пытаться решить проблему 2), но для вопроса 1) код должен быть
public List<CultureInfo> GetSupportedCultures()
{
CultureInfo[] culture = CultureInfo.GetCultures(CultureTypes.AllCultures);
// get the assembly
Assembly assembly = Assembly.GetExecutingAssembly();
//Find the location of the assembly
string assemblyLocation =
Path.GetDirectoryName(Uri.UnescapeDataString(new UriBuilder(assembly.CodeBase).Path));
//Find the file anme of the assembly
string resourceFilename = Path.GetFileNameWithoutExtension(assembly.Location) + ".resources.dll";
//Return all culture for which satellite folder found with culture code.
return culture.Where(cultureInfo =>
assemblyLocation != null &&
Directory.Exists(Path.Combine(assemblyLocation, cultureInfo.Name)) &&
File.Exists(Path.Combine(assemblyLocation, cultureInfo.Name, resourceFilename))
).ToList();
}
Ответ 7
Общий ответ, где указан тип ресурса для поиска. Использует отражение, но кэшируется.
Использование:
List<string> comboBoxEntries = CommonUtil.CulturesOfResource<GlobalStrings>()
.Select(cultureInfo => cultureInfo.NativeName)
.ToList();
Реализация (класс утилит):
static ConcurrentDictionary<Type, List<CultureInfo>> __resourceCultures = new ConcurrentDictionary<Type, List<CultureInfo>>();
/// <summary>
/// Return the list of cultures that is supported by a Resource Assembly (usually collection of resx files).
/// </summary>
static public List<CultureInfo> CulturesOfResource<T>()
{
return __resourceCultures.GetOrAdd(typeof(T), (t) =>
{
ResourceManager manager = new ResourceManager(t);
return CultureInfo.GetCultures(CultureTypes.AllCultures)
.Where(c => !c.Equals(CultureInfo.InvariantCulture) &&
manager.GetResourceSet(c, true, false) != null)
.ToList();
});
}
С принятым ответом может возникнуть та же проблема, что все языковые ресурсы, вероятно, будут загружены.