如何将ng-template中定义的翻译内容作为组件属性传入?
解决方案:将翻译文本作为组件属性传入
你现在的核心困扰是没法把模板里的翻译文本提取出来作为组件的label属性值,对吧?因为ngTemplateOutlet是用来渲染DOM节点的,而组件属性需要的是字符串值,两者没法直接打通。这里有几种实用的解决思路,你可以根据自己的场景选择:
方案1:直接在组件类中用$localize定义翻译映射(最推荐)
Angular的$localize支持直接在代码中调用翻译标记,你可以在组件类里创建一个路由到翻译文本的映射对象,然后在模板中直接绑定:
组件类代码
import { Component } from '@angular/core'; import { $localize } from '@angular/localize'; @Component({ // ... 你的组件元数据 }) export class YourComponent { menuRoutes = ['/foo', '/bar']; // 定义路由对应的翻译文本,和模板里的i18n标记对应 routeLabels: Record<string, string> = { '/foo': $localize`:@@foo:Foo`, '/bar': $localize`:@@bar:Bar` }; }
模板代码
<ng-container *ngFor="let menuRoute of menuRoutes"> <some-component [route]="menuRoute" [label]="routeLabels[menuRoute]" /> </ng-container>
这种方式最直接,翻译逻辑和组件绑定逻辑分离,维护起来也很方便。
方案2:使用自定义管道复用翻译逻辑
如果需要在多个组件中复用路由到翻译的转换逻辑,可以创建一个自定义管道:
管道代码
import { Pipe, PipeTransform } from '@angular/core'; import { $localize } from '@angular/localize'; @Pipe({ name: 'routeLabel' }) export class RouteLabelPipe implements PipeTransform { transform(route: string): string { switch(route) { case '/foo': return $localize`:@@foo:Foo`; case '/bar': return $localize`:@@bar:Bar`; default: return route; // 兜底返回原路由,避免空值 } } }
记得在你的模块中声明这个管道。
模板代码
<ng-container *ngFor="let menuRoute of menuRoutes"> <some-component [route]="menuRoute" [label]="menuRoute | routeLabel" /> </ng-container>
方案3:从模板中提取翻译文本(适合复杂翻译内容)
如果你的翻译内容包含复杂的HTML结构,必须用模板来定义,那可以通过代码渲染模板并提取文本内容:
组件类代码
import { Component, ViewChild, TemplateRef, ViewContainerRef } from '@angular/core'; @Component({ // ... 你的组件元数据 }) export class YourComponent { @ViewChild('translations') translationsTemplate!: TemplateRef<any>; menuRoutes = ['/foo', '/bar']; routeLabels: Record<string, string> = {}; constructor(private vcRef: ViewContainerRef) {} ngOnInit() { this.menuRoutes.forEach(route => { // 创建嵌入式视图 const embeddedView = this.translationsTemplate.createEmbeddedView({ $implicit: route }); // 创建临时元素挂载视图,用于提取文本 const tempElement = document.createElement('div'); embeddedView.rootNodes.forEach(node => tempElement.appendChild(node)); // 提取并保存翻译文本 this.routeLabels[route] = tempElement.textContent?.trim() || ''; // 清理临时元素和视图,避免内存泄漏 tempElement.remove(); embeddedView.destroy(); }); } }
模板代码
保持你原来的translations模板不变,循环时绑定提取好的翻译文本:
<ng-container *ngFor="let menuRoute of menuRoutes"> <some-component [route]="menuRoute" [label]="routeLabels[menuRoute]" /> </ng-container> <ng-template #translations let-menuRoute> <ng-container [ngSwitch]="menuRoute"> <!-- 注意这里你之前写错了,应该是menuRoute而非menuRoutes --> <ng-container *ngSwitchCase="'/foo'"> <span i18n="@@foo">Foo</span> </ng-container> <ng-container *ngSwitchCase="'/bar'"> <span i18n="@@bar">Bar</span> </ng-container> </ng-container> </ng-template>
注意:这个方案比较繁琐,只推荐给翻译内容包含复杂DOM结构的场景,纯文本翻译用前两种方案更高效。
内容的提问来源于stack exchange,提问作者Remi




