In my Angular application, I display a sentence like:
[UserX] commented [item] from [UserY] at [PlaceZ]
This sentence (currently hardcoded in English) needs to be translated but the tricky thing is that [UserX], [UserY], [item] and [PlaceZ] are rendered through angular components, even inside ng-container switches.
This is because these elements are clickable and have their own avatar and are used all over the application for consistency.
It roughly looks like:
<ng-container *ngTemplateOutlet='user;context:{id: "X"}'></ng-container>
commented
<ng-container *ngTemplateOutlet='impactedEntity'></ng-container>
of
<ng-container *ngTemplateOutlet='user;context:{id: "Y"}'></ng-container>
at
<location id="Z"></location>
<ng-template #user let-id="id">
<!-- display "you" if same user, etc -->
...
</ng-template>
<ng-template #impactedEntity>
<ng-container [ngSwitch]='type'>
...
</ng-template>
My question is: what is a simple solution to translate this sentence (considering the order of placeholders can change completely from one language to another), and inject the "rendered" elements?
I've already looked at some common options for injecting HTML inside i18n:
[innerHtml] to have the html rendered. Not applicable because it's not "just" <a href but more complex logic with ng-container.@ViewChild() to get the rendered HTML from each element I need to inject, and use it as simple string for interpolation. It looks like the most realistic approach, but I was wondering if there was not something simpler.Thanks for any feedback!
Olivier
Answering my own question as I think I found a solution that fits quite well.
After more thinking, here's what I came up with:
"MY_KEY": "{userX} commented {entity} of {userY} at {place}"const label = translateService.instant(MY_KEY, {
userX: "|USERX|",
userY: "|USERY|",
entity: "|ENTITY|",
place: "|PLACE|"
})
const elements = label.split('|')
<ng-container *ngFor='let part of elements'>
<ng-container *ngSwitchCase='USERX'>
<ng-container *ngTemplateOutlet='user;context:{id: "X"}'></ng-container>
</ng-container>
<ng-container *ngSwitchCase='USERY'>
<ng-container *ngTemplateOutlet='user;context:{id: "Y"}'></ng-container>
</ng-container>
<ng-container *ngSwitchCase='ENTITY'>
<ng-container *ngTemplateOutlet='impactedEntity'></ng-container>
</ng-container>
<ng-container *ngSwitchCase='PLACE'>
<location></location>
</ng-container>
<ng-container *ngSwitchDefault>
<!-- Here simply dump the translated words -->
{{ part }}
</ng-container>
</ng-container>
</ng-container>
In the end, it's a little hacky (not too much), but:
I'm happy!