在运行时以WinForms中的可本地化形式更改CurrentUICulture [英] Changing CurrentUICulture at runtime in a Localizable Form in WinForms

查看:89
本文介绍了在运行时以WinForms中的可本地化形式更改CurrentUICulture的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找如何更改将 Localizable 属性设置为true的表单的语言。









但是当我选择西班牙语时,文本没有任何变化。



所以也许,我对儿童。也许通过调用方法 CreateCulture ,我不知道。



预先感谢!



编辑:



我已经通过文化信息测试了获取表单资源管理器的能力并每次都返回默认值:

  ResourceSet resourceSet = new ResourceManager(typeof(frmCredentials))。GetResourceSet(new CultureInfo(lang) ),true,true); 
foreach(resourceSet中的DictionaryEntry条目)
{
string resourceKey = entry.Key.ToString();
对象资源= entry.Value; //resourceSet.GetString(resourceKey);
if(resource.GetType()。Equals(typeof(string)))
Console.WriteLine( Key:{0} \nValue:{1} \n\n,resourceKey ,(字符串)资源);
}

其中 new CultureInfo(lang),我也测试过: new CultureInfo( es)& Thread.CurrentThread.CurrentCulture (CurrentUICulture)没有运气。就像它永远不存在或被替换一样,但是在我的设计和文件浏览器中我可以看到文件。



EDIT2:



也许是因为我正在使用ILMerge将所有dll合并到一个唯一的dll中。我正在对此进行审查:单组装多-语言Windows窗体部署(ILMerge和附属程序集/本地化)-可能吗?



回复EDIT2:



是的,删除ILMerge,此问题已解决,我提供的第一个解决方案可以解决此问题。但是由于某种原因,西班牙语被视为默认语言,当我尝试从中获取资源集时,它什么也没回。



我已将Localizable属性设置为false,并且没有使用值创建默认的resx文件。我不知道这是否是一个好习惯。



我会尝试一些新的东西...

解决方案

经过一番尝试,我意识到有些事情失败了。



我还必须说,在这方面给予的所有帮助这个问题非常值得赞赏,并且 LocalizedForm片段非常有用。



第一个问题是我已经意识到,使用此解决方案的子层次结构中处于1级以上的控件不起作用。



<遍历所有控件是一项昂贵的任务。也许我的情况最糟糕,但是迭代次数更少(因为我只喜欢使用文本控件)

  ///< summary> 
///这种形式的当前区域性
///< / summary>
[Browsable(false)]
[描述(此形式的当前文化)]
[EditorBrowsable(EditorBrowsableState.Never)]
public CultureInfo文化
{
get {return this.culture; }
set
{
if(this.culture!= value)
{
ResourceSet resourceSet = new ComponentResourceManager(GetType())。GetResourceSet(value,true,真正);
IEnumerable< DictionaryEntry> entrys = resourceSet
.Cast< DictionaryEntry>()
.Where(x => x.Key.ToString()。Contains(。Text))
.Select(x = > {x.Key = x.Key.ToString()。Replace(>,).Split('。')[0]; return x;});

foreach(条目中的DictionaryEntry条目)
{
if(!entry.Value.GetType()。Equals(typeof(string)))return;

字符串Key = entry.Key.ToString(),
Value =(string)entry.Value;

试试
{
Control c = Controls.Find(Key,true).SingleOrDefault();
c.Text =值;
}
catch
{
Console.WriteLine(控件{0}在形式{1}中为空!,Key,GetType()。Name);
}
}

this.culture =价值;
this.OnCultureChanged();
}
}
}

我的工作是,首先,我搜索 ResourceManager ,请注意!因为这是第二个问题,是如果使用 CultureInfo.CreateSpecificCulture 而不是 CultureInfo.GetCultureInfo ,将创建区域性并返回默认值( Form1.resx 值,而不是 Form1.es.resx 值(例如)。



一旦我们从 resx文件中加载了所有值,我们就会遍历所有这些值,然后删除double >>(在某些情况下会出现),我们得到只声明了 Text属性的那些 Controls 的名称。



下一步是找到 Control 并替换其Text ...



好吧,我对派生类,这就是为什么我创建了尝试捕获系统的原因,因为 Controls.Find search in all Derived Classes 更具体一点,但我不知道如何...(这就是为什么我创建了这个问题



有了这个,我们不会保存任何对象,因为我们不会清除并重新创建它们。



这里的主要问题不是我这样做的方式,因为它是正确的。
问题是合并的程序集会产生奇怪的结果,例如,调用以下命令:



ResourceSet resourceSet = new ComponentResourceManager(GetType())。GetResourceSet(value,true,true);



将是默认值...类似于文化不存在之类的东西,这是因为合并的程序集无法找到resx文件



所以,我将尝试@ScottChamberlain向我建议的 AppDomain.CurrentDomain.AssemblyResolve 。或者 ILRepack



感谢您提供任何有关优化或想法的建议,以帮助其解决问题!


I have been searching about how to change the language of a Form that has the Localizable attribute set to true.

https://msdn.microsoft.com/en-us/library/system.threading.thread.currentuiculture(v=vs.110).aspx

This is to set the language of the form, but this needs to be set before we instantiate the form. This cannot be called after this event.

Searching for information, I have seen the following question: https://stackoverflow.com/a/11738932/3286975 but, as a comment said, I have controls inside of a TabControl and a MenuStrip, so they aren't affected.

I have tried to modify this, by getting all the controls of the Form without luck.

In this menu I call the following callback:

    private void englishToolStripMenuItem_Click_1(object sender, EventArgs e)
    {
        string lang = (string) ((ToolStripMenuItem) sender).Tag;
        base.Culture = CultureInfo.CreateSpecificCulture(lang);
    }

    private void spanishToolStripMenuItem_Click(object sender, EventArgs e)
    {
        string lang = (string) ((ToolStripMenuItem) sender).Tag;
        base.Culture = CultureInfo.CreateSpecificCulture(lang);
    }

I change the Culture by using the Tag.

When I click it nothing happens. Also, I have modified a little bit the ApplyResources method from the mentioned answer.

private void ApplyResources(Control parent, CultureInfo culture)
{
        this.resManager.ApplyResources(parent, parent.Name, culture);

        foreach (Control ctl in parent.IterateAllChildren())
        {
            //this.ApplyResources(ctl, culture);
            this.resManager.ApplyResources(ctl, ctl.Name, culture);
        }
}

Where IterateAllChildren is the following: https://stackoverflow.com/a/16725020/3286975

Also, I tried with (System.LINQ): Controls.OfType<Label>() (because I have one Label to test this) without luck...

But when I select the Spanish language, no text is changed.

So maybe, I'm failling with the childrens. Or maybe by calling the method CreateCulture, I don't know.

Thanks in advance!

EDIT:

I have tested to get the Resource Manager of my form by the Culture Info and it returns the default one everytime:

 ResourceSet resourceSet = new ResourceManager(typeof(frmCredentials)).GetResourceSet(new CultureInfo(lang), true, true);
            foreach (DictionaryEntry entry in resourceSet)
            {
                string resourceKey = entry.Key.ToString();
                object resource = entry.Value; //resourceSet.GetString(resourceKey);
                if (resource.GetType().Equals(typeof(string)))
                    Console.WriteLine("Key: {0}\nValue: {1}\n\n", resourceKey, (string) resource);
            }

Where new CultureInfo(lang), I haved tested also: new CultureInfo("es") & Thread.CurrentThread.CurrentCulture (CurrentUICulture) without luck. Is like it never exists or is replaced, but in my design and file explorer I can see the files.

EDIT2:

Maybe is because I'm using ILMerge to merge all dlls in a unique one. I'm reviewing this: Single-assembly multi-language Windows Forms deployment (ILMerge and satellite assemblies / localization) - possible?

Reply to EDIT2:

Yep, deleting ILMerge the problem is solved, and the first solution I gave resolves this. But for some reason, Spanish language is taken as the default language, and when I tried to get the resourceset from it, it didn't return me nothing.

Aso, I have set the Localizable attribute to false, and it didn't created a default resx file with values. I don't know if this is a good practice.

I will try something new...

解决方案

After some tries, I have realized that several things are failing.

I have to say also that all the given help in this question is greatly appreciated, and also that the LocalizedForm snippet is very useful.

The first issue is that I have realized is that the controls that are under a level of more than 1 in the child hierarchy with this solution doesn't work.

And iterating over all the controls is a expensive task. Maybe mine is worst but has less iterations (because I only seach for Controls with Text)

    /// <summary>
    /// Current culture of this form
    /// </summary>
    [Browsable(false)]
    [Description("Current culture of this form")]
    [EditorBrowsable(EditorBrowsableState.Never)]
    public CultureInfo Culture
    {
        get { return this.culture; }
        set
        {
            if (this.culture != value)
            {
                ResourceSet resourceSet = new ComponentResourceManager(GetType()).GetResourceSet(value, true, true);
                IEnumerable<DictionaryEntry> entries = resourceSet
                    .Cast<DictionaryEntry>()
                    .Where(x => x.Key.ToString().Contains(".Text"))
                    .Select(x => { x.Key = x.Key.ToString().Replace(">", "").Split('.')[0]; return x; });

                foreach (DictionaryEntry entry in entries)
                {
                    if (!entry.Value.GetType().Equals(typeof(string))) return;

                    string Key = entry.Key.ToString(),
                           Value = (string) entry.Value;

                    try
                    {
                        Control c = Controls.Find(Key, true).SingleOrDefault();
                        c.Text = Value;
                    }
                    catch
                    {
                        Console.WriteLine("Control {0} is null in form {1}!", Key, GetType().Name);
                    }
                }

                this.culture = value;
                this.OnCultureChanged();
            }
        }
    }

What I do is the following, first, I search for the ResourceManager, take care! Because here is the second issue and is that if you use CultureInfo.CreateSpecificCulture instead CultureInfo.GetCultureInfo in some cases a new culture will be created and default values will be returned (Form1.resx values instead of Form1.es.resx values (for example)).

Once we have loaded all the value from the resx file, we iterate over all of them, and we delete the double >> (it appears in some cases) and we get the name of those Controls that only have declared the Text attribute.

The next step is find the Control and replace its Text...

Well, I have a little mess with the derived classes, that's why I created a try-catch system, because, Controls.Find search in all the Derived Classes I would prefer to be a little bit more specific but I don't know how... (That's why I created this question)

With this we haven't to save any object because we won't clear and recreate them.

The main problem here wasn't the way I was doing this, because it was correct. The problem is that Assemblies merged do weird things when you call for example this:

ResourceSet resourceSet = new ComponentResourceManager(GetType()).GetResourceSet(value, true, true);

The value will be the default... Something like that this Culture doesn't exist, and is because, the merged Assembly can't find the resx file.

So, I will try AppDomain.CurrentDomain.AssemblyResolve that @ScottChamberlain has suggested to me. Or ILRepack maybe.

Any help for optimization or ideas (in comments) of why this doesn't work will be appreciated!

这篇关于在运行时以WinForms中的可本地化形式更改CurrentUICulture的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆