【问题标题】:Apply only localization strings (translations) from a locale's ResourceManager仅应用区域设置的 ResourceManager 中的本地化字符串(翻译)
【发布时间】:2018-03-16 12:35:33
【问题描述】:

我问这是this other question 的一种可能的解决方法。问题围绕在窗体中的所有控件上对ResourceManager.ApplyResources() 的递归调用,这会导致所有锚定/布局重置为设计器中定义的大小(即ResourceManager 中的默认值)。虽然另一个问题试图通过在应用资源后重新应用布局来解决问题,但另一种方法是引导ApplyResources 的行为,以便仅将本地化字符串应用于控件而不是大小和位置属性,这是导致不良行为的原因。

设计人员通过将表单的Localizable 属性设置为true,将表单的语言切换为区域设置,并将控件的文本设置为该特定区域设置中的翻译,来自动创建不同区域设置的资源文件。

那么,这是否可以不用ResourceManager.GetString()手动一一设置属性?

提前致谢!

【问题讨论】:

    标签: winforms localization


    【解决方案1】:

    我能想到的一种方法是过滤资源管理器的内容。

    下面是把上述思想封装在一个自定义扩展方法中的实现:

    using System.Collections;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Resources;
    
    namespace System.Windows.Forms
    {
        public static partial class Extensions
        {
            public static void ApplyResources(this Control target, Func<KeyValuePair<string, object>, bool> filter, CultureInfo culture = null)
            {
                ApplyResources(new FilteringComponentResourceManager(target.GetType(), filter), target, "$this", culture);
            }
    
            static void ApplyResources(FilteringComponentResourceManager resourceManager, Control target, string name, CultureInfo culture = null)
            {
                // Have the resource manager apply the resources to the given target
                resourceManager.ApplyResources(target, name, culture);
                // Iterate through the collection of children and recursively apply resources
                foreach (Control child in target.Controls)
                {
                    if (child is UserControl)
                        ApplyResources(child, resourceManager.Filter, culture);
                    else
                        ApplyResources(resourceManager, child, child.Name, culture);
                }
            }
    
            class FilteringComponentResourceManager : ComponentResourceManager
            {
                ComponentResourceManager source;
                Func<KeyValuePair<string, object>, bool> filter;
                public FilteringComponentResourceManager(Type type, Func<KeyValuePair<string, object>, bool> filter)
                {
                    this.source = new ComponentResourceManager(type);
                    this.filter = filter;
                }
                public Func<KeyValuePair<string, object>, bool> Filter { get { return filter; } }
                protected override ResourceSet InternalGetResourceSet(CultureInfo culture, bool createIfNotExists, bool tryParents)
                {
                    var sourceSet = source.GetResourceSet(culture, createIfNotExists, tryParents);
                    return sourceSet != null ? new FilteredResourceSet(sourceSet, filter) : null;
                }
                class FilteredResourceSet : ResourceSet
                {
                    public FilteredResourceSet(ResourceSet source, Func<KeyValuePair<string, object>, bool> filter)
                    {
                        foreach (DictionaryEntry entry in source)
                        {
                            if (filter(new KeyValuePair<string, object>((string)entry.Key, entry.Value)))
                                Table.Add(entry.Key, entry.Value);
                        }
                    }
                }
            }
        }
    }
    

    过滤是通过两个自定义类实现的——一个派生自ComponentResourceManager,一个派生自ResourceSet。第一个类覆盖InternalGetResourceSet,以便创建并返回第二种类型的实例,该实例执行实际的过滤。

    示例用法:

    仅应用名为 Text 的属性:

    this.ApplyResources(entry => entry.Key.EndsWith(".Text"));
    

    仅应用 string 类型的属性:

    this.ApplyResources(entry => entry.Value is string);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-05-08
      • 1970-01-01
      相关资源
      最近更新 更多