6

Trong dự án hiện tại của tôi (.NET Windows Forms application) Tôi có yêu cầu các biểu mẫu .NET phải được bản địa hóa nhưng các phần tử bản địa hóa (chỉ là bản dịch chứ không phải hình ảnh hoặc vị trí kiểm soát) nên đến từ cơ sở dữ liệu để cho phép người dùng cuối sửa đổi các thuộc tính kiểm soát được bản địa hóa (chỉ phụ đề/văn bản) như họ muốn. Để giữ cho các nhà phát triển unburdened với các vấn đề nội địa hóa giải pháp tốt nhất cho tôi sẽ chỉ đơn giản là đánh dấu các hình thức như bản địa hóa trong VS thiết kế. Điều này sẽ đặt tất cả các giá trị thuộc tính có thể bản địa hóa trong tệp .resx của biểu mẫu.Nội địa hóa WinForms .NET - thay thế ComponentResourceManager

Bây giờ, sự cố của tôi là cách cung cấp bản dịch từ cơ sở dữ liệu. Thời điểm biểu mẫu được đánh dấu là Bản địa hóa thiết kế biểu mẫu VS sẽ đặt mọi thứ có thể được bản địa hóa là tệp .resx. Nhà thiết kế cũng sẽ sửa đổi phương thức factory.cs InitializeComponent chuẩn để nó khởi tạo ComponentResourceManager và sau đó sử dụng trình quản lý tài nguyên đó để nạp các thuộc tính có thể bản địa hóa của các đối tượng (các điều khiển và các thành phần).

Tôi đã thấy các giải pháp nơi mọi người đã xây dựng phương pháp riêng của họ trong việc áp dụng các thuộc tính được bản địa hóa cho Biểu mẫu và các điều khiển của nó. Tất cả các giải pháp mà tôi đã nhìn thấy thường đun sôi xuống để đệ quy lặp đi lặp lại thông qua các bộ sưu tập điều khiển của mẫu và điều khiển của nó và áp dụng các bản dịch. Thật không may, các bản địa hóa .NET Forms không đơn giản như vậy và điều này không bao gồm tất cả các kịch bản đặc biệt nếu bạn có một số điều khiển bên thứ 3. Ví dụ:

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

Tất cả các giải pháp tôi thấy không thể dịch được như yêu cầu của các thành phần trên.

Vì VS đã tạo mã cung cấp bản dịch khi cần giải pháp lý tưởng của tôi sẽ bằng cách nào đó thay thế ComponentResourceManager bằng lớp dẫn xuất của chính tôi. Nếu tôi chỉ có thể thay thế các dòng sau trong InitializeComponent:

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

với

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

sau đó tôi có thể giải quyết tất cả mọi thứ khác mà không có bất kỳ vấn đề.

Thật không may tôi không tìm thấy cách tôi có thể làm điều gì đó tương tự như vậy ở đây tôi đang trên SO hỏi một câu hỏi về cách nó có thể được thực hiện.

P.S. tôi cũng sẽ chấp nhận bất kỳ giải pháp định vị khác mà phù hợp với các yêu cầu: 1. Thay đổi bản dịch nên có thể mà không redeploying ứng dụng 2. Các nhà phát triển không nên chăm sóc về dịch khi tạo các hình thức/user điều khiển

Cảm ơn bạn.

EDIT: Larry cung cấp tham chiếu tuyệt vời cho sách có mã giải quyết một phần vấn đề của tôi. Với sự trợ giúp đó, tôi đã có thể tạo ra thành phần của riêng tôi thay thế ComponentResourceManager mặc định trong phương thức InitializeComponent. Đây là mã cho một thành phần được gọi là Localizer thay thế các ComponentResourceManager với MyResourceManager tùy chỉnh để người khác cũng có thể được hưởng lợi từ nó:

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

Tôi đã tìm hiểu thêm về cách Localizer hoạt động tại đây: http://flylib.com/books/en/3.147.1.147/1/ –

Trả lời

5

Tôi là tác giả của một công cụ bản địa hóa cho các nhà phát triển Visual Studio (trong lợi ích của việc tiết lộ đầy đủ). Tôi đề nghị nên giữ một bản sao của cuốn sách của Guy Smith-Ferrier, ".Tôi tin rằng đó là cuốn sách chính xác anyway (đúng tác giả chắc chắn), nhưng bạn sẽ cần phải kiểm tra, vì nó đã được một thời gian dài kể từ khi tôi nhìn vào nó (và Logged Guy là một MSFT MVP và guru bản địa hóa Ông cho bạn thấy làm thế nào để làm chính xác những gì bạn đang cố gắng, trong trường hợp của mình, bằng cách tạo ra một thành phần mà bạn có thể kéo vào vùng khay của mỗi Các thành phần sau đó sẽ cho phép bạn thay thế "ComponentResourceManager" bằng của riêng bạn (có một số lớp liên quan đến thiết kế của mình) .Bạn có thể đọc chuỗi của bạn từ bất kỳ nguồn nào bao gồm DB. IIRC, ví dụ của riêng mình thậm chí còn sử dụng Bạn có thể tìm thấy mã trực tuyến mà không cần phải mua sách của mình, vì tôi nghĩ rằng anh ấy thậm chí có thể cung cấp nó trên trang web của riêng mình.Bạn cũng có thể tìm thấy các đoạn miễn phí từ cuốn sách của mình trên các trang web mua sách có uy tín, vì thông tin là vô giá ngay cả khi bạn không sử dụng kỹ thuật (rất khó tìm ở nơi khác). Lưu ý rằng tôi đã kiểm tra mã của anh ấy một lần một thời gian (một thời gian dài trước đây), và nó hoạt động như quảng cáo.

+0

Cảm ơn bạn rất nhiều. Tôi sẽ kiểm tra nó ra và đánh dấu câu trả lời của bạn là chính xác. –

+0

Công cụ này là gì? :) –

+1

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