Angular internationalization (i18n) and *ngFor
Asked Answered
P

3

18

I have a simple generic component in Angular which receives a list of strings and creates a radio group for these strings:

@Component({
  selector: 'radio-group',
  templateUrl: 
           `<div *ngFor="let item of items">
                 <label for="input_{{item}}">{{item}}</label>
                 <input type="radio" id="input_{{item}}" value="{{item}}" [formControl]="radioControl">
           </div>`,
  styleUrls: ['./radio-group.component.scss']
})
export class RadioGroupComponent {
    @Input()
    items: string[];
    @Input()
    radioControl: FormControl;
}

I need the radio group labels internationalized.
The official i18n documentation of Angular talks only about static HTML.

Is there any way to internationalize dynamic components (like *ngFor entries) with i18n template translation?

I'm aware of ngx-translate way, I'm interested particularly in i18n way.

Pegasus answered 24/1, 2017 at 9:33 Comment(1)
Better would be to do this in .ts but that is not yet available as a part of angular2 i18n. Similar request github.com/angular/angular/issues/12008 and github.com/angular/angular/issues/11405Offal
H
4

I was looking for the very same thing and also for an option to do dynamic translation without ngx-translate. ocombe seems to be the one responible for i18n at Angular. In this GitHub issue #16477 he posted some kind of roadmap for i18n in Angular.

▢ Use translation strings outside of a template - #11405 [blocked by runtime i18n]

As you can see this feature is not implemented in Angular yet but it's planned. The issue that is blocking this feature luckily is in progress:

▢ Runtime i18n (one bundle for all locales with AOT) - [working on it]

I don't remember where I read it but I think ocombe wrote, they want to implement this feature still in Angular 5 so it might be available before spring 2018 (the Angular roadmap says Angular 6 will be published in spring 2018)

Date: March/April 2018; Stable Release: 6.0.0

ocombe just posted this today:

I'm not the one working on this feature, and it's the holidays break, I'll let you know as soon as I know more

So all that remains is to use ngx-translate if you cannot wait, or you could subscribe to these GitHub issues #11405 & #16477 and get updated until they make this feature available. Hopefully early 2018 :)

PS: as far as I understood they also want to implement dynamic translation, but I think it wont be available before Angular 6.

UPDATE:

Now it's official: Runtime i18n wont be before Angular 6 (see: 11405#issuecomment-358449205)

EDIT:
I found a dirty hack to do that. you can create hidden div tags for your translations and save them via ViewChildren in a map for further use. You could even subscribe to the elements to update them.

@ViewChildren('test') myChildren; // the class needs to implement AfterViewInit
myMap = new Map();
ngAfterViewInit() {
  this.myChildren.forEach(value => this.myMap.set(value.nativeElement.getAttribute('name'), value.nativeElement.innerHTML));
  console.log(this.myMap);
}
Hauptmann answered 24/12, 2017 at 0:31 Comment(2)
You can follow the progress of the new Ivy renderer, which will make runtime i18n available here: github.com/angular/angular/issues/21706Hauptmann
looks like i18n with more features is a step closer now :) github.com/angular/angular/issues/11405#issuecomment-375769568Hauptmann
P
3

In Angular 9 you can use global $localize function like this:

$localize`String to translate`

Great article on this: https://blog.ninja-squad.com/2019/12/10/angular-localize/

Pursuer answered 26/4, 2020 at 7:31 Comment(0)
F
0

I am using @ngx-translate. What I did is, I declare the content that I want to translate in both language files, in my case es.json, and en.json.

es.json:

        "CONTENTS": {
    "CONT_1": "TEXTO_1",
    "CONT_2": "TEXTO_1",
    "CONT_3": "TEXTO_1",
    "CONT_4": "TEXTO_1",
    "CONT_5": "TEXTO_1",
    "CONT_6": "TEXTO_1",
    "CONT_7": "TEXTO_1",
    "CONT_8": "TEXTO_1",
    "CONT_9": "TEXTO_1",
    "CONT_10": "TEXTO_1",
    "CONT_11": "TEXTO_1"
}

en.json:

    "CONTENTS": {
    "CONT_1": "TEXT_1",
    "CONT_2": "TEXT_1",
    "CONT_3": "TEXT_1",
    "CONT_4": "TEXT_1",
    "CONT_5": "TEXT_1",
    "CONT_6": "TEXT_1",
    "CONT_7": "TEXT_1",
    "CONT_8": "TEXT_1",
    "CONT_9": "TEXT_1",
    "CONT_10": "TEXT_1",
    "CONT_11": "TEXT_1"
}

In the component that I want to translate, in my case the contents.component.ts, I: i) declare an array of contents; ii) inject the translate Service; iii) set it; iv) loop a for in which you construct an object that looks like this,

import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
@Component({
  selector: 'app-contents',
  templateUrl: './contents.component.html',
  styleUrls: ['./contents.component.css']
})
export class ContentsComponent implements OnInit {
  // i) Declare an array
  public contents = [];
  // inject the translateService
  constructor(public translateService: TranslateService) {
    // iii) set it
    translateService.addLangs(['es', 'en']);
    translateService.setDefaultLang('es');
    const browserLang = translateService.getBrowserLang();
    translateService.use(browserLang.match(/es|en/) ? browserLang : 'es');
    // loop for build a content object and push to the array
    for (let index = 1; index <= 11; index++) {
      const contentObj = {
        id: index,
        content: 'CONTENTS.CONT_' + index.toString()
      };
      this.contents.push(contentObj);
    }
  }
  ngOnInit() {
  }
}

Finally, in my contents.component.html looks like this

<ul>
    <li *ngFor= "let content of contents" >
        {{  content.content | translate }}
    </li>
</ul>

You can improve this code and make it better :) I Hope could be useful.

Feinleib answered 18/11, 2019 at 18:55 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.