2011-02-25 21 views
7

Un livello superiore a this question, quale sarebbe il modo di archiviare tutte (e scorrere) le risorse disponibili e le culture associate, per consentire la selezione dell'utente di una cultura specifica?Passa attraverso risorse incorporate di lingue/culture diverse in C#

Ulteriori spiegazioni:

file di tre risorse Supponiamo:

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

ho potuto avere una stringa in ciascuno denominata LanguageName. Come potrei essere in grado di scorrere a livello di codice tra i diversi valori LanguageName per elencarli (in una casella di riepilogo?)?

EDIT: progetto WinForms, risorse incorporate.

risposta

8

Ecco una soluzione credo che lavori per WinForms:

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

Ed ecco come si dovrebbe utilizzare per un WindowsFormsApplication1:

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

Questo non funziona per alcuni dialetti cinesi che hanno codici di 6 caratteri. zh-CHS e zh-CHT. Fallirà anche per alcune delle nuove culture introdotte in .Net 4: http://msdn.microsoft.com/en-us/library/vstudio/dd997383(v=vs.100).aspx –

+1

@RobertGraves - buon punto . Ho aggiornato il codice. –

4

Supponendo di aver un ListBox di nome ListBox1 ei tuoi file di risorse di nome Resource.resx, Resource.es.resx, ecc .:

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

Questa è una risposta impressionante. E lo rovinerò chiedendomi se può funzionare come risorse incorporate, perché è un progetto WinForms. – MPelletier

1

Ecco un metodo per restituire un IEnumerable di stringa con i valori dai file di risorse, con una esempio di utilizzo. È sufficiente passare la parte di comando del nome della risorsa e la chiave dalle risorse che si desidera.

[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)); 
    } 
Problemi correlati