• c#: 界面多语言动态切换简单实现


    终于有空整理下多语言实现思路。查阅已有方案,有用不同resx文件的,有每个控件动态设置的,有用反射去整的,颇为繁琐。

    结合项目中实现方法,并做简化,实现通用的多语言切换方案,以做备忘。

    它支持语言自定义添加与扩充,灵活易用,更易于维护。它以xml格式存储语言信息,支持自定义语言、ToolTip等字串,支持即时切换。

    一、语言格式:

    每种语言对应一个xml格式文件,比如中文为Chinese.lng,英文为English.lng,置于程序运行目录之Languages文件夹下,其存放位置可自定义。

    本欲以反射获取已有程序集之字串,却未有成功,因为字串值初始化在InitializeComponent()中动态设置,反射不出来这些属性值,所以手动提取,以NotePad++做批量处理,亦是方便。

    文件分为自定义字串区(strings节点)、窗体语言文件区(forms节点),结构如下图示:

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <language Id="CHS" Name="Chinese" LocaleName="中文(简体)" LangID="0x0409" CodePage="1252">
      <strings>
        <INF_AppName>记事本</INF_AppName>
        <INF_NoTitle>无标题</INF_NoTitle>
        <INF_Information>提示</INF_Information>
        <INF_CannotFound>找不到 "{0}"</INF_CannotFound>
        <INF_ContentChanged>文件内容已被改变,要保存吗?</INF_ContentChanged>
      </strings>
      <forms>
        <MainForm Text="记事本">
          <miFile Text="文件(&amp;F)" />
          <miNew Text="新建(&amp;N)" />
          <miOpen Text="打开(&amp;0)..." />
          <miSave Text="保存(&amp;S)" />
          <miSaveAs Text="另存为(&amp;A)..." />
          <miPageSet Text="页面设置(&amp;U)..." />
          <miPrint Text="打印(&amp;P)..." />
          <miExit Text="退出(&amp;X)" />
          ...
          <miHelp Text="帮助(&amp;H)" />
          <miHelpTopic Text="帮助主题(&amp;H)" />
          <miLanguage Text="语言" />
          <miAbout Text="关于记事本(&amp;A)" />
        </MainForm>
        <GotoLineForm Text="跳转到指定行">
          <lblLine Text="行数(&amp;L):" />
    <txtLine ToolTip="请输入您想要跳转到的行号:" /> <btnOk Text="确定" /> <btnCancel Text="取消" /> </GotoLineForm> <SearchForm Text="查找"> <btnCancel Text="取消" /> <btnSearch Text="查找下一个(&amp;F)" /> <lblContent Text="查找内容(&amp;N):" /> <cbCaseSensitive Text="区分大小写" /> <gbDirection Text="方向" /> <rbDown Text="向下" /> <rbUp Text="向上" /> </SearchForm> </forms> </language>

    二、解析与加载类

    仍然对每个窗体做遍历,加载对应字串,提取语言文件语种信息。

    此文件是个完整的语言管理器类,且可根据需要自行扩充,列码如下:

    //多语言管理类
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Windows.Forms;
    using System.Xml;
    
    namespace Notepad
    {
        //单个语言项
        public class LanguageItem
        {
            private const string RootNodeName = "language";
            private const string StringsNodeName = "strings";
            private const string FormsNodeName = "forms";
    
            private XmlNode stringsNode;
            private XmlNode formsNode;
    
            private string id;
            private string name;
            private string localeName;
    
            public LanguageItem(string fileName)
            {
                var xmlDoc = new XmlDocument();
                xmlDoc.Load(fileName);
                var root = xmlDoc.DocumentElement;
                if (root != null)
                {
                    this.id = GetAttributeValue(root, "Id");
                    this.name = GetAttributeValue(root, "Name");
                    this.localeName = GetAttributeValue(root, "LocaleName");
    
                    this.stringsNode = root.SelectSingleNode(StringsNodeName);
                    this.formsNode = root.SelectSingleNode(FormsNodeName);
                }
            }
    
            public string Id
            {
                get { return this.id; }
            }
    
            public string Name
            {
                get { return this.name; }
            }
    
            public string LocaleName
            {
                get { return this.localeName; }
            }
    
            private void ApplyLanguage(Control control, XmlNode formNode, ToolTip toolTip = null)
            {
                if (string.IsNullOrEmpty(control.Name))
                    return;
    
                var ctrlNode = formNode.SelectSingleNode(control.Name);
                if (ctrlNode != null)
                {
                    control.Text = GetAttributeValue(ctrlNode, "Text");
                    string tips = GetAttributeValue(ctrlNode, "ToolTip");
                    if (!string.IsNullOrEmpty(tips) && toolTip != null)
                        toolTip.SetToolTip(control, tips);
                }
                //弹出菜单
                if (control.ContextMenuStrip != null)
                    ApplyMenuLanguage(control.ContextMenuStrip, formNode);
                foreach (Control ctrl in control.Controls)
                    ApplyLanguage(ctrl, formNode, toolTip);
                //菜单项,特别遍历
                if (control is ToolStrip)
                {
                    foreach (ToolStripItem toolItem in (control as ToolStrip).Items)
                        ApplyMenuLanguage(toolItem, formNode);
                }
            }
    
            private void ApplyMenuLanguage(ToolStrip menu, XmlNode formNode)
            {
                foreach (ToolStripItem toolItem in menu.Items)
                    ApplyMenuLanguage(toolItem, formNode);
            }
    
            private void ApplyMenuLanguage(ToolStripItem menuItem, XmlNode formNode)
            {
                if (string.IsNullOrEmpty(menuItem.Name))
                    return;
    
                var itemNode = formNode.SelectSingleNode(menuItem.Name);
                if (itemNode != null)
                {
                    menuItem.Text = GetAttributeValue(itemNode, "Text");
                    menuItem.ToolTipText = GetAttributeValue(itemNode, "ToolTip");
                }
                if (menuItem is ToolStripDropDownItem)
                {
                    foreach (ToolStripItem item in (menuItem as ToolStripDropDownItem).DropDownItems)
                        ApplyMenuLanguage(item, formNode);
                }
            }
    
            public bool LoadLanguageRes(ContainerControl cc)
            {
                if (cc == null || formsNode == null || !formsNode.HasChildNodes || formsNode.SelectSingleNode(cc.Name) == null)
                    return false;
    
                //创建ToolTip控件, 以支持ToolTip显示
                var toolTip = new ToolTip();
                var formNode = formsNode.SelectSingleNode(cc.Name);
                cc.Text = GetAttributeValue(formNode, "Text");
                foreach (Control ctrl in cc.Controls)
                    ApplyLanguage(ctrl, formNode, toolTip);
                return true;
            }
    
            public bool LoadLanguageRes(ContainerControl cc, ToolStrip menu)
            {
                if (cc == null || formsNode == null || !formsNode.HasChildNodes || formsNode.SelectSingleNode(cc.Name) == null)
                    return false;
    
                var formNode = formsNode.SelectSingleNode(cc.Name);
                ApplyLanguage(menu, formNode);
                return true;
            }
    
            private string GetAttributeValue(XmlNode xmlNode, string attrName)
            {
                if (xmlNode.Attributes != null && xmlNode.Attributes[attrName] != null)
                    return xmlNode.Attributes[attrName].Value;
                return string.Empty;
            }
    
            public string GetText(string textID, string defaultText = "")
            {
                if (stringsNode == null || !stringsNode.HasChildNodes)
                    return defaultText;
    
                foreach (XmlNode node in stringsNode.ChildNodes)
                    if (node.Name.Equals(textID))
                        return node.InnerText;
    
                return defaultText;
            }
        }
    
        public class LanguageList : List<LanguageItem>
        {
        }
    
        /// <summary>
        /// 多语言管理器
        /// </summary>
        public static class ML
        {
            private static LanguageItem activeLanguage;
            private static LanguageList languages;
    
            //最初调用
            public static int LoadLanguages(string searchPattern, string defaultLanguageId = "")
            {
                string path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Languages");
                return LoadLanguages(path, searchPattern, defaultLanguageId);
            }
    
            public static int LoadLanguages(string path, string searchPattern, string defaultLanguageId = "")
            {
                languages = new LanguageList();
                if (!Directory.Exists(path))
                    return 0;
    
                var files = Directory.GetFiles(path, searchPattern);
                foreach (string file in files)
                    languages.Add(new LanguageItem(file));
                if (!string.IsNullOrEmpty(defaultLanguageId))
                    LoadLanguageById(defaultLanguageId);
    
                return languages.Count;
            }
    
            public static string ActiveLanguageId
            {
                get { return (activeLanguage != null) ? activeLanguage.Id : string.Empty; }
            }
    
            public static string[] LanguageLocalNames
            {
                get
                {
                    if (languages == null || languages.Count == 0)
                        return new string[0];
                    var names = new string[languages.Count];
                    for (int i = 0; i <= languages.Count - 1; i++)
                        names[i] = languages[i].LocaleName;
                    return names;
                }
            }
    
            public static LanguageItem ActiveLanguage
            {
                get { return activeLanguage; }
            }
    
            public static LanguageList Languages
            {
                get { return languages; }
            }
    
            public static bool LoadLanguageRes(ContainerControl cc)
            {
                return (ActiveLanguage != null) ? ActiveLanguage.LoadLanguageRes(cc) : false;
            }
    
            //为动态弹出菜单设计
            public static bool LoadLanguageRes(ContainerControl cc, ToolStrip menu)
            {
                return (ActiveLanguage != null) ? ActiveLanguage.LoadLanguageRes(cc, menu) : false;
            }
    
            public static string Text(string textId, string defaultText = "")
            {
                return GetText(textId, defaultText);
            }
    
            public static string GetText(string textId, string defaultText = "")
            {
                return (ActiveLanguage != null) ? ActiveLanguage.GetText(textId, defaultText) : defaultText;
            }
    
            public static bool LoadLanguageById(string id)
            {
                if (languages == null)
                    return false;
    
                foreach (var language in languages)
                {
                    if (language.Id.Equals(id))
                    {
                        activeLanguage = language;
                        return true;
                    }
                }
    
                return false;
            }
    
            public static bool LoadLanguageByIndex(int index)
            {
                if (index < 0 || index > languages.Count - 1)
                    return false;
    
                activeLanguage = languages[index];
                return true;
            }
        }
    }

    OK,一行加载完成。

    窗体创建事件中,加入加载语言代码:

            //改写构造函数
            public MainForm(string[] args)
            {
                InitializeComponent();
    
                appName = ML.GetText("INF_AppName", APP_NAME);
                ML.LoadFormLanguage(this);
    //若有未与控件关联的弹出菜单,可加如下代码实现:
    //ML.LoadLanguageRes(this, pmMain);
    BuildLanguageMenuItems();
    this.args = args; }

    这样就完成了语言加载。

    这里有个多语言项生成菜单,其动态生成语言菜单项并加入事件触发,函数片段如下:

            private void BuildLanguageMenuItems()
            {
                if (ML.LanguageLocalNames.Length == 0)
                {
                    miLanguage.Visible = false;
                    return;
                }
    
                for (int i = 0; i <= ML.LanguageLocalNames.Length - 1; i++)
                {
                    string ln = ML.LanguageLocalNames[i];
                    var menuItem = new ToolStripMenuItem(ln);
                    //menuItem.CheckOnClick = true;
                    menuItem.Tag = i;
                    if (i == 0)
                        menuItem.Checked = true;
                    menuItem.Click += new EventHandler((sender, e) =>
                    {
                        foreach (ToolStripMenuItem item in miLanguage.DropDownItems)
                            item.Checked = (item == sender);
                        ML.LoadLanguageByIndex((int)(sender as ToolStripItem).Tag);
                        ML.LoadFormLanguage(this);
                    });
                    miLanguage.DropDownItems.Add(menuItem);
                }
            }

    功能完美实现。

    四、自定义语言用法

    语言串中,自定义语言定义在了strings节点,程序中如此调用:

    MessageBox.Show(this.searchForm, string.Format(ML.GetText("INF_CannotFound", "找不到 "{0}""), this.searchText), ML.GetText("INF_Information", "提示"), MessageBoxButtons.OK, MessageBoxIcon.Warning);
    switch (MessageBox.Show(ML.GetText("INF_ContentChanged", "文件内容已被改变,要保存吗?"), ML.GetText("INF_Information", "提示"), MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question))
    {
        case DialogResult.Yes:
            return Save();
        case DialogResult.No:
            return true;
        case DialogResult.Cancel:
            return false;
        default:
            return true;
    }

    颇为灵活。

    五、效果图:

    Demo源码下载:

    Notepad_ML.rar

  • 相关阅读:
    网站要满足用户的期望
    在网站内如何引导你的用户
    网站要一步一步的引导用户
    photoshop:制作sprite拼贴图片
    photoshop:css3插件
    注册表修改PSD关联photoshop
    photoshop:找不到增效工具入口点
    ajax:$.get()
    Photoshop支持ico输出
    JavaScript数字精度丢失问题总结
  • 原文地址:https://www.cnblogs.com/crwy/p/9897914.html
Copyright © 2020-2023  润新知