网站搜索

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 —— 那么 && 后面的代码将不会执行 —— 因此不会出现索引错误