目录
要使一个窗体(Form)支持本地化,需要付出一定量的努力。用于本地化控件的努力很小,而且只需做一次。代码中内嵌的文本字符串需要以特定方式处理,但只有需要本地化的字符串才需要这样处理。仅使用异常对象或 exception.message 属性来显示错误的 Try…Catch 结构,会根据操作系统的语言设置自动显示。任何不打算让用户去解读的应用程序错误都应保留英文,这样当用户把错误报告给我们时,开发团队就不必做额外的工作去弄清该错误究竟是什么。
附加属性
以下属性需要添加到任何要支持本地化的窗体中:
Property ToolTipText(c As Control) As String Get ToolTipText = Me.ToolTip1.GetToolTip(c) End Get Set(Value As String) ToolTip1.SetToolTip(c, Value) End Set End Property
该属性为任何不直接支持工具提示(ToolTip)属性的控件返回并设置 ToolTipText(实际上几乎除菜单项(MenuItems)之外的所有控件都是如此)。请注意,窗体上启用这些功能的 ToolTip 组件必须命名为 ToolTip1,否则必须把上面的代码改为正确的名称。如果窗体上没有编写任何工具提示,则完全省略该属性例程。
Property Msg(keyy As String) As String Get Try 'Debug.Print(keyy) If Microsoft.VisualBasic.Strings.Left(keyy, 1) = ChrW(157) Then keyy = Strings.Right(keyy, Len(keyy) - 1) End If Msg = dict(keyy).ToString Catch Msg = "Invalid key - " & keyy & " - is missing from translation dictionary. Please contact the development team." End Try End Get Set(Value As String) dict(keyy) = Value End Set End Property
ReadOnly Property GetMsgDict() As Dictionary(Of String, String) Get GetMsgDict = dict End Get End Property
这些属性支持对内联消息进行字符串查找和替换,例如任何要送往 MsgBox 或 StatusStrip 的内容。变量 dict 是一个字典,其结构和用途将在下文说明。
附加事件
Private Sub Station_LanguageChanged() Handles stn.LanguageChanged Call SetLocalStrings(Me, True) End Sub
如果在配置器(Configurer)窗体中更改了语言,这将使该窗体以新语言重新绘制。
注意:调用 SetLocalStrings 时的可选参数(上例中为 True)用于在调用时强制把字符串转换为英文。通常,如果所选语言是英文(默认值),该例程不再做其他事,而是立即返回。如果语言从非英文改回英文,则该例程必须在数据库中查找英文字符串并使用它们,事件处理程序才能做任何有意义的事。否则,需要关闭并重新打开应用程序,才能以英文重新显示。
必需调用
将以下调用添加到窗体加载事件中:
Call SetLocalStrings(Me)
支持的控件
本地化代码目前支持以下控件。
- Label – Text 属性与 ToolTip 属性(若存在)
- CheckBox – Text 属性与 ToolTip 属性(若存在)
- RadioButton – Text 属性与 ToolTip 属性(若存在)
- Button – Text 属性与 ToolTip 属性(若存在)
- ListView – ColumnHeaders 的 Text 属性
- GroupBox – Text 属性及所有子控件
- GroupBoxEx – Text 属性及所有子控件
- TableLayoutPanel – Text 属性及所有子控件
- Panel – Text 属性及所有子控件
- TabControl – 所有子控件,包括选项卡页(Tab Pages)
- StatusStrip – 所有 ToolStripStatusLabels 子控件
- MenuStrip(及其子对象,即菜单项(MenuItems))– Text 与 ToolTip 属性
- N1MMNumericUpDown – 忽略(不显示“Object not handled yet”消息)
- AxN1MMWave – 忽略(不显示“Object not handled yet”消息)
- ComboBox – ToolTipText 属性(若存在)
- TextBox – ToolTipText 属性(若存在)
- RichTextBox – ToolTipText 属性(若存在)
- PictureBox – ToolTipText 属性(若存在)
- NumericUpDown – ToolTipText 属性(若存在)
- HScrollBar – ToolTipText 属性(若存在)
- DateTimePicker – 忽略,没有要设置的属性
- ListBox – 忽略,没有要设置的属性
- TrackBar – 忽略,没有要设置的属性
- AxXMMVView – 忽略,没有要设置的属性
- AxXMMVLvl – 忽略,没有要设置的属性
- DataGridView – 列标题文本与工具提示。注意,目前只能翻译预定义的静态列标题文本。动态设置的文本元素可通过字典实现。
- AxXMMVBtn – Text 属性
以下控件存在于 N1MM+ 中,但目前不受支持:
- ShapeContainer
- SplitContainer
- Chart
注意,许多控件是其他元素的容器。选项卡页(TabPages)就是一个明显的例子。某些控件(如 ListView)没有可直接设置的文本元素属性,但其子级(例如列标题)有。在这些情况下,会为该控件建立一条数据库记录,并把文本值字段留空。该条目的用途是通过 Parent 数据库字段维护修改子级所需的控件层级。
字典
为了实现内联字符串的翻译,在要启用翻译的每个窗体中都会创建一个字典。该字典只需保存待翻译字符串的英文占位符。我编写了一个工具来提取字符串、创建关联的编译时字典声明,并在要启用的字符串语句中插入适当的引用。这对我有效,YMMV。首次为一个大型窗体启用翻译可能很繁琐。一旦加入了字典,添加新字符串所需的工作就相当微不足道了。
再次强调,要记住帕累托原则(Pareto Principle),不要在这上面走火入魔。我大多把录入窗口(EntryWindow)的 MsgBox 标题(若存在)保留为英文,这样如果翻译后由用户报告给开发团队,就更容易识别出具体的错误消息。如果你决定不允许翻译这些字符串,可以完全跳过它(连同上面的相关属性)。