-
Notifications
You must be signed in to change notification settings - Fork 4
Localization
- lucca-front uses
LOCALE_ID
to know what locale to use - you can't dynamically change locale
- all translations are overridable
Most components in lucca-front are made as to not have any text in it to avoid having to handle localization. But now some of them have, like the user-select
or the modal
each component that has associated translations gets them through token injection. for example the default translations for the lu-user-select
are provided as such
@NgModule({
/* ... */
providers: [
{ provide: LU_USER_SELECT_INPUT_TRANSLATIONS, useValue: luUserSelectInputTranslations },
]
})
export class LuUserSelectInputModule {}
each translations so provided contains translations in different languages, then lucca-front uses the one corresponding to the LOCALE_ID
, with a fallback to english.
as the translated labels are provided and use the provided value LOCALE_ID
, the translations cannot change dynamically. as a result the first LOCALE_ID
you provide is going to be the locale used.
it is not a huge problem as our solutions don't allow for a dynamic change of language ; but when working with ngx-translate it is easy to make a SPA that initializes in english, then calls an api to know what language the current user prefers, then switch to this language. With the current implementation, this behaviour is not supported. If you need a http call to know what language to use, there are 2 ways you could do it.
angular allows for some providers to be resolved before the app really initialises. you can find documentation about it here, a basic example would look like that
//app.module.ts
@NgModule({
declarations: [AppComponent],
imports: [ /* ... */ ],
providers: [
{
provide: APP_INITIALIZER,
useFactory: localeInit, // this factory calls the api endpoint to know what `LOCALE_ID` to use
multi: true,
},
],
bootstrap: [AppComponent],
})
export class AppModule {}
the problem with this approach is that the initialize
step of your application could become a bottleneck. the SPA will start initializing after the call resolves. If your api endpoint is slow, then you are delaying the Time to interactive, or even the First contentful paint on your SPA by this much.
this solution, which i am not a fan of, consists of
- having a robust lazyloading, each root route should load a module
- add a language guard at the root, that calls the api to know whats the current language is and sets it
- each lazyloaded module should reprovide
LOCALE_ID
with the right value - the appModule should be as empty as possible
as a result, when you navigate to /lol
for example, theses thing happen in this order
- app.module is loaded with
LOCALE_ID
= en - the language guard on
/
is called, it calls the language api, gets the current language, sets it somewhere, and resolve allowing the navigation to continue - the LolModule is lazyloaded
- it provides for its context
LOCALE_ID
with the right value
what might happen with this implementation is that all services that are provided in root may use the LOCALE_ID
provided in root, so en
if you forget the guard and/or to provide LOCALE_ID
in one of the lazy loaded modules, you might have a part of your SPA that is not in the same language as the rest
also it uses the notion of RouterGuard
for something it is not made for: resolving something
and it will be called with all navigationbetween root routes, from /lol
to /rofl
, from /rofl
to /lol
if you want to override translations for a given components, you just have to provide your own set of translations
const myUserSelectInputTranslations = {
en: { /* ... */ },
fr: { /* ... */ },
};
@NgModule({
imports: [
LuUserSelectInputModule,
],
providers: [
{ provide: LU_USER_SELECT_INPUT_TRANSLATIONS, useValue: myUserSelectInputTranslations },
]
})
export class MyModule {}
and voila, your translations are used instead of the default ones