Translations and Localizations
Translations and Localizations
Translation and localization services are in ASOL Platform Core library as AsolTranslationService and AsolLocalizationService.
Localization
The localization service is used to determine, store, and retrieve user's locale settings. The service implements these methods:
- getLanguage() - used to get current locale, in standard IETF BCP 47 format (e.g. 'en-US')
- getFallbackLanguage() - get fallback locale, which is 'en-US'
- changeLanguage() - changes the current locale programmatically
Current locale may be retrieved using the locale property or preferrably using the localeSignal. Signal version allows you to retrieve
localized texts using computed signals and thus automatically change them whenever the locale changes as well as using effects for reacting
to locale updates.
There is also the updated event that fires whenever the current locale is changed.
The current locale settings are looked up in the following places and in that order:
- cookies
- URL
- browser settings
If the information is not found in any of these, the service fallbacks to default language.
Translations
Translations are stored in a json file which can be defined at a module or component level. Translations are defined in key value pairs for each supported language. Keys should be in English language and in Pascal case.
You can (and should) have more than one translation file per application. Ideally, there should be at least one translation file per module. Shared translations should be in a shared folder of each application.
Individual dictionaries (JSON files) are distinguished using unique keys assigned when the translations are loaded. More on that in the next section.
Currently AVASpace support these languages:
- English (en-US)
- Slovak (sk-SK)
- Czech (cs-CZ)
Example of a translation file:
{
"en-US": {
"PleaseSelect": "Please Select",
"RightsCatalogue": "Rights Catalogue",
"AlertMessage": "The record contains unsaved changes, do you want to discard them?",
"AlertTitle": "Change node"
},
"cs-CZ": {
"PleaseSelect": "Please Select",
"RightsCatalogue": "Rights Catalogue",
"AlertMessage": "The record contains unsaved changes, do you want to discard them?",
"AlertTitle": "Change node"
},
"sk-SK": {
"PleaseSelect": "Please Select",
"RightsCatalogue": "Rights Catalogue",
"AlertMessage": "The record contains unsaved changes, do you want to discard them?",
"AlertTitle": "Change node"
}
}
Load (initialize) translations
As explained in the previous section, there is typically a whole lot of translation dictionaries that are distinguished
using unique keys. These keys are assigned when the translation dictionaries are loaded (initialized). They are simple
string, but the convention is to keep these strings in a constant object called TRANS. For example:
export const TRANS = {
HOME: "app-home-page-translations",
DASHBOARD: "app-dashboard-translations",
SHARED: "app-shared",
GENERAL: "apt-trans-general",
};
The key should be in a {unique-app-shortcut}-{component} form.
Note the TRANS.GENERAL key that refers to shared dictionary with generic translations from the Core library.
Provide translations
You load the translations using the provideTranslations function in the providers of your module or component, e.g.
import { Component } from '@angular/core';
import { provideTranslations } from '@asol-platform/core';
import { TRANS } from 'src/app/shared/constants/trans';
import translations from './translations.json';
@Component({
...
providers: [
// Other providers...
...provideTranslations(TRANS.MY_COMPONENT, translations),
],
})
export class MyComponent {}
The function does two things:
- Loads your dictionary from the translations.json into the translations service and assigns it the
TRANS.MY_COMPONENTkey - Provides the
TRANS.MY_COMPONENTkey, so that it can be injected from anywhere in the component's subtree
The second point (providing the key) simplifies further work with using the localization, as you don't need to explicitly provide that
key to the components that will use that dictionary. You can also benefit from a shorter localized pipe statements.
Note that due to the implementation of Angular's DI providers, any component in the subtree can provide its own key that would override
TRANS.MY_COMPONENT for its view, making the work with keys very convenient and intuitive.
Older initialize function
Before introducing provideTranslations, you had to load the translations using initialize method of the AsolTranslationService.
This was typically done in component's constructor. Whilst you can still use that function, and in fact that's what provideTranslations
does internally, it is recommended to use the new way, since it offers the benefits described above and can save quite a lot of writing.
Example of previous initialization:
import { Component, inject } from '@angular/core';
import { TRANS } from 'src/app/shared/constants/trans';
import translations from './translations.json';
@Component({
...
})
export class MyComponent {
private readonly trans = inject(AsolTranslationService);
constructor() {
this.trans.initialize(TRANS.HOME, localization);
}
}
Localized pipe
In order to get the localized strings in the component's template, you can use the localized pipe. In tandem with provideTranslations
it offers a very short and intuitive statements. Its return value is a signal, so that the string is automatically updated when the current
locale changes, so that you don't have to worry with subscribing to AsolLocalizationService.update event.
If you don't need to override any default (you use the provided translation key and current locale), the statement looks like this:
<p>{{ ('MyTranslation' | localized)() }}</p>
Note that you need to call the signal, so that it is evaluated, and that's why the whole expression needs to be in parentheses.
The pipe otherwise accepts two more arguments:
- Translation key if you don't use
provideTranslationsor need to override the provided one - Locale to be used, should you want to override the current one
Translating AsolLocalizedValue
The first pipe works with translation key. However, when working with real data, values are often stored in the AsolLocalizedValue<string>.
Those object can be translated with pipe localizeStringPure. Also, we have the localize function, which can be used in the typescript
part of the component
protected loc = inject(AsolLocalizationService)
protected objectToTranslate: AsolLocalizedValue<string> = // YOU object value
yourMethod() {
const translated = localize(objectToTranslate, this.loc);
}
Considering you have injected AsolLocalizationService in the component, you can use localizeStringPure in HTML.
<p>{{ objectToTranslate | localizeStringPure : loc.localeSignal() }}</p>