How to translate mat-paginator in Angular 4?

AngularMaterial DesignAngular Material

Angular Problem Overview


Do you have any ideas how can I translate "Items per page" in Angular's mat-paginator tag? The mat-paginator is an element from Material Design.

Angular Solutions


Solution 1 - Angular

You can use the MatPaginatorIntl for this. Will Howell made an example that no longer works, so here is an updated version (with Dutch) and step-by-step guidance.

  1. Import the MatPaginatorIntl from @angular/material into your application.
  2. Create a new paginator file for your locale (in this example I use Dutch) and import that: import { getDutchPaginatorIntl } from './app/dutch-paginator-intl'; in main.ts file
  3. Set a provider for the Paginator inside of the main.ts file, so it takes the translations of your local file (instead of English as default language):
providers: [
   { provide: MatPaginatorIntl, useValue: getDutchPaginatorIntl() }
]
  1. Inside your paginator-intl file, set the labels for the strings that can be translated and export these. Most important part of that file (see the example for more info):
paginatorIntl.itemsPerPageLabel = 'Items per pagina:';
paginatorIntl.firstPageLabel = 'Eerste pagina';
paginatorIntl.previousPageLabel = 'Vorige pagina';
paginatorIntl.nextPageLabel = 'Volgende pagina';
paginatorIntl.lastPageLabel = 'Laatste pagina';
paginatorIntl.getRangeLabel = dutchRangeLabel;

Example on StackBlitz with the paginator translations file as starting point.


June 2018 - Update to Angular 6.x
This updated Example on StackBlitz is upgraded to Angular 6.x to accommodate the latest version of the framework. Only packages have changed, nothing inside the paginator has changed.


June 2019 - Update to Angular 8.x
This updated Example on StackBlitz is upgraded to Angular 8.x to accommodate the latest version of the framework. Only packages have changed, nothing inside the paginator has changed.


February 2020 - Update to Angular 9.x
This updated Example on StackBlitz is upgraded to Angular 9.x to accommodate the latest version of the framework. Package versions have changed. Major change is the way to import from Angular Material. You cannot import from Material root anymore. You need to specify the import from the module (material/paginator) itself:

import { MatPaginatorModule, MatPaginatorIntl } from '@angular/material/paginator';


June 2020 - Update to Angular 10.x
This updated Example on StackBlitz is upgraded to Angular 10.x to accommodate the latest version of the framework. Only packages have changed, nothing inside the paginator has changed.


December 2020 - Update to Angular 11.x
This updated Example on StackBlitz is upgraded to Angular 11.x to accommodate the latest version of the framework. Only packages have changed, nothing inside the paginator has changed.


May 2021 - Update to Angular 12.x
This updated Example on StackBlitz is upgraded to Angular 12.x to accommodate the latest version of the framework. Only packages have changed, nothing inside the paginator has changed.


January 2022 - Update to Angular 13.x
This updated Example on StackBlitz is upgraded to Angular 13.x to accommodate the latest version of the framework. Only packages have changed, nothing inside the paginator has changed.

Solution 2 - Angular

Modified solution (with Angular 6) based on accepted answer with [@ngx-translate][1]:

@NgModule({
  imports: [...],
  providers: [
    {
      provide: MatPaginatorIntl, deps: [TranslateService],
      useFactory: (translateService: TranslateService) => new PaginatorI18n(translateService).getPaginatorIntl()
    }
  ]
})
export class CoreModule {}

And the PaginatorI18n:

import { MatPaginatorIntl } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';

export class PaginatorI18n {

    constructor(private readonly translate: TranslateService) {}

    getPaginatorIntl(): MatPaginatorIntl {
        const paginatorIntl = new MatPaginatorIntl();
        paginatorIntl.itemsPerPageLabel = this.translate.instant('ITEMS_PER_PAGE_LABEL');
        paginatorIntl.nextPageLabel = this.translate.instant('NEXT_PAGE_LABEL');
        paginatorIntl.previousPageLabel = this.translate.instant('PREVIOUS_PAGE_LABEL');
        paginatorIntl.firstPageLabel = this.translate.instant('FIRST_PAGE_LABEL');
        paginatorIntl.lastPageLabel = this.translate.instant('LAST_PAGE_LABEL');
        paginatorIntl.getRangeLabel = this.getRangeLabel.bind(this);
        return paginatorIntl;
    }

    private getRangeLabel(page: number, pageSize: number, length: number): string {
        if (length === 0 || pageSize === 0) {
            return this.translate.instant('RANGE_PAGE_LABEL_1', { length });
        }
        length = Math.max(length, 0);
        const startIndex = page * pageSize;
        // If the start index exceeds the list length, do not try and fix the end index to the end.
        const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize;
        return this.translate.instant('RANGE_PAGE_LABEL_2', { startIndex: startIndex + 1, endIndex, length });
    }
}

and cz.json

{
    "ITEMS_PER_PAGE_LABEL": "Počet řádků:",
    "NEXT_PAGE_LABEL": "Další stránka",
    "PREVIOUS_PAGE_LABEL": "Předchozí stránka",
    "FIRST_PAGE_LABEL": "První stránka",
    "LAST_PAGE_LABEL": "Poslední stránka",
    "RANGE_PAGE_LABEL_1": "0 z {{length}}",
    "RANGE_PAGE_LABEL_2": "{{startIndex}} - {{endIndex}} z {{length}}"
}  

Configure ngx-translate in app.module.ts:

import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core';
const httpLoaderFactory = (http: HttpClient) => new TranslateHttpLoader(http, './assets/i18n/', '.json');
@NgModule({
  imports: [
    TranslateModule.forRoot({
      loader: { provide: TranslateLoader, useFactory: httpLoaderFactory, deps: [HttpClient] }
    })
  ],
  providers: [{ provide: LOCALE_ID, useValue: 'cs' }],
  bootstrap: [AppComponent]
})
export class AppModule { }

[1]: https://github.com/ngx-translate/core "@ngx-translate"

Solution 3 - Angular

For a quick and dirty solution use this.paginator._intl property.

In my ...component.ts I have:

@ViewChild(MatPaginator) paginator: MatPaginator;

ngOnInit() {
  ...
  this.paginator._intl.itemsPerPageLabel = 'My translation for items per page.';
  ...
}

Solution 4 - Angular

For angular 9.0.0, if you are using i18n package, you can do

require: ng add @angular/localization

Create a file called my-paginator-intl.ts

import { MatPaginatorIntl } from '@angular/material/paginator'

const matRangeLabelIntl = (page: number, pageSize: number, length: number) => {
    if (length === 0 || pageSize === 0) {
        return $localize`:@@paginator.zeroRange:0 in ${length}`
    }
    length = Math.max(length, 0)
    const startIndex = page * pageSize

    // If the start index exceeds the list length, do not try and fix the end index to the end.
    const endIndex = startIndex < length ?  Math.min(startIndex + pageSize, length) : startIndex + pageSize
    return $localize`:@@paginator.rangeOfLabel:${startIndex + 1} - ${endIndex} in ${length}`
}

export function MyPaginatorIntl() {
    const paginatorIntl = new MatPaginatorIntl()

    paginatorIntl.itemsPerPageLabel = $localize`:@@paginator.displayPerPage:Items per page`
    paginatorIntl.nextPageLabel = $localize`:@@paginator.nextPage:Next page`
    paginatorIntl.previousPageLabel = $localize`:@@paginator.prevPage:Prev page`
    paginatorIntl.getRangeLabel = matRangeLabelIntl

    return paginatorIntl
}

Import to app.modudle.ts

import { MatPaginatorIntl } from '@angular/material/paginator'
import { MyPaginatorIntl } from './shared/paginator-int/my-paginator-intl'

@NgModule({
    providers: [
        { provide: MatPaginatorIntl, useValue: MyPaginatorIntl() },
    ]
})

Copy following to your language xlf file

<trans-unit id="paginator.zeroRange">
  <source>0 of <x id="PH" /></source>
  <target>0 trong <x id="PH" /></target>
</trans-unit>
<trans-unit id="paginator.rangeOfLabel">
  <source><x id="PH" /> - <x id="PH_1" /> of <x id="PH_2" /></source>
  <target><x id="PH" /> - <x id="PH_1" /> trong <x id="PH_2" /></target>
</trans-unit>
<trans-unit id="paginator.displayPerPage">
  <source>Items per page</source>
  <target>Hiển thị/Trang</target>
</trans-unit>
<trans-unit id="paginator.nextPage">
  <source>Next page</source>
  <target>Trang kế</target>
</trans-unit>
<trans-unit id="paginator.prevPage">
  <source>Prev page</source>
  <target>Trang trước</target>
</trans-unit>

Solution 5 - Angular

You can hack your way into MatPaginator._intl and put your string there using ngx-translate.

forkJoin({
  itemsPerPageLabel: this.translate.get('paginator.itemsPerPageLabel'),
  nextPageLabel: this.translate.get('paginator.nextPageLabel'),
  previousPageLabel: this.translate.get('paginator.previousPageLabel'),
  firstPageLabel: this.translate.get('paginator.firstPageLabel'),
  lastPageLabel: this.translate.get('paginator.lastPageLabel'),
}).subscribe(values => {
  this.paginator._intl.itemsPerPageLabel = values.itemsPerPageLabel;
  this.paginator._intl.nextPageLabel = values.nextPageLabel;
  this.paginator._intl.previousPageLabel = values.previousPageLabel;
  this.paginator._intl.firstPageLabel = values.firstPageLabel;
  this.paginator._intl.lastPageLabel = values.lastPageLabel;

  // 1 – 10 of 100
  // https://github.com/angular/components/blob/master/src/material/paginator/paginator-intl.ts#L41
  this.paginator._intl.getRangeLabel = (page: number, pageSize: number, length: number): string => {
    length = Math.max(length, 0);
    const startIndex = page * pageSize;
    const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize;
    return this.translate.instant('paginator.getRangeLabel', {
      startIndex: startIndex + 1,
      endIndex,
      length,
    });
  };

  // Otherwise, the paginator won't be shown as translated.
  this.dataSource.paginator = this.paginator;
});

Solution 6 - Angular

I build on Felix' answers, who builds on Roy's answer.

To account for dynamic language switch, my factory method uses TranslateService's stream() method (instead of instance()) that returns an observable that fires each time language is set. I also call paginator's change.next() to force redraw.

TranslateService is able to return a "dictionary" of vocabularies. With the right keys in the JSON file, Object.assign() can do most of the job.

Finally, I do not re-implement paginator's getRangeLabel(). Rather I take the old value and replace occurrences of "of" with translated text.

public getPaginatorIntl(): MatPaginatorIntl {
    const paginatorIntl = new MatPaginatorIntl();
    this.translation.stream('paginator.paginatorIntl').subscribe(dict => {
        Object.assign(paginatorIntl, dict);
        paginatorIntl.changes.next();
    });
    const originalGetRangeLabel = paginatorIntl.getRangeLabel;
    paginatorIntl.getRangeLabel = (page: number, size: number, len: number) => {
        return originalGetRangeLabel(page, size, len)
            .replace('of', this.translation.instant('paginator.of'));
    };
    return paginatorIntl;
}

Here is the fr.json for example.

{
    "paginator": {
        "paginatorIntl" : {
            "itemsPerPageLabel": "Items par page",
            "nextPageLabel": "Page suivante",
            "previousPageLabel": "Page précédente",
            "firstPageLabel": "Première page",
            "lastPageLabel": "Dernière page"
        },
        "of": "de"
    }
}

Solution 7 - Angular

this.dataSource.paginator._intl.itemsPerPageLabel = "Your string here";

this worked in latest angular8 + material8;

Solution 8 - Angular

Another version of @Felix's answer, but here you inject your service directly in the function without the need to make or instantiate a class:

In app.module.ts Add your provider:

providers: [
    YourCustomService,
    {provide: MatPaginatorIntl, useFactory: getPaginatorI18n, deps: [YourCustomService]}
  ]

Create a new ts file with your function (Example paginator-i18n.ts):

import {MatPaginatorIntl} from '@angular/material/paginator';

// This is the word that shows up in the range label
let paginPerRng = '';

const i18nRangeLabel = (page: number, pageSize: number, length: number) => {
  if (length == 0 || pageSize == 0) {
    return `0 ${paginPerRng} ${length}`;
  }

  length = Math.max(length, 0);

  const startIndex = page * pageSize;

  // If the start index exceeds the list length, do not try and fix the end index to the end.
  const endIndex = startIndex < length ?
    Math.min(startIndex + pageSize, length) :
    startIndex + pageSize;

  return `${startIndex + 1} - ${endIndex} ${paginPerRng} ${length}`;
};

export function getPaginatorI18n(YourCustomService: customService) {
  const paginatorIntl = new MatPaginatorIntl();

  // Call the localization methods in your service
  paginatorIntl.itemsPerPageLabel = customService.getResource(...);
  paginatorIntl.nextPageLabel = customService.getResource(...);
  paginatorIntl.previousPageLabel = customService.getResource(...);
  paginatorIntl.firstPageLabel = customService.getResource(...);
  paginatorIntl.lastPageLabel = customService.getResource(...);
  // We localize the word that shows up in the range label before calling the RangeLabel constant
  paginPerRng = customService.getResource(...);
  paginatorIntl.getRangeLabel = i18nRangeLabel;
  return paginatorIntl;
}

Solution 9 - Angular

Following the current Angular Material documentation (10.2.0) to modify the labels and text displayed, create a new instance of MatPaginatorIntl and include it in a custom provider. You have to import MatPaginatorModule (you would need it anyway to display paginator component)

import { MatPaginatorModule } from '@angular/material/paginator';

and in your component (where you are using paginator) you could use it in following way:

 constructor(private paginator: MatPaginatorIntl) {
    paginator.itemsPerPageLabel = 'Your custom text goes here'; 
}

Solution 10 - Angular

A laconic solution to change all labels of MatPaginator.

const rangeLabel: string = 'із';
const itemsPerPageLabel: string = 'Елементiв на сторiнцi:';
const firstPageLabel: string = 'Перша сторінка';
const lastPageLabel: string = 'Остання сторінка';
const previousPageLabel: string = 'Попередня сторінка';
const nextPageLabel: string = 'Наступна сторінка';

const getRangeLabel: (page: number, pageSize: number, length: number) => string = (
  page: number,
  pageSize: number,
  length: number
): string => {
  return new MatPaginatorIntl().getRangeLabel(page, pageSize, length).replace(/[a-z]+/i, rangeLabel);
};

export function getPaginatorIntl(): MatPaginatorIntl {
  const paginatorIntl: MatPaginatorIntl = new MatPaginatorIntl();

  paginatorIntl.itemsPerPageLabel = itemsPerPageLabel;
  paginatorIntl.firstPageLabel = firstPageLabel;
  paginatorIntl.lastPageLabel = lastPageLabel;
  paginatorIntl.previousPageLabel = previousPageLabel;
  paginatorIntl.nextPageLabel = nextPageLabel;
  paginatorIntl.getRangeLabel = getRangeLabel;
  
  return paginatorIntl;
}

Solution 11 - Angular

A simple solution using ngx-translate.

@ViewChild(MatPaginator, { static: true }) paginator: MatPaginator;

constructor(private translate: TranslateService){}

ngOnInit() {
  this.translatePaginator();
}

async translatePaginator() {
  const label = await this.translate.get('COMMON.ItemsPerPageLabel').toPromise();
  this.paginator._intl.itemsPerPageLabel = label;
}

Solution 12 - Angular

If you want to change dynamically the languange, you can enter this code:

    this.translate.onLangChange.subscribe(() => {
            this.getPaginatorIntl(matPaginatorIntl);
        });

    private getPaginatorIntl(matPaginatorIntl: MatPaginatorIntl): void {
        matPaginatorIntl.itemsPerPageLabel = this.translate.instant('PAGINATOR.ITEM');
        matPaginatorIntl.nextPageLabel = this.translate.instant('PAGINATOR.NEXT_PAGE');
        matPaginatorIntl.previousPageLabel = this.translate.instant('PAGINATOR.PREVIOUS_PAGE');
        matPaginatorIntl.firstPageLabel = this.translate.instant('PAGINATOR.FIRST_PAGE');
        matPaginatorIntl.lastPageLabel = this.translate.instant('PAGINATOR.LAST_PAGE');
        matPaginatorIntl.getRangeLabel = this.getRangeLabel.bind(this);
        matPaginatorIntl.changes.next();
    }

    private getRangeLabel(page: number, pageSize: number, length: number): string {
        if (length === 0 || pageSize === 0) {
            return `0 ${this.translate.instant('PAGINATOR.OF')} ${ length }`;
        }
        length = Math.max(length, 0);
        const startIndex = page * pageSize;
        // If the start index exceeds the list length, do not try and fix the end index to the end.
        const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize;
        return `${startIndex + 1} - ${endIndex} ${this.translate.instant('PAGINATOR.OF')} ${length}`;
    }

It's import insert 'changes.next();' after the edit of the object matPaginatorIntl.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbigmeisterView Question on Stackoverflow
Solution 1 - AngularRoyView Answer on Stackoverflow
Solution 2 - AngularFelixView Answer on Stackoverflow
Solution 3 - AngularGoToView Answer on Stackoverflow
Solution 4 - AngularxCiCiView Answer on Stackoverflow
Solution 5 - AngularNato BoramView Answer on Stackoverflow
Solution 6 - AngularAhmad ShahwanView Answer on Stackoverflow
Solution 7 - Angularshaheer shukurView Answer on Stackoverflow
Solution 8 - AngularYassir KhaldiView Answer on Stackoverflow
Solution 9 - AngularlukView Answer on Stackoverflow
Solution 10 - AngularYarik256View Answer on Stackoverflow
Solution 11 - AngularYadiana MolinaView Answer on Stackoverflow
Solution 12 - AngularAndrea Di LorenzoView Answer on Stackoverflow