Multi-Language and Translations
Openbravo ERP is a multi language application. It can be translated to different languages and then it is possible to select one of these languages to show the user interface in that language.
Languages are defined in AD_Language table, which can be accessed from within the General Setup || Application || Language menu.
This table maintains a list of all languages and indicates which of them are currently in use. A language is in use in case it is marked as System Language.
Openbravo has out of the box a number of predefined languages, but it is also possible to define new ones. As AD_Language table is not exported directly to modules, if a new language is defined it must be exported to a module as reference data.
Translated texts are maintained in TRL database tables. Each table with data that requires translation has an associated TRL table. Note that apart from the translations defined in core it is also possible to define new translation tables for new tables in modules.
TRL tables are named like the base table to be translated plus a _TRL suffix. Thus the table where translations for AD_Window table are stored in is AD_Window_TRL.
These are the columns that a TRL table must have:
- Standard columns: ID, Client, Organization and audit columns.
- Foreign key to base table: for example in AD_Window_TRL there is a AD_Window_ID column that links the the record in AD_Window to be translated.
- AD_Language column. This column indicates the language this record translates to.
- IsTranslated column. It is a boolean value (Y/N) that indicates whether the record is translated or not. See population section for more details.
- Translation columns. For each column in the base table to be translated, the TRL table has a column with the same name. For example the name column in AD_Window table is translatable so AD_Window_TRL table has a name column.
Link between TRL and base tables
TRL tables are linked to their base tables by naming: each TRL table is named like its base one plus the TRL prefix and each translated column has the same name.
Additionally, the columns in the base table that require translation must be checked as translation.
TRL tables are automatically populated by database triggers. When a new record is added to the base table a trigger for that table should add a new record to the TRL table copying to the translation column the original ones and setting the isTranslated column to 'N'. If the base record is updated, the record in the TRL table must be updated setting the isTranslated column to 'N' but maintaining the translation columns as they were, this indicates that translation should be manually reviewed.
Here is an example of this kind of triggers.
New Manual UI
New manual components built in using Smartclient components should use the function OB.I18N.getLabel('MessageValue'), where 'MessageValue' is the value of an existing entry in the Ad_Message table. For example:
var buttonLabel = OB.I18N.getLabel('OBUIAPP_editButtonLabel');
This function will automatically return the translated label in the current language, if there is one (if not, it will return the label in the English language). It reads information from an array which is generated when the user logs in the application, so if you add or change some message values, you need to log out and log in again for your changes to take effect.
Old Manual UI
Translation for old manual windows and reports requires to pay special attention. It basically works in the same way as standard TRL tables, in this case the base table is AD_TextInterfaces and its translations table is AD_TextInterfaces_Trl.
These tables are populated when the system is built as part of the complete process or the can be populated explicitly invoking directly the translate ant task.
This task parses all files that can be translated (html, jrxml, srpt and fo) looking for translatable tags. When they are found, it checks whether the text in that tag exists in AD_TextInterfaces and if it does not it is inserted and a copy is done in AD_TextInterfaces_Trl for the rest of active languages.
Note that this table has a FileName column. When looking for the existence of the text it is done for all records that have the same file name as the one where the tag is found and in those that do not have any file name. This is used to allow to share the same translation for all tags with the same text regardless the file they are in, but it also allows to have one of these generic translations (without file name) but to translate a tag with that text in a different way for a singular file.
Before a compile complete is done, AD_TextInterfaces.IsUsed column is set to 'N' for all records of modules in development and when the text is found is set to 'Y' again. After the process finishes, this table is cleaned up removing all unused entries. All of this is executed by the compile.complete task in case tr property is true.
Modules and languages
When a module is defined, in case it contains elements that are translatable (for example windows, manual html pages, reports, etc.) it is necessary to check the Translation Required field and to select a language.
This selected language sets the base language for the module. This means that records for this module in base tables will have all the texts in that language and the TRL ones will contain translations for the rest of active languages. For example if we define a module's language as Spanish and this module adds new windows, these windows will be named in Spanish and they could be translated (in the TRL tables) to English.
A module can be set as a Translation module, in this case it will only contain a translation for another module. For more information read the article.
Although translations can be done using directly the application the standard process consists in exporting the translation to XMl files and translating them. Here is a complete explanation for this process.