6

W moim bieżącym projekcie (aplikacja .NET Windows Forms) mam wymóg, aby formularze okien .NET były zlokalizowane, ale elementy lokalizacyjne (tylko tłumaczenia, a nie obrazy lub pozycje kontrolne) powinien pochodzić z bazy danych, aby umożliwić użytkownikom końcowym modyfikowanie właściwości kontrolowanych lokalizacji (tylko podpis/tekst) zgodnie z własnym życzeniem. Aby deweloperzy nie obciążali problemów związanych z lokalizacją, najlepszym rozwiązaniem byłoby po prostu oznaczenie formularza jako Lokalizowalne w projektancie VS. Spowoduje to umieszczenie wszystkich wartości właściwości lokalizowalnych w pliku .resx formularzy..NET Lokalizacja WinForms - zastępowanie ComponentResourceManager

Teraz mój problem polega na tłumaczeniu z bazy danych. W momencie, gdy formularz zostanie oznaczony jako Localizable, projektant formularzy VS umieści wszystko, co może być zlokalizowane, w pliku .resx w postaci. Projektant zmodyfikuje również standardową metodę designer.cs InitializeComponent, aby utworzyć instancję ComponentResourceManager, a następnie użyć tego menedżera zasobów, aby załadować lokalizowalne właściwości obiektów (formantów i komponentów).

Widziałem rozwiązania, w których ludzie stworzyli własną metodę zastosowania zlokalizowanych właściwości do formularza i jego kontroli. Wszystkie rozwiązania, które widziałem zwykle sprowadzają się do rekursywnej iteracji poprzez kolekcję Formantów i jej kontroli oraz stosowania tłumaczeń. Niestety lokalizacja .NET Forms nie jest tak prosta i nie obejmuje wszystkich scenariuszy, szczególnie jeśli masz jakieś kontrole innych firm. Na przykład:

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"))}); 

Wszystkie rozwiązania, które widziałem, nie mogą wykonywać tłumaczeń wymaganych przez powyższe składniki.

Ponieważ VS już wygenerował kod, który zapewnia tłumaczenie w razie potrzeby, moim idealnym rozwiązaniem byłoby jakoś zastąpić ComponentResourceManager moją własną klasą pochodną. Gdybym tylko mógł zastąpić następującą linię w InitializeComponent:

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

z

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

wtedy mogę rozwiązać wszystko inne bez żadnych problemów.

Niestety nie znalazłem sposobu, w jaki mogłem zrobić coś takiego, więc tutaj jestem na ZADZEJ, zadając pytanie, jak to zrobić.

P.S. Chciałbym również przyjąć innego rozwiązania lokalizacyjne, które odpowiada wymaganiom: 1. Zmiana tłumaczenia powinno być możliwe bez przesunięcia wniosku 2. deweloper nie powinien dbać o tłumaczeniu podczas tworzenia formularzy/użytkownik kontroluje

Dziękuję.

EDYCJA: Larry podał świetne odniesienie do książki, która ma kod, który częściowo rozwiązuje mój problem. Dzięki tej pomocy udało mi się stworzyć własny komponent, który zastępuje domyślny ComponentResourceManager w metodzie InitializeComponent. Oto kod dla składnika o nazwie Lokalizator który zastępuje ComponentResourceManager z niestandardowym MyResourceManager tak, że ktoś inny może z niego korzystać:

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

Znalazłem więcej wyjaśnień, jak Localizer działa tutaj: http://flylib.com/books/en/3.147.1.147/1/ –

Odpowiedz

5

Jestem autorem narzędzie lokalizacyjne dla programistów Visual Studio (w zainteresowanie pełnym ujawnieniem). Sugeruję, aby zdobyć kopię książki Guya Smitha-Ferriera ".NET Internationalization, Przewodnik programisty do budowania globalnego systemu Windows i aplikacji internetowych "Uważam, że i tak jest to poprawna książka (na pewno poprawny autor), ale musicie to sprawdzić, ponieważ minęło sporo czasu, odkąd na nią patrzyłem (i może nawet napisał coś nowego od tego czasu) Guy jest MSFT MVP i guru lokalizacyjnym pokazuje, jak zrobić dokładnie to, co próbujesz, w jego przypadku, tworząc komponent, który możesz przeciągnąć na obszar tacy każdego Komponent pozwoli ci wtedy na zastąpienie "ComponentResourceManager" swoim własnym (istnieje kilka klas związanych z jego projektem), możesz następnie odczytać ciągi z dowolnego źródła, w tym z bazy danych, IIRC, jego własny przykład nawet używa DB Prawdopodobnie możesz znaleźć kod online bez kupowania jego książki, ponieważ myślę, że może ją nawet dostarczyć na swojej stronie Możesz również znaleźć bezpłatne fragmenty swojej książki na renomowanych stronach z książkami, ponieważ informacje są nieocenione nawet jeśli nie używasz jego techniki (bardzo trudne do znalezienia gdzie indziej). Zauważ, że testowałem jego kod raz na jakiś czas (dawno temu) i działa on tak, jak jest reklamowany.

+0

Dziękuję bardzo. Zamierzam to sprawdzić i oznaczyć twoją odpowiedź jako poprawną. –

+0

Co to za narzędzie? :) –

+1

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

Powiązane problemy