typescript - 保护 Angular 5 应用程序,防止模板中数组未定义的插值
我想为 Angular 5 应用添加多语言功能,但我不确定我是否选择了正确的方法。
我在一个服务中定义了这两种类型:
type appMsgTuple = {
[key : string] : string | string[]
}
type appMsgs = {
es : appMsgTuple,
en : appMsgTuple
}
所以,我定义变量来保存应用程序不同组件的翻译,例如:
export var MSG_USER : appMsgs = {
"es" : {
"MSG_USER_1" : "Por favor, introduzca sus datos de acceso",
"MSG_USER_BUTTONS" : [ "ACCEDER", "Síganos" ]
},
"en" : {
"MSG_USER_1" : "Please, type your login details",
"MSG_USER_BUTTONS": [ "LOGIN", "Follow us"]
}
}
在每个组件中,我从服务中导入相应的字符串:
// USER COMPONENT
[ ... ]
import { MSG_USER } from 'app/services/languages.service';
public MSGS : any = {}; // We'll use this to 'point' to the right language in MSG_USER (see below)
为了使其更简洁,我将变量MSGS分配给正确的语言(由用户选择),如下所示:
// USER COMPONENT
[ ... ]
ngOnInit() {
this.MSGS = MSG_USER[selUsr.selectedLanguage];
[ ... ]
}
最后,在模板中,我使用 MSGS 变量来显示不同的字符串,方式如下:
<h5 class="fwcBlue">{{ MSGS['MSG_USER_1'] }}</h5>
<button label="{{ MSGS['MSG_USER_BUTTONS'][1] }}" [disabled]="!formModel.valid || formModel.pristine" (click)="onLogin()">
</button>
这可以使用,但有一个大问题:如果我拼错任何一个键(例如,我输入 MSGS['MSG_USER_BUTTTTTTTONS'][1]),应用程序会崩溃,因为它不存在,且 Javascript 无法访问未定义的第 1 个位置。
我如何才能避免这种潜在风险?提前谢谢您,
答案#1
Angular 模板支持为此目的使用安全导航操作符(Elvis 操作符)。
它不支持括号表示法,因此在这种情况下需要采取保护措施:
<button
*ngIf="MSGS['MSG_USER_BUTTONS']"
label="{{ MSGS['MSG_USER_BUTTONS'][1] }}"
[disabled]="!formModel.valid || formModel.pristine" (click)="onLogin()"
>
</button>
正因为这个原因,元组并不是这个用途的好选择。键值对就不会有这样的麻烦:
"es" : {
"MSG_USER_1" : "Por favor, introduzca sus datos de acceso",
"MSG_USER_BUTTONS" : { ACCEDER: Síganos }
}
提供一个不需要直接访问消息对象的抽象是有益的——一个服务和管道,会返回所使用语言和指定路径的值,比如 {{ 'MSG_USER_BUTTONS.LOGIN' | translate }},这通常就是这样实现的。已有几个采用这种方法的国际化解决方案,例如 ngx-translate。
答案#2
你可以像下面这样写:
MSGS['MSG_USER_BUTTTTTTTONS'] && MSGS['MSG_USER_BUTTTTTTTONS'][1]
如果 MSGS['MSG_USER_BUTTTTTTTONS'] 是 null 或 undefined —— 那么 && 后面的代码将不会执行 —— 因此不会出现索引错误
