仅应用语言环境的ResourceManager中的本地化字符串(翻译)

时间:2018-03-16 12:35:34

标签: winforms localization

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

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

那么,这是否可行,而无需使用ResourceManager.GetString()逐个手动设置属性?

提前致谢!

1 个答案:

答案 0 :(得分:2)

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

以下是封装在自定义扩展方法中的上述想法的实现:

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