The new paginator has a small text in the documentation about Internationalization. I was wondering if anyone has an example of doing this. The document states that you can do this by "providing your own instance of MdPaginatorIntl". I have no idea how to do this... Thanks!
Please keep GitHub issues for bug reports / feature requests. Better avenues for troubleshooting / questions are stack overflow, gitter, mailing list, etc.
Although this is not explicitly mentioned in the docs, you can infer the purpose of MdPaginatorIntl
because it's listed as an Injectable class. This means that it can be leveraged with Angular Dependency Injection (DI), which you can read up on here.
When the docs say you must provide your own instance, it means extending the MdPaginatorIntl
class, and then overriding the existing implementation in your component in the providers
section.
Try in oninit this:
this.paginator._intl.itemsPerPageLabel = 'Registros por p谩gina';
Okay I solved this by using each of your solutions ;)
Adding MdPaginator to providers array =>
providers: [MdPaginator]
In the constructor inject the paginator =>
private paginator: MdPaginator
In the OnInit cycle (using translateService of ng2-translate) =>
this.translate.get('app.pagination.itemsPerPageLabel').subscribe(translation => {
this.paginator._intl.itemsPerPageLabel = translation
});
_intl
is a private data member on MdPaginator for a reason: it shouldn't be modified directly. Please follow the documentation to create your own instance of the provider, instead of violating abstraction barriers.
@Laurensvdw, actually @CaerusKaru is right but in your defence I can say you just couldn't implement it properly since MdPaginatorIntl
is not exposed.
Okay that explains why I couldn't get it working with the documentation @CaerusKaru mentioned earlier about DI, as the MdPaginatorIntl
was not available to place in the providers
... Thanks for your findings @shlomiassaf !
Ah, now _that_ is a bug. I sent #5726 to fix.
I'm still unclear as to the process for this.
what I understand; and please correct me wherever I'm wrong
what else?
thank you in advanced
@Lior-G see https://plnkr.co/edit/Zy0kOh78CBelkBH8VEug?p=preview. I don't know if that's the best way to do it, but it works
@willshowell
what version of Angular Material are you using?
MdPaginatorIntl is not exposed in in 2.0.0-beta.8 which currently is the latest release
@Lior-G The Plunkr uses the latest build from the master branch (generally a couple of commits behind the latest commit). MdPaginatorIntl is exposed as of #5716.
You can have your project rely on the latest build by following Step 1 in the Getting Started guide, just run:
npm install --save angular/material2-builds angular/cdk-builds
Hi, MdPaginatorIntl is exported as ex on (@angular/material/typings/index.d.ts) you can import this class like this:
import {
傻x as MdPaginatorIntl
} from '@angular/material';
And after:
@NgModule({
declarations: [
],
imports: [
{ provide: MdPaginatorIntl, useClass: MyClassIntl }
]
, bootstrap: [AppComponent]
})
export class AppModule { }
//MyClassIntl
export class MyClassIntl {
itemsPerPageLabel = 'Registros por p谩gina: ';
nextPageLabel = 'P谩gina siguiente';
previousPageLabel = 'P谩gina anterior';
getRangeLabel(page: number, pageSize: number, length: number): string {
if (length === 0 || pageSize === 0) {
return `0 de ${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} de ${length}`;
}
}
The cool example that @diarcastro provide unfortunately is not working on beta.10
seems that /typings/index.d.ts in beta.10 has't
export { MdPaginatorIntl as 傻x } from './paginator/paginator-intl';
The documentation to do this is really poor. Anybody with an example for creating your own class with internationalization using for example ngx-translate? Something DYNAMIC ???
+1 to an example how to make this DYNAMIC!!! We use ngx-translate and cannot make this single line of the table dynamic...
@mhosman @rsaulo This is how I did it in "@angular/material": "^5.0.3",
Create separate file e.g. custom-mat-paginator-int.ts:
import {TranslateService} from '@ngx-translate/core';
import {MatPaginatorIntl} from '@angular/material';
import {Injectable} from '@angular/core';
@Injectable()
export class CustomMatPaginatorIntl extends MatPaginatorIntl {
constructor(private translate: TranslateService) {
super();
this.translate.onLangChange.subscribe((e: Event) => {
this.getAndInitTranslations();
});
this.getAndInitTranslations();
}
getAndInitTranslations() {
this.translate.get(['ITEMS_PER_PAGE', 'NEXT_PAGE', 'PREVIOUS_PAGE', 'OF_LABEL']).subscribe(translation => {
this.itemsPerPageLabel = translation['ITEMS_PER_PAGE'];
this.nextPageLabel = translation['NEXT_PAGE'];
this.previousPageLabel = translation['PREVIOUS_PAGE'];
this.changes.next();
});
}
getRangeLabel = (page: number, pageSize: number, length: number) => {
if (length === 0 || pageSize === 0) {
return `0 / ${length}`;
}
length = Math.max(length, 0);
const startIndex = page * pageSize;
const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize;
return `${startIndex + 1} - ${endIndex} / ${length}`;
}
}
Load and include it in providers in app.module.ts
import {CustomMatPaginatorIntl} from './shared/custom-mat-paginator-intl';
providers: [{
provide: MatPaginatorIntl,
useClass: CustomMatPaginatorIntl
}]
@rivoheinsalu , yes, i ended with the same solution, thanks for the reply!
Hey @rivoheinsalu, thanks for sharing. The only problem about this is that it keeps saying for example 1 of 2. How can I change the "of"?
@mhosman I have edited my example, see getRangeLabel.
I have not tried it with 'of', insted changed it to '/'.
You could try to set private properti and assing value in translation part:
this.ofLabel = translation['OF_LABEL']
And then try to use it in getRangeLabel(). Unfortunately I cannot currently test it.
Great @rivoheinsalu !! Thank you very much for your help!
Sorry I have just one last problem... I have another component with preferences. In that component I change the language. Then, I just go back to the component with the paginator and the language is not being changed (just in the paginator, in the rest of the site is working ok). The onLangChange is not working or maybe because I change the language in other component, the onLangChange is not being fired... so... the only way is to create a custom observable??
@mhosman did you include following to providers in global (app.module.ts) as I told not in component?
providers: [{
provide: MatPaginatorIntl,
useClass: CustomMatPaginatorIntl
}]
For me it works well when changing language in one component and then navigating to component with table.
Second this.getAndInitTranslations();
in CustomMatPaginatorIntl should get translations on first load with current language and onLangChange should trigger this.getAndInitTranslations();
only when language is changed while table component is already open.
Try debugging or console logging in CustomMatPaginatorIntl and see if second this.getAndInitTranslations()
is even invoked, hope I am not wrong, but I think the problem comes down to your setup somewhere.
Yes @rivoheinsalu all setup it's okay. Paginator is working okay and current language it's okay. The only problem is with onLangChange. It's not being fired (I also put a console.log inside and nothing). Important: all the rest of the site is changing the language okay, the only problem is with the onLangChange inside this CustomMatPaginatorIntl.
In my table I only added the following in the ngOnInit():
ngOnInit() {
this.paginator._intl.itemsPerPageLabel = 'Registros por p谩gina';
this.paginator._intl.nextPageLabel = 'Siguiente';
this.paginator._intl.previousPageLabel = 'Anterior';
}
@dani3lrp how an I translate "1 of 10" ?
@rivoheinsalu I got No provider for TranslateService! with your solution
@duard Have you properly setup ngx-translate module importing TranslateModule.forRoot()?
See documentation from here: https://github.com/ngx-translate/core
Extending on @rivoheinsalu his answer (with 'OF' translation & unsubscribing from translate)
import { Injectable, OnDestroy } from '@angular/core';
import { MatPaginatorIntl } from '@angular/material';
import { TranslateService } from '@ngx-translate/core';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class CustomMatPaginatorIntl extends MatPaginatorIntl implements OnDestroy {
unsubscribe: Subject<void> = new Subject<void>();
OF_LABEL = 'of';
constructor(private translate: TranslateService) {
super();
this.translate.onLangChange.takeUntil(this.unsubscribe).subscribe(() => {
this.getAndInitTranslations();
});
this.getAndInitTranslations();
}
ngOnDestroy() {
this.unsubscribe.next();
this.unsubscribe.complete();
}
getAndInitTranslations() {
this.translate.get([
'PAGINATOR.ITEMS_PER_PAGE',
'PAGINATOR.NEXT_PAGE',
'PAGINATOR.PREVIOUS_PAGE',
'PAGINATOR.OF_LABEL'
])
.takeUntil(this.unsubscribe)
.subscribe(translation => {
this.itemsPerPageLabel = translation['PAGINATOR.ITEMS_PER_PAGE'];
this.nextPageLabel = translation['PAGINATOR.NEXT_PAGE'];
this.previousPageLabel = translation['PAGINATOR.PREVIOUS_PAGE'];
this.OF_LABEL = translation['PAGINATOR.OF_LABEL'];
this.changes.next();
});
}
getRangeLabel = (page: number, pageSize: number, length: number) => {
if (length === 0 || pageSize === 0) {
return `0 ${this.OF_LABEL} ${length}`;
}
length = Math.max(length, 0);
const startIndex = page * pageSize;
const endIndex = startIndex < length ? Math.min(startIndex + pageSize, length) : startIndex + pageSize;
return `${startIndex + 1} - ${endIndex} ${this.OF_LABEL} ${length}`;
};
}
Everything else is exactly the same as specified in Rivo's answer
Here is my test file for the code above. If you like to have code coverage 馃挴 :
import { TestBed } from '@angular/core/testing';
import { async } from '@angular/core/testing';
import { TranslateCompiler, TranslateFakeCompiler, TranslateModule, TranslateService } from '@ngx-translate/core';
import { CustomMatPaginatorIntl } from './custom-matPaginatorIntl.service';
describe('CustomMatPaginatorIntl', () => {
let service: CustomMatPaginatorIntl;
let translateService: TranslateService;
beforeEach(async(() => {
TestBed.configureTestingModule({
providers: [CustomMatPaginatorIntl],
imports: [
TranslateModule.forRoot({
compiler: { provide: TranslateCompiler, useClass: TranslateFakeCompiler },
}),
],
});
translateService = TestBed.get(TranslateService);
translateService.langs = ['fr', 'en'];
translateService.currentLang = 'fr';
translateService.setTranslation('en', { 'translation.paginator.items-per-page': 'Item per page' });
translateService.setTranslation('fr', { 'translation.paginator.items-per-page': '脡l茅ments par page' });
service = TestBed.get(CustomMatPaginatorIntl);
}));
it('should be created', () => {
expect(service).toBeTruthy();
});
it('should get the translation from TranslateService', () => {
expect(service.itemsPerPageLabel).toEqual('脡l茅ments par page');
expect(service.nextPageLabel).toEqual('translation.paginator.next-page');
expect(service.previousPageLabel).toEqual('translation.paginator.previous-page');
expect(service.ofLabel).toEqual('translation.paginator.of-label');
expect(service.getRangeLabel(1, 10, 20)).toEqual('11 - 20 translation.paginator.of-label 20');
});
describe('when language change', () => {
it('should changes the translation language', (done: any) => {
service.changes.subscribe(() => {
expect(service.itemsPerPageLabel).toEqual('Item per page');
done();
});
translateService.use('en');
});
});
});
@AnimaWolf in my case ngOnDestroy never get called, have you tested your implementation of OnDestroy?
Are they joking with this??? Refactor. Provide simple inputs. Please.
WoW- I just found one of the ugliest sides of angular material...
The subscription to this.translate.onLangChange
is unnecessary when you use this.translate.stream
instead of this.translate.get
, because it will execute everytime the language changes. So the following implementation is the same as @AnimaWolf's answer, but a little shorter:
`
import { MatPaginatorIntl } from "@angular/material";
import { TranslateService } from "@ngx-translate/core";
import { OnDestroy, Injectable } from "@angular/core";
import { takeUntil } from "rxjs/operators";
import { Subject } from "rxjs";
@Injectable()
export class MatPaginatorI18n extends MatPaginatorIntl implements OnDestroy {
private onDestroy$: Subject<boolean> = new Subject();
constructor(private readonly translate: TranslateService) {
super();
this.translate
.stream([
"MATERIAL.PAGINATOR.ITEMS_PER_PAGE",
"MATERIAL.PAGINATOR.NEXT_PAGE",
"MATERIAL.PAGINATOR.PREVIOUS_PAGE",
"MATERIAL.PAGINATOR.FIRST_PAGE",
"MATERIAL.PAGINATOR.LAST_PAGE"
])
.pipe(takeUntil(this.onDestroy$))
.subscribe(translations => {
this.itemsPerPageLabel = translations["MATERIAL.PAGINATOR.ITEMS_PER_PAGE"];
this.nextPageLabel = translations["MATERIAL.PAGINATOR.NEXT_PAGE"];
this.previousPageLabel = translations["MATERIAL.PAGINATOR.PREVIOUS_PAGE"];
this.firstPageLabel = translations["MATERIAL.PAGINATOR.FIRST_PAGE"];
this.lastPageLabel = translations["MATERIAL.PAGINATOR.LAST_PAGE"];
this.getRangeLabel = this.getRangeLabel.bind(this);
this.changes.next();
});
}
ngOnDestroy(): void {
this.onDestroy$.next();
this.onDestroy$.complete();
{
getRangeLabel = (page: number, pageSize: number, length: number): string => {
if (length === 0 || pageSize === 0) {
return this.translate.instant("MATERIAL.PAGINATOR.RANGE_LABEL_NO_ITEMS", { 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("MATERIAL.PAGINATOR.RANGE_LABEL", {
startIndex: startIndex + 1,
endIndex,
length
});
}
}
`
This issue has been automatically locked due to inactivity.
Please file a new issue if you are encountering a similar or related problem.
Read more about our automatic conversation locking policy.
_This action has been performed automatically by a bot._
Most helpful comment
@mhosman @rsaulo This is how I did it in
"@angular/material": "^5.0.3",
Create separate file e.g. custom-mat-paginator-int.ts:
Load and include it in providers in app.module.ts
import {CustomMatPaginatorIntl} from './shared/custom-mat-paginator-intl';