Closed duncte123 closed 6 months ago
@duncte123 If I understand correctly there are two issues here.
About the time element, with this library you can simply do this (since the time will be formatted as a string):
<span [params]="{ startTime: today | l10nDate:locale.language:{ timeStyle: 'short' }}" l10nTranslate>startsIn</span>
where today
is a date, and json is: { "startsIn": "Begins {{startTime}}" }
About the routerLink
, as part of a translated text, it's an old problem in Angular, because it's not simply a string. You can find other issues in this repository where the problem is addressed, such as these: https://github.com/robisim74/angular-l10n/issues/128, https://github.com/robisim74/angular-l10n/issues/206
This scenario is not supported by this library, and I don't think it will be: hydration enabled during SSR does not support DOM manipulation.
Personally, I remain of this opinion: https://github.com/robisim74/angular-l10n/issues/206#issuecomment-424981972
Greetings
Thank you for your reply, unfortunately this library does not render the time using the semantic element as is preferred in my application hence me bringing it up.
The stackblitz example shows me this
@duncte123 I get it.
But if you have this need (for links, time element or other html tags) why don't you develop a custom slot component like the one in vue-i18n?
For example something like this:
@Component({
selector: 'l10n',
template: `
<span #contentWrapper>
<ng-content></ng-content>
</span>
`,
standalone: true,
imports: [
CommonModule,
L10nTranslationModule
],
// host: { ngSkipHydration: 'true' } if you hydration enabled
})
export class L10nComponent {
@ViewChild('contentWrapper') contentWrapper: ElementRef;
@Input() key: string;
private translation = inject(L10nTranslationService);
private renderer = inject(Renderer2);
private destroy = new Subject<boolean>();
private elementWrapper: HTMLElement;
private element: HTMLElement;
ngAfterViewInit() {
if (!this.element && !this.elementWrapper) {
this.elementWrapper = this.contentWrapper.nativeElement;
this.element = this.contentWrapper.nativeElement.childNodes[0];
this.translation.onChange().pipe(takeUntil(this.destroy)).subscribe({
next: () => {
this.replace();
}
});
}
}
replace() {
const val = this.translation.translate(this.key, { inner: this.element.outerHTML });
this.renderer.setProperty(this.elementWrapper, 'innerHTML', val);
}
ngOnDestroy(): void {
this.destroy.next(true);
}
}
Usage:
<l10n key="startsIn">
<time [dateTime]="today">{{ today | l10nDate:locale.language:{ timeStyle: 'short' } }}</time>
</l10n>
<l10n key="something.base">
<a routerLink="/about" l10nTranslate>something.linkText</a>
</l10n>
and the json with a fixed inner
param:
{
"startsIn": "Begins {{inner}}",
"something": {
"base" : "click this cool {{inner}}",
"linkText": "Hello world"
}
}
Just keep in mind that you are manipulating the DOM to do this, and you may have problems if you use SSR with hydration enabled.
I hadn't actually thought about slot components, thanks for the recommendation :)
Is your feature request related to a problem? Please describe. Inside of my app I have components that deal with the localisation of time, for these components I want to use the time element. But that is not all. Some if my strings need links in them and some of these links are required to be routerLinks.
I am currently migrating away from
ngx-translate
as it is in maintenance mode and does not support this feature.A great example of what I would like already exists in the real world as vue-i18n has this feature. (see additional context)
Describe the solution you'd like An awesome way to go about this is to just allow a template to be inserted as a parameter like this:
Outputting:
Describe alternatives you've considered I have tried to use arrays for specific keys, but that solution does not work as some languages may have a different sentence structure source.
Comming form ngx-translate I have looked at this proposal, it works, but isn't perfect and has a lot of issues when switching languages causing duplicated elements.
I have looked for a lot of libs but none seem to offer this feature.
Additional context With the following translation keys
Vue allows us to do the following (
$formatTime
is a custom function defined by me)This will render as the following
With the HTML rendering as
Another example of this would be
With the HTML rendering as: