Přeskočit na hlavní obsah

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:

  1. Loads your dictionary from the translations.json into the translations service and assigns it the TRANS.MY_COMPONENT key
  2. Provides the TRANS.MY_COMPONENT key, 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 provideTranslations or 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>