VonaJS: I18n如何支持Swagger多语言

VonaJS提供的I18n支持模块化体系。每个业务模块都可以单独提供自己的 I18n 语言资源。我们先了解I18n的一般用法,然后再看看如何支持Swagger多语言

初始化代码骨架

我们先在模块demo-student中初始化I18n的代码骨架

1. Cli命令

bash 复制代码
$ vona :init:locale demo-student

2. 菜单命令

bash 复制代码
右键菜单 - [模块路径]: `Vona Init/Locale`

定义语言资源

以模块demo-student为例,定义模块的语言资源:

  • 英文

src/module/demo-student/src/config/locale/en-us.ts

diff 复制代码
export default {
+ StudentName: 'Student Name',
};
  • 中文

src/module/demo-student/src/config/locale/zh-cn.ts

diff 复制代码
export default {
+ StudentName: '学生名称',
};

使用语言资源

可以通过 Scope 实例提供的locale对象获取模块的语言资源,支持类型化提示

typescript 复制代码
class ControllerStudent {
  @Web.get('test')
  test() {
    // use current locale
    const message1 = this.scope.locale.StudentName();
    // use locale en-us
    const message2 = this.scope.locale.StudentName.locale('en-us');
    // use locale zh-cn
    const message3 = this.scope.locale.StudentName.locale('zh-cn');
    console.log(message1, message2, message3);
  }
}  

跨模块使用语言资源

typescript 复制代码
class ControllerStudent {
  @Web.get('test')
  test() {
    // use current locale
    const message1 = this.$scope.demoStudent.locale.StudentName();
    // use locale en-us
    const message2 = this.$scope.demoStudent.locale.StudentName.locale('en-us');
    // use locale zh-cn
    const message3 = this.$scope.demoStudent.locale.StudentName.locale('zh-cn');
    console.log(message1, message2, message3);
  }
}  

覆盖语言资源

可以使用项目级别的语言资源覆盖模块级别的语言资源

  • 英文

src/backend/config/locale/en-us.ts

diff 复制代码
export default {
  modules: {
+   'demo-student': {
+     StudentName: 'Student Name!',
+   },
  },
};
  • 中文

src/backend/config/locale/zh-cn.ts

diff 复制代码
export default {
  modules: {
+   'demo-student': {
+     StudentName: '学生名称!',
+   },
  },
};

当前locale

1. 获取当前locale

typescript 复制代码
const locale = this.ctx.locale;

2. 设置当前locale

typescript 复制代码
this.ctx.locale = 'en-us';

3. 获取缺省locale

typescript 复制代码
const localeDefault = this.$scope.i18n.config.defaultLocale;

获取当前locale的规则

当用户访问后端 API 时,后端会自动根据规则获取当前 locale

1. 模块配置

I18n 是由模块 a-i18n 提供的核心能力,可以在 App config 中修改模块的配置:

src/backend/config/config/config.ts

typescript 复制代码
// modules
config.modules = {
  'a-i18n': {
    defaultLocale: 'en-us',
    queryField: 'x-vona-locale',
    headerField: 'x-vona-locale',
    cookieField: 'locale',
  },
};
名称 说明
defaultLocale Default locale
queryField 从request query中获取当前locale,query key默认为x-vona-locale
headerField 从request header中获取当前locale,header key默认为x-vona-locale
cookieField 从request cookie中获取当前locale,cookie key默认为locale

2. 规则次序

系统按以下次序,依次判断当前 locale

queryField > headerField > cookieField > Header: Accept-Language > defaultLocale

添加新语言

VonaJS 默认提供了两个语言:en-uszh-cn。下面演示如何添加新语言zh-tw

1. 添加类型定义

采用接口合并机制添加新语言的类型定义

在 VSCode 编辑器中,输入代码片段recordlocale,自动生成代码骨架:

typescript 复制代码
declare module 'vona' {
  export interface ILocaleRecord {
    : never;
  }
}

调整代码,然后添加zh-tw

diff 复制代码
declare module 'vona' {
  export interface ILocaleRecord {
+   'zh-tw': never;
  }
}

2. 添加语言资源

新建语言文件zh-tw.ts,然后添加语言资源

src/module/demo-student/src/config/locale/zh-tw.ts

typescript 复制代码
export default {
  StudentName: '學生名稱',
};

复数

1. 定义语言资源

src/module/demo-student/src/config/locale/en-us.ts

diff 复制代码
export default {
+ TestApples_: '%d apples',
+ TestApples_0: 'no apples',
+ TestApples_1: 'one apple',
};

src/module/demo-student/src/config/locale/zh-cn.ts

diff 复制代码
export default {
+ TestApples_: '%d个苹果',
+ TestApples_0: '没有苹果',
};

2. 使用语言资源

typescript 复制代码
this.ctx.locale = 'en-us';
const apple0 = this.scope.locale.TestApples_(0);
const apple1 = this.scope.locale.TestApples_(1);
const apple2 = this.scope.locale.TestApples_(2);
console.log(`${apple0}, ${apple1}, ${apple2}`);

控制台输出如下:

bash 复制代码
no apples, one apple, 2 apples
  • TestApples_: 缺省语言资源。语言资源添加后缀_,可以提示开发者该语言资源需要传入参数
  • TestApples_{n}: 可以针对任何具体的n提供独立的语言资源。系统在进行语言翻译时,如果找不到具体n的语言资源,就使用缺省语言资源TestApples_

复数: 多参数

如果语言资源支持多参数,那么可以明确指定哪个参数支持复数

1. 定义语言资源

src/module/demo-student/src/config/locale/en-us.ts

diff 复制代码
export default {
+ TestNameApples_: '%s has %d apples',
+ TestNameApples_0_1: '%s has no apples',
+ TestNameApples_1_1: '%s has one apple',
};

src/module/demo-student/src/config/locale/zh-cn.ts

diff 复制代码
export default {
+ TestNameApples_: '%s有%d个苹果',
+ TestNameApples_0_1: '%s没有苹果',
};

2. 使用语言资源

typescript 复制代码
this.ctx.locale = 'en-us';
const apple0 = this.scope.locale.TestNameApples_('Tom', 0);
const apple1 = this.scope.locale.TestNameApples_('Tom', 1);
const apple2 = this.scope.locale.TestNameApples_('Tom', 2);
console.log(`${apple0}, ${apple1}, ${apple2}`);

控制台输出如下:

bash 复制代码
Tom has no apples, Tom has one apple, Tom has 2 apples
  • TestNameApples_: 缺省语言资源。语言资源添加后缀_,可以提示开发者该语言资源需要传入参数
  • TestNameApples_{n}_{ordinal}: ordinal代表参数序数

Swagger/Openapi

VonaJS 提供了一组工具函数,为 Swagger/Openapi 实现 I18n 国际化

比如,为EntityStudent的字段name提供国际化的title信息

1. $localeScope

在设置字段 title 信息时,要使用语言资源FullKey。在实际生成 Swagger/Openapi 元数据时,系统会自动将语言资源FullKey翻译为指定的语言

diff 复制代码
+ import { $localeScope } from 'vona';

class EntityStudent {
+ @Api.field(v.title($localeScope('demo-student', 'Name')))
  name: string;
}
  • v.title: 设置 title 信息
  • $localeScope: 传入模块名称语言资源Key,从而生成语言资源FullKey: demo-student::Name

2. $locale

VonaJS 还提供了一个简化的工具函数$locale

diff 复制代码
+ import { $locale } from '../.metadata/index.ts';

class EntityStudent {
+ @Api.field(v.title($locale('Name')))
  name: string;
}
  • $locale: 传入语言资源Key,从而生成语言资源FullKey: demo-student::Name
    • 每个模块都提供了 <math xmlns="http://www.w3.org/1998/Math/MathML"> l o c a l e 函数,因此,使用本模块的 locale 函数,因此,使用本模块的 </math>locale函数,因此,使用本模块的locale 函数就可以取得模块名称

资源

相关推荐
None3211 小时前
【NestJs】基于Redlock装饰器分布式锁设计与实现
后端·node.js
时光不负努力6 小时前
编程常用模式集合
前端·javascript·typescript
时光不负努力6 小时前
ts+vue3开发规范
vue.js·typescript
Gogo11216 小时前
构建高性能 Node.js 集中式日志体系 (下篇):Pino + PM2 + OpenSearch 代码落地实战
node.js
小岛前端6 小时前
Node.js 宣布重大调整,运行十年的规则要改了!
前端·node.js
时光不负努力6 小时前
typescript常用的dom 元素类型
前端·typescript
时光不负努力6 小时前
TS 常用工具类型
前端·javascript·typescript
前端付豪7 小时前
Nest 项目小实践之前端注册登陆
前端·node.js·nestjs
codingWhat1 天前
整理「祖传」代码,就是在开发脚手架?
前端·javascript·node.js
Wect1 天前
LeetCode 210. 课程表 II 题解:Kahn算法+DFS 双解法精讲
前端·算法·typescript