Reputation: 10483
I am using the i18n features of Angular 4 and building the project successfully with angular-cli in the target language. HTML templates are properly translated. However I got some texts in the javascript code.
What's the recommended way of localizing strings used in js source for things like validations? Can we expect i18n to come with a solution?
Currently I am using the locale to determine which translation to use.
The Locale gets set from the ng serve --locale fr
or ng build --locale fr
Building/serving like this:
ng serve --aot --locale fr ...
and using the locale in the code like this:
import { LOCALE_ID } from '@angular/core';
// ...
constructor (@Inject(LOCALE_ID) locale: string) {
}
(I was following the great hints on http://blog.danieleghidoli.it/2017/01/15/i18n-angular-cli-aot/)
Upvotes: 4
Views: 2668
Reputation: 5833
We're now (early 2019) using Angular 7 and it seems there's still no support for localizing static strings in TypeScript source files.
So we come up with a simple (if "hacky") way of doing it:
<!-- string table -->
<span #toolTipText hidden i18n="Tool tip text|Text displayed on the tooltip@@TOOLTIP_TEXT">Do not click this or bad things will happen.</span>
<span #errorOccured hidden i18n="Error notification|Error message displayed when the user ignores the warning on the tooltip@@ERROR_MESSAGE">A very bad thing just happened.</span>
@ViewChild()
decorator:@Component({
// ...
})
export class BadThingsComponent implements OnInit {
// "string table" elements for i18n
@ViewChild('toolTipText') warningMsg;
@ViewChild('errorOccurred') errorMsg;
// ...
.nativeElement.innerText
:onTryToPreventBadThings(event: CustomEvent) {
// ...
this.preventer.messageToDisplay = this.warningMsg.nativeElement.innerText;
// ...
}
onBadThingDidHappen(event: CustomEvent) {
// ...
this.notifier.message = this.errorMsg.nativeElement.innerText;
// ...
}
Upvotes: 1
Reputation: 6298
It seems that Angular is not supporting this yet. I use a mixture of the default Angular i18n approach because the toolchain is quite nice and a 3rd party tool like angular-l10n. The benefit of later is that it is automatically doing what is common for fetching resource files with translations, i.e. falling back from fr-FR -> fr -> en if no translation is available and offering other convenient functions like placeholders in translations. A manual approach does not offer this.
I'm using this in my service like the following:
constructor(translationService: TranslationService) {}
...
foo() {
this.translationService.translate('httpService.pagingError')
}
In the app starter app.module.ts
I modified the setup a bit to load the default locale from the app. Note the constructor.
import { L10nConfig, L10nLoader, TranslationModule, StorageStrategy, ProviderType } from 'angular-l10n';
const l10nConfig: L10nConfig = {
locale: {
languages: [
{ code: 'en', dir: 'ltr' },
{ code: 'de', dir: 'ltr' }
],
language: 'en',
storage: StorageStrategy.Cookie
},
translation: {
providers: [
{ type: ProviderType.Static, prefix: './assets/locale-' }
],
caching: true,
missingValue: 'No key'
}
};
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
TranslationModule.forRoot(l10nConfig)
],
declarations: [AppComponent, HomeComponent],
bootstrap: [AppComponent]
})
export class AppModule {
constructor(public l10nLoader: L10nLoader, public localeService: LocaleService,
@Inject(LOCALE_ID) locale: string) {
this.l10nLoader.load().then(() => this.localeService.setDefaultLocale(locale));
}
}
Upvotes: 0
Reputation: 20015
Use the I18nPipe
inside your code:
constructor(private translator: I18nPipe) {
let translatedText = this.translator.transform('Hello');
}
Where transform()
is a method within your I18nPipe
class that given a string
parameter translates it. Example:
i18n Pipe:
@Pipe({
name: 'i18n',
pure: false
})
export class I18nPipe implements PipeTransform {
constructor(public i18nService: I18nService) {
}
transform(phrase: any, args?: any): any {
return this.i18nService.getTranslation(phrase);
}
}
i18nService:
@Injectable()
export class I18nService {
public state;
public data: {};
getTranslation(phrase: string): string {
return this.data && this.data[phrase] ? this.data[phrase] : phrase;
}
private fetch(locale: any) {
this.jsonApiService.fetch(`/langs/${locale}.json`)
.subscribe((data: any) => {
this.data = data;
this.state.next(data);
this.ref.tick();
});
}
}
In your i18nService
you are getting the current language in the fetch()
method and through a custom API service (in my case is jsonApiService
) you get the data from a es.json, en.json, de.json, etc. (depending on your local
parameter) and in getTranslation()
you are actually translating a given parameter and returning it's translated value.
Update 1:
With this, you can have a file like es.json
:
"hello": "Hola",
"sentence1": "This is the sentence 1",
"goodbye": "Adiós"
And this @Pipe
can be used in the code to apply a translation in your .component.ts
file like I have shown above (this is useful for DataTables rendered with Ajax, for example).
Or can be applied in your template, simply:
{{ 'hello' | i18n }}
{{ this.goodbyeStringVariable | i18n }}
Upvotes: 4