There is a certain amount of effort required to enable a form for localization. The effort required is tiny and one-time only for localizing controls. Text strings embedded within code need to be handled in a specific way, but that handling is only required for strings that need localization. Try…Catch constructs that display errors using only the exception object or exception.message property will automatically display based on the operating system language setting. Any application errors that are NOT intended for the user to interpret should be left in English so that the development team does not need to do extra work to figure out what the error is when it is reported to us.
The following properties need to be added to any form that is to support localization:
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
This property returns and sets the ToolTipText for any control that does not support the ToolTip property directly (which is pretty much everything EXCEPT MenuItems). Note that the ToolTip component on the form that enables these must either be named ToolTip1 OR you must change the code above to the correct name. If no ToolTips are coded on the form, omit the property routine altogether.
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
These properties support string lookup and substitution for inline messages, e.g. anything destined for a MsgBox or StatusStrip. The variable dict is a dictionary whose structure and purpose will be described below.
Private Sub Station_LanguageChanged() Handles stn.LanguageChanged Call SetLocalStrings(Me, True) End Sub
This causes the form to be redrawn with the new language if the language is changed in the Configurer form.
NOTE: The optional parameter in the call to SetLocalStrings (True in the above example) is used to force the conversion of strings to English when called. Normally if the selected language is English (the default) the routine does nothing further and returns immediately. If the language is changed from something other than English back to English then the routine must look up the English strings in the database and use those for the event handler to do anything meaningful. Otherwise, the application needs to be closed and reopened to redisplay in English.
Add the following call to the form load event:
The following controls are currently supported by the localization code.
- Label – Text property and ToolTip, if present
- CheckBox – Text property and ToolTip, if present
- RadioButton – Text property and ToolTip, if present
- Button – Text property and ToolTip, if present
- ListView – ColumnHeaders Text property
- GroupBox – Text property and all descendant controls
- GroupBoxEx – Text property and all descendant controls
- TableLayoutPanel – Text property and all descendant controls
- Panel – Text property and all descendant controls
- TabControl –All descendant controls, including Tab Pages
- StatusStrip – All ToolStripStatusLabels descendant controls
- MenuStrip (and descendant objects, i.e. MenuItems) – Text and ToolTip properties
- N1MMNumericUpDown – Ignored (no “Object not handled yet”) message
- AxN1MMWave– Ignored (no “Object not handled yet”) message
- ComboBox – ToolTipText property, if present
- TextBox – ToolTipText property, if present
- RichTextBox – ToolTipText property, if present
- PictureBox – ToolTipText property, if present
- NumericUpDown – ToolTipText property, if present
- HScrollBar – ToolTipText property, if present
- DateTimePicker – Ignored, no properties to set
- ListBox – Ignored, no properties to set
- TrackBar – Ignored, no properties to set
- AxXMMVView – Ignored, no properties to set
- AxXMMVLvl – Ignored, no properties to set
- DataGridView – Column header text and tool tips. Note that only predefined static column header text can be translated currently. Dynamically set text elements can be implemented via the dictionary.
- AxXMMVBtn – Text property
The following controls exist in N1MM+ but are not currently supported:
Note that a number of controls are containers for other elements. TabPages are an obvious example. Some controls such as the ListView have no direct text element properties that can be set but their descendent children (e.g. column headers) do. In these cases a database entry is made for the control with the text value field left blank. The purpose of the entry is to maintain the hierarchy of controls needed to alter the children via the Parent database field.
In order to implement the translation of inline strings, a dictionary is created in each form to be enabled for translation. This dictionary is only necessary to hold the English placeholders for strings to be translated. I created a tool to extract the string, create an associated compile time dictionary declaration and insert an appropriate reference in the string statement being enabled. This worked for me, YMMV. It can be tedious to enable a large form for the first time. The effort required to add a new string once a dictionary is included is pretty trivial.
Again, remember the Pareto Principle and do not go crazy with this. I mostly left the EntryWindow MsgBox headers (if present) in English so that it would be easier to identify the specific error message if translated and sent to the development team by a user. You can skip it altogether (along with the associated properties, above) if you decide to disallow any translations on these strings.