Internationalization: Difference between revisions
(Griffind moved page Internationalization to I18n) Tag: New redirect |
No edit summary |
||
(7 intermediate revisions by the same user not shown) | |||
Line 1: | Line 1: | ||
# | <strong>Language dropdown.</strong> In ''App.vue'', there is a language dropdown (currently hidden) at the top-right (to the left of Application dropdown). On app startup, in ''App.vue'', the <span style="color: brown">getLanguages</span>() method will be called which calls ''shell_init/languages'' endpoint which then calls IdentityServer endpoint ''shell_init/languages''. The list of languages come from the following table: | ||
<pre>SELECT lang.* | |||
FROM [Identity].dbo.language lang | |||
ORDER BY lang.language_code, | |||
lang.country_code; | |||
</pre> | |||
The language codes come from ISO 639 standard (see list [https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes here]). The country codes come from ISO 3166-1 alpha-2 standard (see list [https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements here]). Both can be combined to form a ''locale e.g. en-CA'' (for English Canada), ''fr-CA'' (French Canada), ''zh-CN'' (China), etc. | |||
<strong>Add translatable string in Novus-UI.</strong> Novus-UI is using [https://github.com/kazupon/vue-i18n vue-i18n] library (see documentation [https://kazupon.github.io/vue-i18n/started.html#html here]). | |||
Translations are inside ''src/i18n-messages.ts''. There is an default export which exports an object whose properties are locales and for each locale object, it has a “message” object whose properties are the translatable strings where property name is the translation key and property value is the translation text e.g. description: <span style="color: red">'Description'</span>. Translatable strings can have placeholders e.g. <span style="color: red">{0}</span> (first placeholder), <span style="color: red">{1}</span> (second placeholder), and so on. | |||
In component template, render string like this: {{ $t(<span style="color: red">'message.description'</span>) }}. In component script section, get string like this: <span style="color: blue">this.</span><span style="color: brown">$t</span>(<span style="color: red">'message.description'</span>).<span style="color: brown">toString</span>(). For placeholders, pass in an array as second parameter: $t(<span style="color: red">'message.applyTaxNum'</span>, [<span style="color: red">'1'</span>]). | |||
<strong>Add translatable string in Novus-Server.</strong> Novus-Server is using standard .NET Core for globalization/localization (see documentation [https://learn.microsoft.com/en-us/aspnet/core/fundamentals/localization?view=aspnetcore-3.1 here]). | |||
Translations are inside ''.resx'' resources files in ''Novus.Common/Resources'' folder. The default resources file is ''RsMessages.resx'' and is in English. When creating a resources file for a locale, name the file ''RsMessages.<locale>.resx'' e.g. ''RsMessages.zh-CN.resx'', and make sure its ''Access Modifier'' is set to ''Public'' so that the strings can be accessed in C# code. In the resources file, it’s a table of key-value pairs where key is Name and and Value is the translation text. Translatable strings can have placeholders e.g. <span style="color: red">{0}</span> (first placeholder), <span style="color: red">{1}</span> (second placeholder), and so on. | |||
In C# code, get string like this: <span style="color: rgb(167,209,222)">RsMessages</span>.BillTo. For placeholders, use <span style="color: blue">string</span>.Format() method and pass in placeholder values starting at second parameter which can accept any number of arguments e.g. <span style="color: blue">string</span>.Format(<span style="color: rgb(167,209,222)">RsMessages</span>.RecordSaveErrorUniqueConstraint, duplicateValue). | |||
For HTML attributes or component properties, add a colon (:) at the beginning of the attribute/property like this: :title="$t('message.add')" | |||
For some components such as the <span style="color: rgb(128,0,0)">kendo-tooltip</span> component (e.g. <span style="color: rgb(128,0,0)"><kendo-tooltip</span> :<span style="color red")title(/span)="$t(<span style="color: rgb(128,0,0)">'message.add'</span>)">), the string may not change when the language changes for some reason. A workaround is to add a unique key e.g. :<span style="color: red")>key</span>="<span style="color: rgb(128,0,0)">'fxrate-add-button-'</span> + <span style="color: blue">$i18n.locale</span>", to trigger re-render if locale changes. The key must be unique in the whole application so I recommend prefixing it with the name of the page e.g. “fxrate-” for ForeignExchangeRate.vue. | |||
<strong>Kendo UI table column title translations.</strong> Most of our Kendo UI tables use a computed property to be able to dynamically change the columns based on other variables changing. In the case of i18n, the grid column <span style="color: blue">titles</span> will have to react to <span style="color: blue">this</span>.<span style="color: rgb(0,112,193)>$i18n</span>.<span style="color: blue">locale</span>. For example: | |||
<pre>private columns: GridColumnProps[] = [ | |||
{ | |||
field: "EffectiveDate", | |||
title: this.$t('message.date').toString(), | |||
width: "220px", | |||
filter: "date", | |||
format: `{0:${dateFormats.kendoUi}}`, | |||
}, | |||
{ | |||
field: "FromCurrency", | |||
title: this.$t('message.fromCurrency').toString(), | |||
width: "170px" | |||
}, | |||
// ... | |||
]; | |||
get ForeignExchangeGridColumns() { | |||
return [ | |||
...this.ForeignExchangeGridColumnsUiTable.map(p => { | |||
switch (this.$i18n.locale && p.field) { | |||
case 'EffectiveDate': p.title = this.$t('message.date').toString(); break; | |||
case 'FromCurrency': p.title = this.$t('message.fromCurrency').toString(); break; | |||
// ... | |||
} | |||
return p; | |||
}), | |||
]; | |||
}</pre> | |||
Return to [[Programming Guide]] |
Latest revision as of 14:44, 15 January 2024
Language dropdown. In App.vue, there is a language dropdown (currently hidden) at the top-right (to the left of Application dropdown). On app startup, in App.vue, the getLanguages() method will be called which calls shell_init/languages endpoint which then calls IdentityServer endpoint shell_init/languages. The list of languages come from the following table:
SELECT lang.* FROM [Identity].dbo.language lang ORDER BY lang.language_code, lang.country_code;
The language codes come from ISO 639 standard (see list here). The country codes come from ISO 3166-1 alpha-2 standard (see list here). Both can be combined to form a locale e.g. en-CA (for English Canada), fr-CA (French Canada), zh-CN (China), etc.
Add translatable string in Novus-UI. Novus-UI is using vue-i18n library (see documentation here).
Translations are inside src/i18n-messages.ts. There is an default export which exports an object whose properties are locales and for each locale object, it has a “message” object whose properties are the translatable strings where property name is the translation key and property value is the translation text e.g. description: 'Description'. Translatable strings can have placeholders e.g. {0} (first placeholder), {1} (second placeholder), and so on.
In component template, render string like this: {{ $t('message.description') }}. In component script section, get string like this: this.$t('message.description').toString(). For placeholders, pass in an array as second parameter: $t('message.applyTaxNum', ['1']).
Add translatable string in Novus-Server. Novus-Server is using standard .NET Core for globalization/localization (see documentation here).
Translations are inside .resx resources files in Novus.Common/Resources folder. The default resources file is RsMessages.resx and is in English. When creating a resources file for a locale, name the file RsMessages.<locale>.resx e.g. RsMessages.zh-CN.resx, and make sure its Access Modifier is set to Public so that the strings can be accessed in C# code. In the resources file, it’s a table of key-value pairs where key is Name and and Value is the translation text. Translatable strings can have placeholders e.g. {0} (first placeholder), {1} (second placeholder), and so on.
In C# code, get string like this: RsMessages.BillTo. For placeholders, use string.Format() method and pass in placeholder values starting at second parameter which can accept any number of arguments e.g. string.Format(RsMessages.RecordSaveErrorUniqueConstraint, duplicateValue).
For HTML attributes or component properties, add a colon (:) at the beginning of the attribute/property like this: :title="$t('message.add')"
For some components such as the kendo-tooltip component (e.g. <kendo-tooltip :<span style="color red")title(/span)="$t('message.add')">), the string may not change when the language changes for some reason. A workaround is to add a unique key e.g. :key="'fxrate-add-button-' + $i18n.locale", to trigger re-render if locale changes. The key must be unique in the whole application so I recommend prefixing it with the name of the page e.g. “fxrate-” for ForeignExchangeRate.vue.
Kendo UI table column title translations. Most of our Kendo UI tables use a computed property to be able to dynamically change the columns based on other variables changing. In the case of i18n, the grid column titles will have to react to this.$i18n.locale. For example:
private columns: GridColumnProps[] = [ { field: "EffectiveDate", title: this.$t('message.date').toString(), width: "220px", filter: "date", format: `{0:${dateFormats.kendoUi}}`, }, { field: "FromCurrency", title: this.$t('message.fromCurrency').toString(), width: "170px" }, // ... ]; get ForeignExchangeGridColumns() { return [ ...this.ForeignExchangeGridColumnsUiTable.map(p => { switch (this.$i18n.locale && p.field) { case 'EffectiveDate': p.title = this.$t('message.date').toString(); break; case 'FromCurrency': p.title = this.$t('message.fromCurrency').toString(); break; // ... } return p; }), ]; }
Return to Programming Guide