6

Nel mio progetto corrente (applicazione Windows Form .NET) ho bisogno che i moduli di Windows .NET siano localizzati ma gli elementi di localizzazione (solo le traduzioni, non le immagini o le posizioni di controllo) dovrebbe provenire dal database per consentire agli utenti finali di modificare le proprietà localizzabili di controllo (solo la didascalia/testo) come desiderano. Per mantenere gli sviluppatori alleggeriti dai problemi di localizzazione, la soluzione migliore per me sarebbe semplicemente contrassegnare il modulo come localizzabile nel designer VS. Ciò inserirà tutti i valori di proprietà localizzabili nel file .resx di moduli.Localizzazione .NET WinForms - sostituzione ComponentResourceManager

Ora il mio problema è come fornire le traduzioni dal database. Nel momento in cui il modulo viene contrassegnato come Localizzabile, il designer VS Form posizionerà tutto ciò che può essere localizzato in un file .resx. Il progettista modificherà anche il metodo standard designer.cs InitializeComponent in modo da creare un'istanza di ComponentResourceManager e quindi utilizzare tale gestore risorse per caricare le proprietà localizzabili degli oggetti (controlli e componenti).

Ho visto soluzioni in cui le persone hanno creato il proprio metodo per applicare le proprietà localizzate a Form e ai suoi controlli. Tutte le soluzioni che ho visto di solito si riducono a iterazione ricorsiva attraverso la raccolta Controls di Form e dei suoi controlli e l'applicazione delle traduzioni. Sfortunatamente la localizzazione di .NET Form non è così semplice e questo non copre tutti gli scenari, specialmente se si dispone di alcuni controlli di terze parti. Ad esempio:

this.navBarControl.OptionsNavPane.ExpandedWidth = ((int)(resources.GetObject("resource.ExpandedWidth"))); 
// 
// radioGroup1 
// 
resources.ApplyResources(this.radioGroup1, "radioGroup1"); 
... 
this.radioGroup1.Properties.Items.AddRange(new DevExpress.XtraEditors.Controls.RadioGroupItem[] { 
new DevExpress.XtraEditors.Controls.RadioGroupItem(resources.GetString("radioGroup1.Properties.Items"), resources.GetString("radioGroup1.Properties.Items1")), 
new DevExpress.XtraEditors.Controls.RadioGroupItem(resources.GetString("radioGroup1.Properties.Items2"), resources.GetString("radioGroup1.Properties.Items3"))}); 

Tutte le soluzioni che ho visto non potevano eseguire traduzioni come richiesto dai componenti di cui sopra.

Poiché il VS ha già generato il codice che fornisce la traduzione dove necessario, la mia soluzione ideale sarebbe in qualche modo sostituire ComponentResourceManager con la mia classe derivata. Se solo potessi sostituire la seguente riga in InitializeComponent:

System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(Form1)); 

con

System.ComponentModel.ComponentResourceManager resources = new MyComponentResourceManager(typeof(Form1)); 

quindi ho potuto risolvere tutto il resto senza problemi.

Purtroppo non ho trovato come avrei potuto fare una cosa del genere, quindi eccomi qui a fare una domanda su come potrebbe essere fatto.

P.S. Vorrei anche accettare qualsiasi altra soluzione di localizzazione che soddisfa i requisiti: 1. Cambiare le traduzioni dovrebbero essere possibili senza ridistribuire l'applicazione 2. Lo sviluppatore non dovrebbe prendere cura di traduzione per la creazione di forme/utente controlla

Grazie.

EDIT: Larry ha fornito un ottimo riferimento a un libro che ha un codice che in parte risolve il mio problema. Con questo aiuto sono stato in grado di creare il mio componente che sostituisce il ComponentResourceManager predefinito nel metodo InitializeComponent. Qui è il codice per un componente chiamato localizzatore che sostituisce la ComponentResourceManager con MyResourceManager personalizzato in modo che qualcun altro può anche trarre beneficio da esso:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.ComponentModel; 
using System.ComponentModel.Design.Serialization; 
using System.CodeDom; 
using System.ComponentModel.Design; 

namespace LocalizationTest 
{ 
    [Designer(typeof(LocalizerDesigner))] 
    [DesignerSerializer(typeof(LocalizerSerializer), typeof(CodeDomSerializer))] 
    public class Localizer : Component 
    { 

     public static void GetResourceManager(Type type, out ComponentResourceManager resourceManager) 
     { 
      resourceManager = new MyResourceManager(type); 
     } 

    } 

    public class MyResourceManager : ComponentResourceManager 
    { 
     public MyResourceManager(Type type) : base(type) 
     { 
     } 

    } 


    public class LocalizerSerializer : CodeDomSerializer 
    { 
     public override object Deserialize(IDesignerSerializationManager manager, object codeDomObject) 
     { 
      CodeDomSerializer baseSerializer = (CodeDomSerializer) 
       manager.GetSerializer(typeof(Component), typeof(CodeDomSerializer)); 
      return baseSerializer.Deserialize(manager, codeDomObject); 
     } 

     public override object Serialize(IDesignerSerializationManager manager, object value) 
     { 
      CodeDomSerializer baseSerializer = 
       (CodeDomSerializer)manager.GetSerializer(typeof(Component), typeof(CodeDomSerializer)); 

      object codeObject = baseSerializer.Serialize(manager, value); 

      if (codeObject is CodeStatementCollection) 
      { 
       CodeStatementCollection statements = (CodeStatementCollection)codeObject; 
       CodeTypeDeclaration classTypeDeclaration = 
        (CodeTypeDeclaration)manager.GetService(typeof(CodeTypeDeclaration)); 
       CodeExpression typeofExpression = new CodeTypeOfExpression(classTypeDeclaration.Name); 
       CodeDirectionExpression outResourceExpression = new CodeDirectionExpression(
        FieldDirection.Out, new CodeVariableReferenceExpression("resources")); 
       CodeExpression rightCodeExpression = 
        new CodeMethodInvokeExpression(new CodeTypeReferenceExpression("LocalizationTest.Localizer"), "GetResourceManager", 
        new CodeExpression[] { typeofExpression, outResourceExpression }); 

       statements.Insert(0, new CodeExpressionStatement(rightCodeExpression)); 
      } 
      return codeObject; 
     } 
    } 

    public class LocalizerDesigner : ComponentDesigner 
    { 
     public override void Initialize(IComponent c) 
     { 
      base.Initialize(c); 
      var dh = (IDesignerHost)GetService(typeof(IDesignerHost)); 
      if (dh == null) 
       return; 

      var innerListProperty = dh.Container.Components.GetType().GetProperty("InnerList", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.FlattenHierarchy); 
      var innerList = innerListProperty.GetValue(dh.Container.Components, null) as System.Collections.ArrayList; 
      if (innerList == null) 
       return; 
      if (innerList.IndexOf(c) <= 1) 
       return; 
      innerList.Remove(c); 
      innerList.Insert(0, c); 

     } 
    } 


} 
+0

Ho trovato ulteriori spiegazioni su come funziona Localizer qui: http://flylib.com/books/en/3.147.1.147/1/ –

risposta

5

Sono l'autore di uno strumento di localizzazione per gli sviluppatori di Visual Studio (in interesse della piena divulgazione). Suggerisco caldamente di procurarmi una copia del libro di Guy Smith-Ferrier ".NET Internationalization, The Developer's Guide to Building Global Windows and Web Applications ". Credo che sia comunque il libro corretto (sicuramente autore corretto), ma è necessario verificarlo, poiché è passato molto tempo da quando l'ho guardato (e forse ha scritto qualcosa di più nuovo da allora). Guy è un MSP MVP e guru della localizzazione e ti mostra come fare esattamente quello che stai tentando, nel suo caso, creando un componente che puoi trascinare nell'area del vassoio di ogni Il tuo componente ti permetterà quindi di sostituire il "ComponentResourceManager" con il tuo (ci sono diverse classi coinvolte nella sua progettazione). Puoi quindi leggere le tue stringhe da qualsiasi sorgente incluso un DB. IIRC, il suo stesso esempio usa anche un DB. Probabilmente puoi trovare il codice online senza dover acquistare il suo libro, poiché penso che possa anche fornirlo sul suo sito. Puoi anche trovare passaggi gratuiti dal suo libro su siti di acquisto di libri affidabili, dal momento che le informazioni sono inestimabili anche se non usi il suo tecniche (molto difficili da trovare altrove). Nota che ho provato il suo codice una volta (molto tempo fa) e funziona come pubblicizzato.

+0

Grazie mille. Vado a dare un'occhiata e contrassegno la tua risposta come corretta. –

+0

Qual è lo strumento? :) –

+1

@Derek: http://www.hexadigm.com – Larry