Подтвердить что ты не робот

Программный способ получения всех доступных языков (в сборках спутников)

Я разрабатываю многоязычное приложение, использующее файлы .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, но я получаю только большой список с большим количеством языков, которые я не использую, или пустой список.

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

4b9b3361

Ответ 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();
    });
}

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