How to use MatPaginatorIntl?

I'm using MatPaginator component and I'm trying to figure out how to translate those labels (documentation isn't clear enough about this).

I've found this article showing how to do this and I followed the steps:

1 - I created a file called custom-paginator.ts and put the following there:

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

export class CustomPaginator extends MatPaginatorIntl {
  constructor() {
    super();
    this.nextPageLabel = ' My new label for next page';
    this.previousPageLabel = ' My new label for previous page';
    this.itemsPerPageLabel = 'Task per screen';
  }
}

2 - In app.module.ts I put:

@NgModule({
  // ...
  providers: [
    {
      provide: MatPaginatorIntl,
      useClass: CustomPaginator
    }
  ]
})
export class AppModule

However, it simply doesn't change nothing. What am I missing?


Solution 1:

You can do it like this: I'm providing you with croatian labels:

customClass.ts

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

@Injectable()
export class MatPaginatorIntlCro extends MatPaginatorIntl {
  itemsPerPageLabel = 'Stavki po stranici';
  nextPageLabel     = 'Slijedeća stranica';
  previousPageLabel = 'Prethodna stranica';

  getRangeLabel = (page: number, pageSize: number, length: number) => {
    if (length === 0 || pageSize === 0) {
      return '0 od ' + 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 + ' od ' + length;
  };
}

and AppModule.ts:

providers: [{ provide: MatPaginatorIntl, useClass: MatPaginatorIntlCro}],

Solution 2:

Based on Vinko Vorih code, I made a paginator working with ngx-translate, here is the code :

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

export class PaginatorIntlService extends MatPaginatorIntl {
  translate: TranslateService;

  getRangeLabel = function (page, pageSize, length) {
    const of = this.translate ? this.translate.instant('paginator.of') : 'of';
    if (length === 0 || pageSize === 0) {
      return '0 ' + 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 + ' ' + of + ' ' + length;
  };

  injectTranslateService(translate: TranslateService) {
    this.translate = translate;

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

    this.translateLabels();
  }

  translateLabels() {
    super.itemsPerPageLabel = this.translate.instant('paginator.items_per_page');
    super.nextPageLabel = this.translate.instant('paginator.next_page');
    super.previousPageLabel = this.translate.instant('paginator.previous_page');
    this.changes.next();
  }

}

And then in your module providers entry :

{
  provide: MatPaginatorIntl,
  useFactory: (translate) => {
    const service = new PaginatorIntlService();
    service.injectTranslateService(translate);
    return service;
  },
  deps: [TranslateService]
}

This way, you can store translations in your usual i18n file and if your web app is able to dynamically change locale, paginator will be translated on demand.

Solution 3:

If you want a dynamic language switch with ngx-translate to work for you, here’s the solution, it works for me.

mat-paginator-i18n.service.ts

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

const ITEMS_PER_PAGE = 'Items per page:';
const NEXT_PAGE = 'Next page';
const PREV_PAGE = 'Previous page';
const FIRST_PAGE = 'First page';
const LAST_PAGE = 'Last page';

@Injectable()
export class MatPaginatorI18nService extends MatPaginatorIntl {
public constructor(private translate: TranslateService) {
  super();

  this.translate.onLangChange.subscribe((e: Event) => {
    this.getAndInitTranslations();
  });

  this.getAndInitTranslations();
}

public getRangeLabel = (page: number, pageSize: number, length: number): string => {
  if (length === 0 || pageSize === 0) {
    return `0 / ${length}`;
  }

  length = Math.max(length, 0);

  const startIndex: number = page * pageSize;
  const endIndex: number = startIndex < length
    ? Math.min(startIndex + pageSize, length)
    : startIndex + pageSize;

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

public getAndInitTranslations(): void {
  this.translate.get([
    ITEMS_PER_PAGE,
    NEXT_PAGE,
    PREV_PAGE,
    FIRST_PAGE,
    LAST_PAGE,
  ])
    .subscribe((translation: any) => {
      this.itemsPerPageLabel = translation[ITEMS_PER_PAGE];
      this.nextPageLabel = translation[NEXT_PAGE];
      this.previousPageLabel = translation[PREV_PAGE];
      this.firstPageLabel = translation[FIRST_PAGE];
      this.lastPageLabel = translation[LAST_PAGE];

      this.changes.next();
    });
}
}

In your module AppModule

@NgModule({
  // ...
  providers: [
    {
      provide: MatPaginatorIntl,
      useClass: MatPaginatorI18nService,
    },
  ],
})
export class AppModule {
// ...

en.json, etc.

{
  "Items per page:": "Items per page:",
  "Next page": "Next page",
  "Previous page": "Previous page",
  "First page": "First page",
  "Last page": "Last page",
}