Manera programática de obtener todos los idiomas disponibles (en ensambles satelitales)

Estoy diseñando una aplicación multilingüe usando archivos .resx.

Tengo algunos archivos como GlobalStrings.resx, GlobalStrings.es.resx, GlobalStrings.en.resx, etc. Cuando quiero usar esto, solo necesito configurar Thread.CurrentThread.CurrentCulture.

El problema: tengo un combobox con todos los idiomas disponibles, pero lo estoy cargando manualmente:

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

Lo he intentado con

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

sin ningún éxito También intenté con todos los elementos en CultureTypes, pero solo estoy obteniendo una gran lista con muchos más idiomas que no estoy usando, o una lista vacía.

¿Hay alguna forma de obtener solo los idiomas compatibles?

Puede enumerar programáticamente las culturas disponibles en su aplicación

 // Pass the class name of your resources as a parameter eg 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."); } } 

Esta sería una solución basada en la siguiente statement:
Cada conjunto de satélites para un idioma específico recibe el mismo nombre, pero se encuentra en una subcarpeta que lleva el nombre de la cultura específica, por ejemplo, fr o fr-CA.

 public IEnumerable 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))); } 

basado en la respuesta de @ hans-holzbart pero corregido para no devolver InvariantCulture y envuelto en un método reutilizable:

 public static IEnumerable GetAvailableCultures() { List result = new List(); 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; } 

utilizando ese método, puede obtener una lista de cadenas para agregar a algunos ComboBox con lo siguiente:

 public static ObservableCollection GetAvailableLanguages() { var languages = new ObservableCollection(); var cultures = GetAvailableCultures(); foreach (CultureInfo culture in cultures) languages.Add(culture.NativeName + " (" + culture.EnglishName + " [" + culture.TwoLetterISOLanguageName + "])"); return languages; } 

No estoy seguro acerca de cómo obtener los idiomas, quizás pueda escanear su carpeta de instalación para archivos dll, pero establecer su idioma en un idioma no admitido no debería ser un problema.

.NET recurrirá a los recursos neutrales de cultura si no se pueden encontrar archivos específicos de cultura para que pueda seleccionar de manera segura los idiomas no admitidos.

Siempre que controle la aplicación usted mismo, puede almacenar los idiomas disponibles en algún lugar de la aplicación. Solo una cadena separada por comas con los nombres de cultura debería ser suficiente: “en, es”

Usando lo que dijo Rune Grimstad, termino con esto:

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

o de otra manera

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

Todavía no creo que esta sea una buena idea …

@ “Ankush Madankar” presenta un interesante punto de partida, pero tiene dos problemas: 1) Busca también carpetas de recursos para los recursos de ensamblajes refrendados 2) No encuentra el recurso para el lenguaje ensamblador base

No intentaré resolver el problema 2) pero para el problema 1) el código debería ser

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