As I needed multilingual data on a custom table I tried to identify if Microsoft has a best practice it applies to this requirement. I had to find out that multilingual data is handled differently in every instance I identified.
The application itself (forms, buttons, instructions, help etc.) is truly multilingual and is handled in a uniform throughout AX. On the other hand, record data mostly cannot be saved in different languages. At the most important places Microsoft has recognised this and has added the possibility of adding multilingual data.
Below are all the instances of multilingual texts I have identified:
Label files (application text):
This is still pretty straight forward: Translations of application text is handled in one location (the label files). There is one editor for editing the label files.
- X++: The label code is in quotation marks (e.g. "@SYS1234") and the texts can be edited in the label editor using context menu "Lookup Label/Text"
- AOT object properties: Field showing the standard language, when the field is selected the label code and "…" are displayed. A click on the three dots leads you to the label editor as above.
- The Rename Item Dimension dialogue is the exception to the rule. The dialogue bypasses the label editor, allowing the user to select a language and then edit multiple labels at a time.
Separate tables (multilingual data):
Data is always handled in separate tables and never using label files. I guess this is because you do not want the label files to grow indefinitely as more and more data is added. I wonder however if it could have been an option to use labels for a relatively limited table such as the unit table.
- Item text: Translations for the item text are saved in the InventTxt table. The item text is NOT saved on the InventTable, the default value that is displayed corresponds to the company language. If you change the company language or you share the table over multiple companies with different languages, the default text might be missing. The foreign key linking the InventTxt table to the InventTable is the ItemId.
- Unit text: Translations of the unit text are saved in the UnitTxt table, the default text is however saved on the Units table. The foreign key linking the UnitTxt table to the Unit table is the UnitId.
Even though there is essentially no difference in the table definitions of UnitTxt and InventTxt, the user experience is not the same.
- Workflow instructions: The multilingual instructions of Workflows are again implemented in a different way: The WorkFlowMessageTxt table is a bit more generic than the previous examples by using the TableId and RecordId to link to the source table. In addition the Multilanguage entry form allows the use of variables in the text. Just as is the case with the Item text, the Message text is not save on the base table at all. The system first tries to fetch the users language, if not found, then it tries to fetch the company language. The problem of the item text remains: if you change the company language or you share the table over multiple companies with different languages then the default text might be missing.
Suggestion for Microsoft
Just as Microsoft has added the UtcTimeDate type that supplies clever editing of date and time, Microsoft should add a new datatype for multilingual strings ("MLString"), that supplies the interface to edit, save and display the translations.
I would like to see the following properties:
- Default value when used in forms and reports: Try to find a language specific value in the following order 1. text in users language, 2. text in variant of users language (e.g. en-us instead of en-au), 3. text in company language, 4. text in variant of company language (e.g. de instead of de-ch) 5. any language
- Possibility of adding a second data field or a static text to define a specific language. Optional: If this language is not found, then follow the rules above.
- One consistent way of editing the translations. Suggestion: use the ItemName type of editing.
- Transparent management of the saved translations; Suggestion: A table contains all translations with the key TranslationId (preferably Int64 instead of a string) and the LanguageId. Maybe the TableId of the referencing table could be added to allow horizontal partitioning if the table grew too large. All that needs to be saved in the referring table is the TranslationId.