以编程方式获取所有可用语言(在卫星程序集中)

发布于 2024-07-14 05:38:53 字数 585 浏览 7 评论 0原文

我正在使用 .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 中的所有元素,但我只得到一个包含更多我没有使用的语言的大列表,或者一个空列表。

有没有办法只获取支持的语言?

I'm designing a multilingual application using .resx files.

I have a few files like GlobalStrings.resx, GlobalStrings.es.resx, GlobalStrings.en.resx, etc.
When I want to use this, I just need to set Thread.CurrentThread.CurrentCulture.

The problem:
I have a combobox with all the available languages, but I'm loading this manually:

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

I've tried with

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

without any success. Also tried with all the elements in CultureTypes, but I'm only getting a big list with a lot more languages that I'm not using, or an empty list.

Is there any way to get only the supported languages?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

依 靠 2024-07-21 05:38:54

您可以以编程方式列出应用程序中可用的文化

// 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.");
    }
}

You can programatically list the cultures available in your application

// 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.");
    }
}
不喜欢何必死缠烂打 2024-07-21 05:38:54

基于 @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;
}

based on answer by @hans-holzbart but fixed to not return the InvariantCulture too and wrapped into a reusable method:

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;
}

using that method, you can get a list of strings to add to some ComboBox with the following:

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;
}
眉黛浅 2024-07-21 05:38:54

这将是基于以下声明的解决方案之一:
特定语言的每个附属程序集都具有相同的名称,但位于以特定文化命名的子文件夹中,例如 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)));
}

This would be one of solution on basis of following statement:
Each satellite assembly for a specific language is named the same but lies in a sub-folder named after the specific culture e.g. fr or 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)));
}
对风讲故事 2024-07-21 05:38:54

我不确定是否获取语言,也许您可​​以扫描安装文件夹中的 dll 文件,但将语言设置为不受支持的语言应该不是问题。

如果找不到特定于文化的文件,.NET 将回退到文化中立的资源,以便您可以安全地选择不受支持的语言。

只要您自己控制应用程序,您就可以将可用语言存储在应用程序设置中的某个位置。 只需一个带有区域性名称的逗号分隔字符串就足够了:“en, es”

I'm not sure about getting the languages, maybe you can scan your installation folder for dll-files, but setting your language to an unsupported language should not be a problem.

.NET will fallback to the culture neutral resources if no culture specific files can be found so you can safely select unsupported languages.

As long as you control the application yourself you could just store the available languages in a application setting somewhere. Just a comma-separated string with the culture names should suffice: "en, es"

破晓 2024-07-21 05:38:54

使用 Rune Grimstad 所说的,我最终得到这样的结果:

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)
    {

    }
}

,我仍然认为这不是一个好主意......

Using what Rune Grimstad said I end up with this:

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)
    {

    }
}

or another way

int pathLenght = executablePath.Length + 1;
foreach (string s in directories)
{
    try
    {
        cmbLanguage.Items.Add(CultureInfo.GetCultureInfo(s.Remove(0, pathLenght)));
    }
    catch (Exception)
    {

    }
}

I still don't think that this is a good idea ...

痴情 2024-07-21 05:38:54

指定要搜索的资源类型的通用答案。 使用反射但被缓存。

用法:

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();
    });
}

它可能会遇到与接受的答案相同的问题,因为可能会加载所有语言资源。

A generic answer where the resource type to search is specified. Uses reflection but is cached.

Usage:

List<string> comboBoxEntries = CommonUtil.CulturesOfResource<GlobalStrings>()
    .Select(cultureInfo => cultureInfo.NativeName)
    .ToList();

Implementation (Utility Class):

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();
    });
}

It may suffer the same issue with the accepted answer in that all the language resources will probably be loaded.

岛徒 2024-07-21 05:38:54

@“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();
}

@"Ankush Madankar" presents an interesting starting point but it has two problems:
1) Finds also resource folders for resources of refrenced assemblies
2) Doesn find the resource for the base assembly language

I won't try to solve issue 2) but for issue 1) the code should be

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();
}
世界如花海般美丽 2024-07-21 05:38:54

1. 获取用户首选的语言集,按优先顺序排列:

Windows.System.UserProfile.GlobalizationPreferences.Languages;

2. 获取或设置此语言的语言限定符上下文(应用程序):

Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Languages;

两者都是List

1. Gets the set of languages that are preferred by the user, in order of preference:

Windows.System.UserProfile.GlobalizationPreferences.Languages;

2. Gets or sets the language qualifier for this context (application):

Windows.ApplicationModel.Resources.Core.ResourceContext.GetForCurrentView().Languages;

Both are List<string>.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文