Программный способ получить все доступные языки (в спутниковых сборках) - PullRequest
28 голосов
/ 16 февраля 2009

Я разрабатываю многоязычное приложение с использованием файлов .resx.

У меня есть несколько файлов, таких как GlobalStrings.resx, GlobalStrings.es.resx, GlobalStrings.en.resx и т. Д. Когда я хочу использовать это, мне просто нужно установить Thread.CurrentThread.CurrentCulture.

Проблема: У меня есть поле со всеми доступными языками, но я загружаю это вручную:

comboLanguage.Items.Add(CultureInfo.GetCultureInfo("en"));
comboLanguage.Items.Add(CultureInfo.GetCultureInfo("es"));

Я пробовал с

cmbLanguage.Items.AddRange(CultureInfo.GetCultures(CultureTypes.UserCustomCulture));

безуспешно. Также пробовал все элементы в CultureTypes, но я получаю только большой список с гораздо большим количеством языков, которые я не использую, или пустой список.

Можно ли получить только поддерживаемые языки?

Ответы [ 6 ]

47 голосов
/ 15 июня 2012

Вы можете программно перечислить культуры, доступные в вашем приложении

// 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.");
    }
}
4 голосов
/ 06 октября 2015

Это будет одним из решений на основе следующего утверждения:
Каждая сателлитная сборка для определенного языка называется одинаковой, но находится в подпапке, названной в честь конкретной культуры, например, франц. или франц. ка.

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)));
}
4 голосов
/ 23 августа 2015

основано на ответе @ 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;
}
2 голосов
/ 17 февраля 2009

Используя сказанное Руном Гримстадом, я получаю следующее:

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 голосов
/ 16 февраля 2009

Я не уверен в получении языков, может быть, вы можете отсканировать папку установки на наличие dll-файлов, но установка вашего языка на неподдерживаемый язык не должна быть проблемой.

.NET откатится на нейтральные к культуре ресурсы, если не найдены специфичные для культуры файлы, чтобы вы могли безопасно выбирать неподдерживаемые языки.

Пока вы сами управляете приложением, вы можете просто хранить доступные языки в настройках приложения. Достаточно просто разделить запятыми строку с именами культур: "en, es"

0 голосов
/ 05 мая 2018

@ "Анкуш Маданкар" представляет интересную отправную точку, но у нее есть две проблемы: 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();
}
...