Closed simon11196 closed 6 years ago
So far we assumed that the translated messages don't change dynamically. They're not rendered as templates and don't get their own change detectors.
The specific use case might be served better from an "no records" template.
Do you have other use cases where you'd like to change the translated messages on the fly? You might still be able to do that by using message service, but changes won't show up until the component is recreated.
@tsvetomir Actually we do have this use case, as we allow the user to switch the displayed language at 'run-time' (w/o having to reload the whole page).
We have implemented this with the help of ngx-translate.
The reason why we are using the MessageService
instead of e.g. the no records
template, is to reduce the redundancy in the markup. This way we do not have to add the same template to every grid.
Right now we are facing two problems with the interaction between kendo-angular-l10n
and ngx-translate
.
Right now we do have to use the instant
function to retrieve the translations (string
) synchronous in the MessageService
implementation.
But this does have the drawback, that the translations are sometime not yet loaded (especially if the connection to the server is somewhat bad).
That's why ngx-translate
suggest to use the get
function instead, which returns an Observable<string>
that resolves when the translations are loaded.
import { MessageService } from "@progress/kendo-angular-l10n";
import { TranslateService } from "@ngx-translate/core";
export class TranslateKendoService extends MessageService {
constructor(private service: TranslateService)
{
super();
}
get(key: string) {
//return this.service.get(key); // Returns Observable<string> so it does not work
return this.service.instant(key);
}
}
When the language is changed by the user, ngx-translate
will request the needed translations if they are not available yet.
But we do not have an option to trigger a refresh/redraw of the translations provided by the MessageService
implementation.
Right now we are experimenting with removing the kendoUI-component from the DOM via *ngIf
for the blink of a second, but this does feel far from optimal.
Implement a EventEmitter
/Subject
which triggers the kendoUI-component to reload the translations via MessageService.get
.
export class TranslateKendoService extends MessageService {
constructor(private service: TranslateService)
{
super();
this.service.onLangChange.subscribe(() => this.onLanguageChange());
}
get(key: string) {
return this.service.instant(key);
}
private onLanguageChange() {
// Call the 'Redraw/Refresh EventEmitter' here
}
}
Allow MessageService.get
to (optional) return Observable<string>
instead of string
and watch the changes to reflect it in the components.
export class TranslateKendoService extends MessageService {
constructor(private service: TranslateService)
{
super();
}
get(key: string) {
this.service.get(key); //returns Observable<string>
}
}
Looking forward to hear your opinion on this. Also please let me know if there are any questions and/or something is unclear.
Thank you for the clarification.
We experimented with something similar to the first idea, but we couldn't find an acceptable way to re-render a component based on an external trigger. The "Angular way" to address this would be to render the strings in the component template, thereby creating change detectors for them. This is not how it currently works mostly due to the interaction with the message service.
The second approach is very risky in terms of performance. The number of observables will scale linearly with the number of messages and component instances on the page. The design document for the Angular i18n framework touches on this concern:
Performance considerations: There are extra bindings introduced. There's typically an extra network requests before content can be shown or all the translations for all the languages are served on initial load. There's support to mitigate this but it requires a good amount of extra code.
We tend to agree with the Angular team here. Translating each and every text in the application over the network, with dynamic bindings is very likely to slow it down.
And finally, a question. Wouldn't you use the router to assign different URLs for the different languages? If so, you can inject a different message service for each route.
Thank you for the feedback.
I absolutely agree with you and the Angular team here. If, the way we are currently going, is not done in a proper way it will definitely slow down the application.
In our case we are making heavy use of TypeScript
's inheritance and Angular Provider
's to adapt parts of 3rd party libraries based on our (kind of exotic) use-case.
And finally, a question. Wouldn't you use the router to assign different URLs for the different languages? If so, you can inject a different message service for each route.
This was initially discussed when we started, but we were not able to find a acceptable way to do this, if there is more than one language to be displayed on a page.
For components (like the grid for example) we are always showing the 'primary' language.
And due to that there was the idea to load translations needed for kendoUI components via the MessageService
and Resolve
, but we did not have the time to look into that yet.
You can still have different translations on the page by wrapping the Grid in a custom component. This wrapper can inject a message service configured for the required language.
Something in the line of this plunkr. Here LocalizedComponent will recreate its child component every time the language is changed.
@Component({
selector: 'my-app',
template: `
<button (click)="changeLanguage()">Change Language</button>
<localized-component [language]="lang" [contentType]="childType">
</localized-component>
`
})
export class AppComponent {
public lang: string = 'en';
public childType = MyGridComponent;
public changeLanguage() {
this.lang = this.lang === 'en' ? 'es' : 'en';
}
}
Not ideal, but I'm not aware of any other means to force Angular to re-instantiate a component.
Edit (13/03/2018): Updated plunkr to current version
Thank you for the sample. That is actually really close to what we are doing right now.
What is the official solution of this closed issue?
We're considering our options to make dynamic localization possible. One option is to have a change notification emitted from the message service, as @balazs-zsoldos suggested in the support system.
There are other considerations, such as RTL and Locale information that must be kept in sync with the language change. We'll post updates as our research progresses.
Good news, everyone! The latest develop build adds a notify method for changing translations dynamically. This is currently supported in the Grid package and the rest of the components will follow soon.
Please note that this is a breaking change for the components due to updated peer dependencies. The major version has been incremented and they now require @progress/kendo-angular-l10n
v1.1.0 or later. The Grid also requires @progress/kendo-angular-buttons
v4.0.0 or later.
Beers go to @rkonstantinov, @rusev and @danielkaradachki :beers:
👍
Released officially in @progress/kendo-angular-grid
v3.0.0
@tsvetomir Is there a list somewhere of what is supported or not for changing translations dynamically ?
I searched on your website and didn't found anything about it.
We noticed on our end that the EditorComponent wouldn't refresh the languages when we call the notify
method.. 😐
Will we have some more surprises like this ?
Thanks
Hi @MLefebvreICO, that sounds like a bug with the Editor component. Would you mind filing a separate issue so we don't spam the participants in that fairly old thread? Thanks!
Plunkr:
http://plnkr.co/edit/OYQzlEYW0fqUYUdhF1DQ?p=preview
Message in grid doesn't update on input change (button click).