VSCode插件-i18n
# 0.前言
本篇博客记录的是VSCode插件的国际化(i18n)功能。
由于国际化在 VSCode 插件官网仅给了一个案例 i18n-sample (opens new window),除此以外就无额外说明,因此本篇博客还是具有一定的意义的。
# 1.国际化能力。
国际化共分为三个部分:
- 组件国际化:页面随
Display Language的变化而改变。 VSCode界面(指令)国际化。extension插件国际化,如 弹窗提示内容、title、command等信息都是由编写在代码中的,更改语言后也需要进行变化。
由于能力有限,目前仅实现后两者的能力,而组件国际化暂未涉及。
# 2.工具说明
在国际化改造能力中,需要用到以下插件:
gulp:作用同webpack,通过在gulpfile文件中编写task,实现对代码的处理。vscode-nls:插件国际化的生产依赖。vscode-nls-dev:devDependencies开发依赖,主要用于自动生成package.nls.json、package.nls.[language].json等文件的自动构建。
# 3. VSCode界面(指令)国际化
VSCode 界面的国际化功能的实现非常简单,但由于官方通过 gulp 脚本自动生成 package.nls.[language].json 文件,导致刚开始看的时候没有方向。
以官方 i18n-sample案例为例,实现 command 的国际化
修改
package.json将需要国际化的部分用%variable%方式包裹。"contributes": { "commands": [ { "command": "extension.sayHello", "title": "%extension.sayHello.title%" }, { "command": "extension.sayBye", "title": "%extension.sayBye.title%" } ] },1
2
3
4
5
6
7
8
9
10
11
12以上变量读取
pacakgae.nls.json中的变量{ "extension.sayHello.title": "sayHello", "extension.sayBye.title": "sayBye" }1
2
3
4再创建目标语言的
package.nls.[language].json文件,如zh-cn{ "extension.sayHello.title": "你好", "extension.sayBye.title": "再见" }1
2
3
4
# 4. 插件国际化
这部分修改的是在编写插件代码中,需要替换掉的一些提示信息或标识信息,如:
webview的titleshowInformationMessage(message)中的弹窗提示信息等。
而这部分实现,主要依赖于 vscode-nls 这一生产 依赖实现(在package.json中请严格区分生成和开发依赖,否则插件无法生效)。
# 4.1.vscode-nls的基础使用
从
vscode-nls中导出nlsconst nls = require("vscode-nls"); // commonJS 写法1生成
localize函数// 方式1:其中对 nls.config 的设置没有任何说明。 const localize = nls.config({ messageFormat: nls.MessageFormat.file })(); // 方式2: const localize = nls.loadMessageBundle()1
2
3
4
5传入
key和text,message则会根据不同的语言环境对文字进行切换。const message = localize('sayHello.text', 'Hello');1如果不是用
vscode-nls-dev+gulp的话,则需要在out目录下手动创建以下文件:extension.nls.json:[ "Hello" ]1
2
3extension.nls.ja.map:[ "こんにちは" ]1
2
3extension.nls.metadata.json{ "messages": [ "Hello" ], "keys": [ "sayHello.text" ], "filePath": "extension" }1
2
3
4
5
6
7
8
9
# 4.2 i18n-example 案例说明
上述情况只是对extension文件中存在国际化改造需求时,当案例中存在导入文件的国际化修改需求时,如sayByeCommand。
import * as nls from 'vscode-nls';
import { sayByeCommand } from './command/sayBye';
export function activate(context: vscode.ExtensionContext) {
// 4.1 案例中的一般情况
const helloCmd = vscode.commands.registerCommand('extension.sayHello', () => {
const message = localize('sayHello.text', 'Hello');
vscode.window.showInformationMessage(message);
});
// 4.2 当 command 是由外部导入的情况
const byeCmd = vscode.commands.registerCommand('extension.sayBye', sayByeCommand);
context.subscriptions.push(helloCmd, byeCmd);
}
2
3
4
5
6
7
8
9
10
11
12
13
对于外部导入的文件(sayBye.js),也需要构造nls.zh-cn以及nls.metadata等文件,构建后的代码如下图所示:
# 5.[高级] 使用 gulp+vscode-nls-dev自动创建文件
# 5.1 gulp 的基础使用
此部分内容,已在《VSCode插件-国际化改造之gulp》 (opens new window) gulp 简易教程。
# 5.2 gulpfile 脚本解读
在 i18n-example 案例中 gulp 脚本主要使用到了如下工具:
gulp-sourcemaps:用于生成sourcemapsourcemaps.init()sourcemaps.write(,options)del:用于删除数据与
cleanTask绑定在一起,del(['out/**', 'package.nls.*.json', 'i18n-sample*.vsix']);event-stream: 事件流使用:
es.through()在node中数据以流的形式传递。vscode-nls-dev:国际化函数。nls.rewriteLocalizeCalls:生成了extension.nls.json以及元数据extension.nls.metadata.jsonnls.createAdditionalLanguageFiles:就是基于extension.nls.json生成extension.nls.ja.jsontypescript+gulp-typescript(ts):将代码转化为js代码- 读配置文件并创建
ts工程:tsProject = ts.createProject("./tsconfig.json") - 转化为
js代码:tsProject.src("文件").pipe(tsProject()).js
- 读配置文件并创建
# 5.3 Task
由于 gulpfile 中的task 任务很多,核心的就buildTask、package、clean
buildTask:同步执行三个任务:cleanTask, internalNlsCompileTask, addI18nTask
清空任务,清空
out所有文件,package.nls.*.json(日文),.vsix文件。internalNlsCompileTask:国际化编译任务。该函数接受
true、false布尔值类型,如果是true,则在管道中顺序执行nls.rewrietLocalizeCalls()以及nls.createAdditionalLanguageFile,可以自动创建第4章节所需文件。代码角度:由此也可以看出
es.though()的目标就是为了管道流继续往下流,并将上述结果分别写入sourceMap文件中,并且输出在outDest。addI18nTask:也是国际化内容,自动创建根目录的package.nls.[language].json文件。读取
package.nls.json。读取
i18n/jpn文件夹下的package.i18n.json文件const languages = [{ folderName: 'zh-cn', id: 'zh-cn' }]; const addI18nTask = function() { return gulp.src(['package.nls.json']) .pipe(nls.createAdditionalLanguageFiles(languages, 'i18n'))// 读取 i18n/zh-cn 下的 package.i18n.json 文件 .pipe(gulp.dest('.')); };1
2
3
4
5
6
# BUG记录:升级插件时遇到的一个坑
由于插件国际化按照i18n-example教程中,只能通过打包后才能进行测试。
在原有的 package.json 中存在以下脚本:
"scripts": {
"vscode:prepublish": "yarn run compile",
"compile": "tsc -p ./",
},
2
3
4
即,存在一个生命周期函数:在执行vsce package时触发,会预先进行 prepublish 触发。
具体实现的目的:将 ts 文件进行打包操作。
由于在插件国际化改造过程中,已经通过gulp-typescript对ts代码进行转化了,并且在此基础上还增加了国际化功能,此生命周期函数会直接覆盖掉之前的操作,从而始终无法看到国际化效果。
# 调试技巧记录:如何调试 gulp 文件?
在缺少官方文档的情况下,如何调试 vscode-nls-dev 各API功能?
vscode-nls-dev 的 API :
nls.createAdditionalLanguageFiles()nls.rewriteLocalizeCalls()
在以下脚本中,通过添加 gulp.dest() 代码可以将各个环节的流结果输出到指定目录中。
const doCompile = function (buildNls) {
var r = tsProject.src()
.pipe(sourcemaps.init())
// +.pipe(gulp.dest("./folder1"))
.pipe(tsProject()).js
// +.pipe(gulp.dest("./folder2"))
.pipe(buildNls ? nls.rewriteLocalizeCalls() : es.through())
// +.pipe(gulp.dest("./folder3"))
.pipe(buildNls ? nls.createAdditionalLanguageFiles(languages, 'i18n', 'out') : es.through());
// +.pipe(gulp.dest("./folder4"))
}
2
3
4
5
6
7
8
9
10
11
如通过打印 nls.createAdditionalLanguageFile 的输出结果可以发现,就是根据 packag.nls.json 生成了 package.nls.[language].json 文件。