Programmatic way to get all the available languages (in satellite assemblies)

前端 未结 7 486
青春惊慌失措
青春惊慌失措 2020-11-28 08:11

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 wa

相关标签:
7条回答
  • 2020-11-28 08:28

    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)));
    }
    
    0 讨论(0)
  • 2020-11-28 08:29

    @"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();
    }
    
    0 讨论(0)
  • 2020-11-28 08:34

    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.");
        }
    }
    
    0 讨论(0)
  • 2020-11-28 08:41

    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 ...

    0 讨论(0)
  • 2020-11-28 08:41

    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.

    0 讨论(0)
  • 2020-11-28 08:42

    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"

    0 讨论(0)
提交回复
热议问题