2011-02-25 15 views
7

Un nivel desde this question, ¿cuál sería la forma de almacenar todos los recursos disponibles (y el bucle) y las culturas asociadas, para permitir la selección del usuario de una cultura específica?Bucle a través de recursos incrustados de diferentes idiomas/culturas en C#

una explicación más detallada:

Supongamos que los archivos de tres recursos:

  • GUILanguage.resx
  • GUILanguage.fr.resx
  • GUILanguage.it.resx

que podría tener una cadena en cada llamada LanguageName. ¿Cómo podría iterar programáticamente los diferentes valores de LanguageName para listarlos (por ejemplo, en un cuadro de lista)?

EDIT: Proyecto WinForms, recursos incrustados.

Respuesta

8

Aquí es una solución creo que funciona para Windows Forms:

// get cultures for a specific resource info 
public static IEnumerable<CultureInfo> EnumSatelliteLanguages(string baseName) 
{ 
    if (baseName == null) 
     throw new ArgumentNullException("baseName"); 

    ResourceManager manager = new ResourceManager(baseName, Assembly.GetExecutingAssembly()); 
    ResourceSet set = manager.GetResourceSet(CultureInfo.InvariantCulture, true, false); 
    if (set != null) 
     yield return CultureInfo.InvariantCulture; 

    foreach (CultureInfo culture in EnumSatelliteLanguages()) 
    { 
     set = manager.GetResourceSet(culture, true, false); 
     if (set != null) 
      yield return culture; 
    } 
} 

// determine what assemblies are available 
public static IEnumerable<CultureInfo> EnumSatelliteLanguages() 
{ 
    foreach (string directory in Directory.GetDirectories(AppDomain.CurrentDomain.BaseDirectory)) 
    { 
     string name = Path.GetFileNameWithoutExtension(directory); // resource dir don't have an extension... 

     // format is XX or XX-something, we discard directories that can't match. 
     // could/should be replaced by a regex but we still need to catch cultures errors... 
     if (name.Length < 2) 
      continue; 

     if (name.Length > 2 && name[2] != '-') 
      continue; 

     CultureInfo culture = null; 
     try 
     { 
      culture = CultureInfo.GetCultureInfo(name); 
     } 
     catch 
     { 
      // not a good directory... 
      continue; 
     } 

     string resName = Path.GetFileNameWithoutExtension(Assembly.GetExecutingAssembly().Location) + ".resources.dll"; 
     if (File.Exists(Path.Combine(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, name), resName))) 
      yield return culture; 
    } 
} 

Y aquí es cómo se utiliza durante un WindowsFormsApplication1:

List<CultureInfo> cultures = new List<CultureInfo>(EnumSatelliteLanguages("WindowsFormsApplication1.GUILanguage")); 
+0

Esto no funciona para algunos dialectos chinos que tienen un código de 6 caracteres. zh-CHS y zh-CHT. También fallará para algunas de las nuevas culturas introducidas en .Net 4: http://msdn.microsoft.com/en-us/library/vstudio/dd997383(v=vs.100).aspx –

+1

@RobertGraves - buen punto . He actualizado el código. –

4

Suponiendo que usted ha nombrado a un cuadro de lista ListBox1 y sus archivos de recursos llamado Resource.resx, Resource.es.resx, etc .:

using System; 
using System.Collections.Generic; 
using System.Globalization; 
using System.IO; 
using System.Linq; 
using System.Web.UI.WebControls; 
using Resources; 

public partial class _Default : System.Web.UI.Page 
{ 
    protected void Page_Load(object sender, EventArgs e) 
    { 
     if (ListBox1.Items.Count < 1) 
     { 
      var installedCultures = GetInstalledCultures(); 
      IEnumerable<ListItem> listItems = installedCultures.Select(cultInfo => 
       new ListItem(Resource.ResourceManager.GetString("LanguageName", cultInfo), cultInfo.Name)); 
      ListBox1.Items.AddRange(listItems.ToArray()); 
     } 
    } 

    public IEnumerable<CultureInfo> GetInstalledCultures() 
    { 
     foreach (string file in Directory.GetFiles(Server.MapPath("~/App_GlobalResources"), "*.resx")) 
     { 
      if (!file.EndsWith(".resx")) 
       continue; 
      var endCropPos = file.Length - ".resx".Length; 
      var beginCropPos = file.LastIndexOf(".", endCropPos - 1) + 1; 
      string culture = "en"; 
      if (beginCropPos > 0 && file.LastIndexOf("\\") < beginCropPos) 
       culture = file.Substring(beginCropPos, endCropPos - beginCropPos); 
      yield return new CultureInfo(culture); 
     } 
    } 

    // override to set the Culture with the ListBox1 (use AutoPostBack="True") 
    protected override void InitializeCulture() 
    { 
     base.InitializeCulture(); 

     var cult = Request["ctl00$MainContent$ListBox1"]; 
     if (cult != null) 
     { 
      Culture = cult; 
      UICulture = cult; 
     } 
    } 
} 
+3

Esta es una respuesta impresionante. Y voy a arruinarlo al preguntar si puede funcionar como recursos integrados, porque es un proyecto de WinForms. – MPelletier

1

Aquí es un método para devolver un IEnumerable de cadena con los valores de los archivos de recursos, con una uso de ejemplo. Simplemente ingrese la parte de comando del nombre del recurso y la clave de los recursos que desea.

[Test] 
    public void getLanguageNames() 
    { 
     var names = GetResourceLanguageNames(Assembly.GetExecutingAssembly(), "GUILanguage", "LanguageName"); 
     Console.WriteLine(string.Join("-",names)); 
    } 

    public IEnumerable<string> GetResourceLanguageNames(Assembly assembly, string resourceName, string key) 
    { 
     var regex = new Regex(string.Format(@"(\w)?{0}(\.\w+)?", resourceName)); 

     var matchingResources = assembly.GetManifestResourceNames() 
            .Where(n => regex.IsMatch(n)).Select(rn=>rn.Remove(rn.LastIndexOf("."))); 

     return matchingResources.Select(rn => new ResourceManager(rn, assembly).GetString(key)); 
    } 
Cuestiones relacionadas