DEV Community

Cover image for PrimeNG I18N API Usage with ngx-translate
Yiğit FINDIKLI
Yiğit FINDIKLI

Posted on • Edited on

16 2 2

PrimeNG I18N API Usage with ngx-translate

How can we use PrimeNG I18N with ngx-translate? Let's start!

Project Setup

Let's create a brand new angular application using angular-cli.



ng new primeng-i18n-with-ngx
cd primeng-i18n-with-ngx


Enter fullscreen mode Exit fullscreen mode

Let's add PrimeNG, PrimeFlex, PrimeIcons, and ngx-translate.



npm install primeng primeicons primeflex@2.0.0 @ngx-translate/core @ngx-translate/http-loader @angular/localize


Enter fullscreen mode Exit fullscreen mode

We need to import PrimeNG's CSS dependencies to Angular.json.



node_modules/primeicons/primeicons.css 
node_modules/primeng/resources/themes/vela-blue/theme.css 
node_modules/primeng/resources/primeng.min.css


Enter fullscreen mode Exit fullscreen mode

Now we need a couple of PrimeNG components and ngx-translate setup.

Note: Detailed ngx-translate setup can be found in official docs.

import { HttpClient, HttpClientModule } from '@angular/common/http';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { TranslateLoader, TranslateModule } from '@ngx-translate/core';
import { TranslateHttpLoader } from '@ngx-translate/http-loader';
import { RadioButtonModule } from 'primeng/radiobutton';
import { CalendarModule } from 'primeng/calendar';
import { DropdownModule } from 'primeng/dropdown';
import { FileUploadModule } from 'primeng/fileupload';
import { TableModule } from 'primeng/table';
import { ButtonModule } from 'primeng/button';
import { ConfirmPopupModule } from 'primeng/confirmpopup';
import { AppComponent } from './app.component';
// AoT requires an exported function for factories
export function HttpLoaderFactory(httpClient: HttpClient) {
return new TranslateHttpLoader(httpClient);
}
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
BrowserAnimationsModule,
HttpClientModule,
FormsModule,
RadioButtonModule,
DropdownModule,
CalendarModule,
FileUploadModule,
TableModule,
ConfirmPopupModule,
ButtonModule,
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useFactory: HttpLoaderFactory,
deps: [HttpClient]
}
})
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
view raw app.module.ts hosted with ❤ by GitHub

I want to use English to French translation because ngx-translation uses in their example.

Let's create our translation JSON files. The path should be like this:
structure

en.json:

{
"demo": {
"greetings": "Hello!",
"en": "English",
"fr": "French"
}
}
view raw en.json hosted with ❤ by GitHub

fr.json:

{
"demo": {
"greetings": "Bonjour!",
"en": "Anglaise",
"fr": "Français"
}
}
view raw fr.json hosted with ❤ by GitHub

Let's create our translation logic! We gonna use TranslateService and translate pipe for the general translation functionality for the translation.

app.component.html:

<div class="p-d-flex p-ai-center p-jc-between p-mt-3">
<div class="p-col-6">
<h2 class="p-ml-3">{{ 'demo.greetings' | translate }}</h2>
</div>
<div class="p-d-flex p-col-6 p-jc-end">
<div class="p-mr-3">
<p-radioButton (ngModelChange)="changeLang($event)" name="language" value="en" [(ngModel)]="lang"
inputId="en"></p-radioButton>
<label class="p-ml-1" for="en">{{ 'demo.en' | translate }}</label>
</div>
<div class="p-mr-3">
<p-radioButton (ngModelChange)="changeLang($event)" name="language" value="fr" [(ngModel)]="lang"
inputId="fr"></p-radioButton>
<label class="p-ml-1" for="fr">{{ 'demo.fr' | translate }}</label>
</div>
</div>
</div>

app.component.ts:

import { Component } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ConfirmationService, PrimeNGConfig } from 'primeng/api';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [ConfirmationService]
})
export class AppComponent {
lang: string = "en";
constructor(public translate: TranslateService, public primeNGConfig: PrimeNGConfig, private confirmationService: ConfirmationService) {
translate.addLangs(['en', 'fr']);
translate.setDefaultLang('en');
const browserLang = translate.getBrowserLang();
let lang = browserLang.match(/en|fr/) ? browserLang : 'en';
this.changeLang(lang);
}
changeLang(lang: string) {
this.translate.use(lang);
}
}

Alright, let's try it!
English
French

It's cool, right?

We need to use PrimeNGConfig for the translationing the PrimeNG components. Usage is quite simple.

Usage from the Documentation:

constructor(private config: PrimeNGConfig) {}
ngOnInit() {
this.config.setTranslation({
accept: 'Accept',
reject: 'Cancel',
//translations
});
}

But we want use in the our I18N JSON.

Let's create a calendar and change the month and day names!

Firstly we need to add month and day names to translation files.

PrimeNGConfig uses;

  • Month names for: monthNames

  • Min day names for: dayNamesMin.

Our files should be like this:

{
"demo": {
"greetings": "Hello!",
"en": "English",
"fr": "French",
"date": "Date"
},
"primeng": {
"dayNamesMin": [
"Su",
"Mo",
"Tu",
"We",
"Th",
"Fr",
"Sa"
],
"monthNames": [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
]
}
}
view raw en.json hosted with ❤ by GitHub
{
"demo": {
"greetings": "Bonjour!",
"en": "Anglaise",
"fr": "Français",
"date": "La datte"
},
"primeng": {
"dayNamesMin": [
"Di",
"Lu",
"Ma",
"Me",
"Je",
"Ve",
"Sa"
],
"monthNames": [
"Janvier",
"Février",
"Mars",
"Avril",
"Mai",
"Juin",
"Juillet",
"Août",
"Septembre",
"Octobre",
"Novembre",
"Décembre"
]
}
}
view raw fr.json hosted with ❤ by GitHub

Note: "primeng" usage just an example.

Let's create our Calendar.

<div class="p-d-flex p-ai-center p-jc-between p-mt-3">
<div class="p-col-6">
<h2 class="p-ml-3">{{ 'demo.greetings' | translate }}</h2>
</div>
<div class="p-d-flex p-col-6 p-jc-end">
<div class="p-mr-3">
<p-radioButton (ngModelChange)="changeLang($event)" name="language" value="en" [(ngModel)]="lang"
inputId="en"></p-radioButton>
<label class="p-ml-1" for="en">{{ 'demo.en' | translate }}</label>
</div>
<div class="p-mr-3">
<p-radioButton (ngModelChange)="changeLang($event)" name="language" value="fr" [(ngModel)]="lang"
inputId="fr"></p-radioButton>
<label class="p-ml-1" for="fr">{{ 'demo.fr' | translate }}</label>
</div>
</div>
</div>
<div class="p-fluid p-formgrid p-grid p-jc-center p-mt-3 p-mr-0">
<div class="p-col-6">
<div class="p-field p-col-12">
<label for="date">{{ 'demo.date' | translate }}</label>
<p-calendar inputId="date" [(ngModel)]="date"></p-calendar>
</div>
</div>
</div>

Now we want to change PrimeNG I18N API when ngx-translate trigger. We can use ngx-translate's "stream" observable for the detection.

import { Component, OnDestroy } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ConfirmationService, PrimeNGConfig } from 'primeng/api';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [ConfirmationService]
})
export class AppComponent implements OnDestroy {
lang: string = "en";
date: any;
subscription: Subscription;
constructor(public translate: TranslateService, public primeNGConfig: PrimeNGConfig, private confirmationService: ConfirmationService) {
translate.addLangs(['en', 'fr']);
translate.setDefaultLang('en');
const browserLang = translate.getBrowserLang();
let lang = browserLang.match(/en|fr/) ? browserLang : 'en';
this.changeLang(lang);
this.subscription = this.translate.stream('primeng').subscribe(data => {
this.primeNGConfig.setTranslation(data);
});
}
changeLang(lang: string) {
this.translate.use(lang);
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}

Stream is giving to us primeng section(According to the which translation option used). Coming data is:

{
"dayNamesMin": [
"Su",
"Mo",
"Tu",
"We",
"Th",
"Fr",
"Sa"
],
"monthNames": [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
]
}
view raw data-object hosted with ❤ by GitHub

We just binding our translation data to PrimeNGConfig with setTranslation function. And Voilà! Our calendar translated!

date

la-datte

Let's use this logic for Dropdown, ColumnFilter, ConfirmPopup and FileUpload too!

PrimeNG I18N API keys are on available at the documentation.

Now we're gonna update our translation JSONs again.

{
"demo": {
"greetings": "Hello!",
"en": "English",
"fr": "French",
"date": "Date",
"emptyMessage": "Empty Message",
"message": "Are you sure that you want to proceed?",
"confirm": "Confirm",
"name": "Name"
},
"primeng": {
"dayNamesMin": [
"Su",
"Mo",
"Tu",
"We",
"Th",
"Fr",
"Sa"
],
"monthNames": [
"January",
"February",
"March",
"April",
"May",
"June",
"July",
"August",
"September",
"October",
"November",
"December"
],
"emptyMessage": "No results found",
"emptyFilterMessage": "No results found - Filter",
"choose": "Choose",
"upload": "Upload",
"cancel": "Cancel",
"startsWith": "Starts with",
"contains": "Contains",
"notContains": "Not contains",
"endsWith": "Ends with",
"equals": "Equals",
"notEquals": "Not equals",
"clear": "Clear",
"apply": "Apply",
"matchAll": "Match All",
"matchAny": "Match Any",
"addRule": "Add Rule",
"removeRule": "Remove Rule",
"accept": "Yes",
"reject": "No"
}
}
view raw en.json hosted with ❤ by GitHub
{
"demo": {
"greetings": "Bonjour!",
"en": "Anglaise",
"fr": "Français",
"date": "La datte",
"emptyMessage": "Message vide",
"message": "Êtes-vous sûr de vouloir continuer?",
"confirm": "Confirmer",
"name": "Nom"
},
"primeng": {
"dayNamesMin": [
"Di",
"Lu",
"Ma",
"Me",
"Je",
"Ve",
"Sa"
],
"monthNames": [
"Janvier",
"Février",
"Mars",
"Avril",
"Mai",
"Juin",
"Juillet",
"Août",
"Septembre",
"Octobre",
"Novembre",
"Décembre"
],
"emptyMessage": "Aucun résultat trouvé",
"emptyFilterMessage": "Aucun résultat trouvé - Filtre",
"choose": "Choisir",
"upload": "Télécharger",
"cancel": "Annuler",
"startsWith": "Commence avec",
"contains": "Contient",
"notContains": "Ne contient pas",
"endsWith": "Se termine par",
"equals": "Équivaut à",
"notEquals": "Pas égal",
"clear": "Dégager",
"apply": "Appliquer",
"matchAll": "Faire correspondre tout",
"matchAny": "Correspondre à n'importe quel",
"addRule": "Ajouter une règle",
"removeRule": "Supprimer la règle",
"accept": "Oui",
"reject": "Non"
}
}
view raw fr.json hosted with ❤ by GitHub

Now we're just gonna create our components. Because our translation logic is already present. We don't need any logical change. We already did update the translation JSONs!

<div class="p-d-flex p-ai-center p-jc-between p-mt-3">
<div class="p-col-6">
<h2 class="p-ml-3">{{ 'demo.greetings' | translate }}</h2>
</div>
<div class="p-d-flex p-col-6 p-jc-end">
<div class="p-mr-3">
<p-radioButton (ngModelChange)="changeLang($event)" name="language" value="en" [(ngModel)]="lang"
inputId="en"></p-radioButton>
<label class="p-ml-1" for="en">{{ 'demo.en' | translate }}</label>
</div>
<div class="p-mr-3">
<p-radioButton (ngModelChange)="changeLang($event)" name="language" value="fr" [(ngModel)]="lang"
inputId="fr"></p-radioButton>
<label class="p-ml-1" for="fr">{{ 'demo.fr' | translate }}</label>
</div>
</div>
</div>
<div class="p-fluid p-formgrid p-grid p-jc-center p-mt-3 p-mr-0">
<div class="p-col-6">
<div class="p-field p-col-12">
<label for="date">{{ 'demo.date' | translate }}</label>
<p-calendar inputId="date" [(ngModel)]="date"></p-calendar>
</div>
<div class="p-field p-col-12">
<label for="empty">{{ 'demo.emptyMessage' | translate }}</label>
<p-dropdown [filter]="true" inputId="empty"></p-dropdown>
</div>
<div class="p-field p-col-12">
<p-fileUpload name="demo[]" (onUpload)="onUpload($event)" [multiple]="true">
<ng-template pTemplate="content">
<ul *ngIf="uploadedFiles.length">
<li *ngFor="let file of uploadedFiles">{{file.name}} - {{file.size}} bytes</li>
</ul>
</ng-template>
</p-fileUpload>
</div>
<div class="p-field p-col-12">
<p-table [value]="customers">
<ng-template pTemplate="header">
<tr>
<th>
<div class="p-d-flex p-jc-between p-ai-center">
{{ 'demo.name' | translate }}
<p-columnFilter type="text" field="name" display="menu"></p-columnFilter>
</div>
</th>
</tr>
</ng-template>
<ng-template pTemplate="body" let-customer>
<tr>
<td>
{{customer.name}}
</td>
</tr>
</ng-template>
</p-table>
</div>
<div class="p-field p-col-12">
<p-button (click)="confirm($event)" icon="pi pi-check" [label]="translate.instant('demo.confirm')">
</p-button>
<p-confirmPopup></p-confirmPopup>
</div>
</div>
</div>
import { Component, OnDestroy } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { ConfirmationService, PrimeNGConfig } from 'primeng/api';
import { Subscription } from 'rxjs';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
providers: [ConfirmationService]
})
export class AppComponent implements OnDestroy {
lang: string = "en";
date: any;
uploadedFiles: any[] = [];
password: string = "";
subscription: Subscription;
customers = [
{ "name": "Yancey" },
{ "name": "Chilton" },
{ "name": "Angelo" },
{ "name": "Carita" },
{ "name": "Wernher" }
]
constructor(public translate: TranslateService, public primeNGConfig: PrimeNGConfig, private confirmationService: ConfirmationService) {
translate.addLangs(['en', 'fr']);
translate.setDefaultLang('en');
const browserLang = translate.getBrowserLang();
let lang = browserLang.match(/en|fr/) ? browserLang : 'en';
this.changeLang(lang);
this.subscription = this.translate.stream('primeng').subscribe(data => {
this.primeNGConfig.setTranslation(data);
});
}
changeLang(lang: string) {
this.translate.use(lang);
}
onUpload(event: any) {
for (let file of event.files) {
this.uploadedFiles.push(file);
}
}
confirm(event: any) {
this.confirmationService.confirm({
target: event.target,
message: this.translate.instant('demo.message'),
icon: 'pi pi-exclamation-triangle'
});
}
ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}
}

Here we go!

en-full

fr-full

Voilà!

Thanks for the reading!

For Spanish readers: https://www.ibidemgroup.com/edu/internacionalizacion-i18n-primeng-ngx-translate/ (Translated by Chema Bescós 🙏🏻)

Repos:

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Cloudinary image

Video API: manage, encode, and optimize for any device, channel or network condition. Deliver branded video experiences in minutes and get deep engagement insights.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay