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
的title
showInformationMessage(message)
中的弹窗提示信息等。
而这部分实现,主要依赖于 vscode-nls
这一生产 依赖实现(在package.json
中请严格区分生成和开发依赖,否则插件无法生效)。
# 4.1.vscode-nls的基础使用
从
vscode-nls
中导出nls
const 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
:用于生成sourcemap
sourcemaps.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.json
nls.createAdditionalLanguageFiles
:就是基于extension.nls.json
生成extension.nls.ja.json
typescript
+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
文件。