Simplest translations for Angular (tested for v10+).
- removed
init
method in root import - changed injections: instead of
deps[]
useInjector
as first parameter of provided functions - changed resolver
- standalone ready
- added
EnvironmentProviders
as preferable initialization (provideTranslation
) - changed
translate
directive it is now structural
- see plain JS library changes.
- deprecated
init
method in root import. Instead useaddMiddleware
,loadDictionaries
andfinal
methods instead. -
lang
andfallbackLang
now in the root import. - added middleware pipeline (see Pipeline).
- removed
$less
property. Instead of$less
useplaceholder = 'single'
. - added
fallback
property to directive. -
defaultLang
renamed tolang
. -
extend
inforChild
initialization changed toloadDictionaries
. - added language detection change for directives and pipes
- after initialization
lang
andfallbackLang
can be changed only fromTranslateRootService
. - removed dynamic cache.
Please use link above to learn more about basic interaction, dictionaries, pluralization, cases, etc.
npm i simply-translate-angular
import { provideTranslation, withDictionary } from 'simply-translate-angular';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideTranslation(
{
lang: 'ru-RU',
fallbackLang: 'ru-RU',
},
withDictionary(({ lang }, inject) => {
const client = inject.get(HttpClient);
return client.get(...).pipe(map((result) => ({[lang]: result})));
})
),
],
};
Root Module
import { TranslateModule, TranslateService } from 'simply-translate-angular';
@NgModule({
declarations: [AppComponent, AppViewComponent],
imports: [
TranslateModule.forRoot({
// language
lang: window.navigator.language,
fallbackLang: 'ru-RU',
// static dictionaries
dictionaries:{'ru-RU':{...}}
// load dictionaries
loadDictionaries:({lang, fallbackLang}, injector) => {
const client = injector.get(HttpClient);
return client.get(...).pipe(map((result) => ({[lang]: result})));
}
})
]
});
<!-- use default language -->
<h2 *translate="'hello_user'; values:{ user: 'Oleg' }; let result = value;">{{ result }}</h2>
<!-- use other language -->
<h2 *translate="'hello_user'; to:'ru-RU';values:{ user: 'Oleg' }; let result = value">{{ result }}</h2>
<!-- use fallback -->
<h2 *translate="'hello_user_not_there'; values:{ user: 'Oleg' }; fallback:'Hello user'; let result = value">{{ result }}</h2>
Directives will detect dynamic language change by default. Use [detect] property to disable it.
<h2 *translate="'hello_user'; values:{ user: 'Oleg' }; detect:false; let result = value;">{{ result }}</h2>
Directive can use inner text as a fallback.
<h2>{{ 'hello_user' | translate: { user: 'Oleg' } }}</h2>
<!-- use other language -->
<h2>{{ 'hello_user' | translateTo: 'ru-RU': { user: 'Oleg' } }}</h2>
<!-- use fallback -->
<h2>{{ 'hello_user_not_there' | translate: { user: 'Oleg' } : 'Hello ${user}'}}</h2>
Pipes are pure by default. However if application has dynamic language change you may use special impure directive (it has internal dirty check), it will detect language changes as well as pipe parameters.
<h2>{{ 'hello_user' | translate$: { user: 'Oleg' } }}</h2>
@Component({
...
})
export class Component {
hello: string;
constructor(private translate: TranslateService) {
// use default language
this.hello = translate.translate('hello_user', { user: 'Oleg' })
// use other language
this.hello = translate.translateTo('ru-RU','hello_user', { user: 'Oleg' })
// use fallback
this.hello = translate.translateTo('ru-RU','hello_user_not_there', { user: 'Oleg' }, 'Hello ${user}')
}
}
To change language use TranslateRootService
lang
property.
To detect changes subscribe on languageChange$
and dictionaryChange$
. Note that loadDictionaries
method in root settings will not execute when language changes.
export class Component {
constructor(private rootTranslate: TranslateRootService) {
rootTranslate.lang = 'en-US';
}
}
You can use loader helper.
function getDictionary(lang: string, client: HttpClient) {
return client.get<Dictionary>(`/assets/translations/${lang}.json`);
}
You can use withDictionary
feature to fetch dictionaries.
import { provideTranslation, withDictionary } from 'simply-translate-angular';
export const appConfig: ApplicationConfig = {
providers: [
provideHttpClient(),
provideTranslation(
{
lang: 'ru-RU',
fallbackLang: 'en-US',
},
withDictionary(({ langm fallbackLang }, inject) => {
const client = inject.get(HttpClient);
return forkJoin([getDictionary(lang, client), getDictionary(fallbackLang, client)]).pipe(
map(([current, fallback]) => {
return { [lang]: current, [fallbackLang]: fallback };
})
);
})
),
],
};
Or split into two withDictionary
withDictionary(({ fallbackLang }, inject) => {
const client = inject.get(HttpClient);
return getDictionary(fallbackLang, client).pipe(
map((fallback) => {
return { [fallbackLang]: fallback };
})
);
}),
withDictionary(({ lang }, inject) => {
const client = inject.get(HttpClient);
return getDictionary(lang, client).pipe(
map((dictionary) => {
return { [lang]: dictionary };
})
);
}),
Root Module
forRoot
initialization allows you to fetch dictionaries with its loadDictionaries
field. It returns Observable
that contains set of dictionaries
import { TranslateModule } from 'simply-translate-angular';
@NgModule({
declarations: [...],
imports: [
...
TranslateModule.forRoot({
lang: window.navigator.language,
fallbackLang: 'ru-RU',
loadDictionaries: ({lang, fallbackLang}, injector) => {
const client = injector.get(HttpClient)
const res$ = forkJoin([getDictionary(lang, client), getDictionary(fbLang, client)]).pipe(
map((res) => {
return { [lang]: res[0], fbLang: res[1] };
})
);
return res$;
},
}),
...
],
...
})
Note: it is might be useful to hardcode fallback dictionary in .ts or .json file then import it rather then use http client to download.
import fallback from './translations/fallback';
provideTranslation(
{
lang: 'en-US',
fallbackLang: 'en-US',
},
withDictionary(({ fallbackLang }) => fallback),
withDictionary(/* Regular load*/)
),
Root Module
TranslateModule.forRoot({
...
fallbackLang: env.fallbackLanguage,
dictionaries: {
[env.fallbackLanguage]: fallback,
},
loadDictionaries: /* Regular load */
...
})
Load dictionaries for Lazy modules or components things become a little more complicated. To add synchronous dictionaries it is the same as for Root
import { extendTranslation } from 'simply-translate-angular';
@Component({
standalone: true,
providers:[
...extendTranslation(withDictionaryExtend(({ lang }) => (...)),
],
template: `...`,
})
export class DynamicComponent {
constructor() {}
}
Child Module
@NgModule({
declarations: [...],
imports: [
TranslateModule.forChild({
deps: [ HttpClient ],
dictionaries: ({ lang }) => (...),
...
})
]
})
export class DynamicModule {}
But to Asynchronously load dictionaries you would need to use translateResolve
.
Do not forget to provide service for lazy routes with extendTranslation
in providers
of route
export const routes: Routes = [
{
path: '...',
loadComponent: () => import('./dynamic/dynamic.component').then((m) => m.DynamicComponent),
resolve: translateResolve(
withDictionary(({ lang }, inject) => {
const client = inject.get(HttpClient);
return getDictionary(lang, client).pipe(
map((current) => {
return { [lang]: current };
})
);
}),
),
providers: [
...extendTranslation()
]
}
For rare cases you may use id
parameter for sub modules or components, that allows having different values with same key.
Unique values will be available only for modules with that special id
and for that special id
.
import { extendTranslation } from 'simply-translate-angular';
@Component({
standalone: true,
providers: [...extendTranslation(withIdentifier('my unique id'))],
template: `...`,
})
export class DynamicComponent {
constructor() {}
}
Child Module
@NgModule({
declarations: [...],
imports: [
TranslateModule.forChild({
id: 'my unique id'
dictionaries: ({ lang }) => ({[lang]:{
'key':'Value for Lazy'
}})
})
]
})
Currently it is possible to append middleware to the end of translation pipeline.
It might be specially useful to add logger or rarely fine-tune translation result.
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(routes),
provideHttpClient(),
provideTranslation(...,
withMiddleware(()=>
(injector) => {
const logger = injector.get(Logger)
return [
({params, result}) => {
if (result.fallingBack) {
logger.log(`Translation absent [${params.lang}:${params.key}]`);
}
},
];
},
)
),
],
};
Root Module
@NgModule({
declarations: [...],
imports: [
...
TranslateModule.forRoot({
addMiddleware: (injector) => {
const logger = injector.get(Logger);
return [
({params, result}) => {
if (result.fallingBack) {
logger.log(`Translation absent [${params.lang}:${params.key}]`);
}
},
];
},
}),
...
],
...
})