How to use i18n with component inputs that are objects in Angular?
Asked Answered
L

3

9

There is a situation where an input is defined on a child component like the following:

interface MyValues {
   text: string;
   path: string;
   someOtherValue: string;
}

@Input() myValues: MyValues;

I need to pass myValues to the child component from the parent via an input like the following:

<my-child-component [myValues]="myValues" />

Since it's not a simple data type input, I can't use the attribute style of i18n as recommended in the Angular docs here. This is an object with multiple values so it can't be translated as it's passed to the child component (unless I'm missing something).

In the child component, there is some code such as the following:

<span *ngFor="let myValue of myValues">
   <a>{{myValue.Text}}</a>
</span>

Ordinarily what I'd like to do is assign an id to that anchor that needs translated like the following:

<a i18n="@@myChildComponent_text">{{myValue.Text}}</a>

The problem with this is it will create exactly one field in the translation file named, @@myChildComponent_text to be translated. However, this object being passed in to this child component is dynamic in what values are inside of myValues and therefore the literal translation will vary depending on what's being passed in.

My question is, how do I still leverage the i18n Angular internationalization abilities and @@id custom ids when passing an object to an input on a child component, where that object will have varying physical values within it that need translated?

Lamori answered 30/8, 2019 at 21:5 Comment(0)
F
1

Dynamic fields cannot be translated using angulars i18n. Because eventually it is a simple text replace what happens.

You add an attribute to your HTML-Tags which contains simple text. The ng extract command creates a file (XLIFF 1.2 (default), XLIFF 2, XML Message Bundle (XMB)), which can be used with different tools (normally this is done by an Translator) to create a new, translated file. You can extend angular.json with a configuration for each language, telling angular which translation file should be used. For example French:

"configurations": {
...
"fr": {
  "aot": true,
  "outputPath": "dist/my-project-fr/",
  "i18nFile": "src/locale/messages.fr.xlf",
  "i18nFormat": "xlf",
  "i18nLocale": "fr",
  ...
}

When you now use ng-build --configuration=frAngular replaces your static text with the one from the translation file. For every language a separate application is built. When you deploy your app you handle different languages using different urls, e.g. host/my-app/fr for French or host/my-app/de for german, each pointing to a specific translated build of your application.

The downside of this approach is you cannot handle dynamic values because it works only with static text. That's why you have to use a third party library for handling this scenario. A common library would be ngx-translate. Where you can resolve ids against a json file. If you want to use multiple translation files you can also use ngx-translate-multi-http-loader in combination with ngx-translate.

Mostly you combine i18n with ngx-translate (or another similar library) to get full multi language support.

EDIT 05.02.2021:

The future of ngx-translate is unclear, PRs will be merged it is currently kind of a basic support. More Information here: https://github.com/ngx-translate/core/issues/783

As an alternative try out:

ngneat/transloco

Fechner answered 10/9, 2019 at 14:8 Comment(2)
Where did you found information, that ngx-translate isn't supported anymore?Herbage
github.com/ngx-translate/core/issues/783 Meanwhile they agreed to continue support, which means only fixing bugs, there won't be new features. It is an ongoing discussionFechner
A
0

You should use ngx-translate https://github.com/ngx-translate/core.

Define the translations: Once you've imported the TranslateModule, you can put your translations in a json file that will be imported with the TranslateHttpLoader. The following translations should be stored in en.json.

{
    "HELLO": "hello {{value}}"
}

You can also define your translations manually with setTranslation.

translate.setTranslation('en', {
    HELLO: 'hello {{value}}'
});

The TranslateParser understands nested JSON objects. This means that you can have a translation that looks like this:

{
    "HOME": {
        "HELLO": "hello {{value}}"
    }
}

Use the service, the pipe or the directive: You can either use the TranslateService, the TranslatePipe or the TranslateDirective to get your translation values.

With the service, it looks like this:

translate.get('HELLO', {value: 'world'}).subscribe((res: string) => {
    console.log(res);
    //=> 'hello world'
});

This is how you do it with the pipe:

<div>{{ 'HELLO' | translate:param }}</div>

And in your component define param like this:

param = {value: 'world'};

This is how you use the directive:

<div [translate]="'HELLO'" [translateParams]="{value: 'world'}"></div>

Or even simpler using the content of your element as a key:

<div translate [translateParams]="{value: 'world'}">HELLO</div>
Acclimatize answered 4/9, 2019 at 11:28 Comment(1)
I'm sorry but my issue with this is telling someone to "use another library" is not necessarily an answer to the problem. If the answer is, "the implementation you're needing can't be done because of x, y, and z (facts)" then that's acceptable. However if the person posting is knee deep in a particular library/implementation seeking help & the answer is, "just use a different library," that won't work. If you'd like to improve the answer as to why the Angular i18n implementation will or will not work I'll be happy to remove the downvote (which I feel badly about as I know you spent time on it)Lamori
L
0

I ran into a similar situation, where a multiselect component requires certain options to be set before it's initialized.

I resolved it as followed:

#Page Component

dropdownSettings = {
    singleSelection: false,
    idField: 'id',
    textField: 'nameNl',
    selectAllText: 'Select all',
    unSelectAllText: 'Deselect all',
    itemsShowLimit: 3,
    allowSearchFilter: true
};

updateDropdownSettingsOnLanguageChange(selectAllText: string, unSelectAllText: string) {
    this.dropdownSettings.selectAllText = selectAllText;
    this.dropdownSettings.unSelectAllText = unSelectAllText;
    return this.dropdownSettings;
}

#Component HTML

<ng-multiselect-dropdown [data]="availableLabels"
[settings]="updateDropdownSettingsOnLanguageChange(('service-dropdown.select-all' | translate), ('service-dropdown.deselect-all' | translate))">
                        </ng-multiselect-dropdown>
Loiseloiter answered 22/6, 2020 at 9:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.