本記事は、
vscode-nls 2.0.2
とvscode-nls-dev 2.1.6
をベースに書かれた内容となります。
2020/1/13 現在、vscode-nls 4.1.1
とvscode-nls-dev 3.3.1
が最新となりますが、最新バージョンでは、nls.config(process.env.VSCODE_NLS_CONFIG);
の記述は機能しなくなっています。また、microsoft/vscode-nls と、それを利用したi18n-sample サンプルをベースにした本記事は、シンプルではないという指摘を頂いたり、使用すべきではないと注意喚起されている記事も見受けますので、vscode 拡張機能のローカライズに取り組む場合は、Visual Studio Code 拡張のローカライズ対応方法 を参考にして頂ければと思います。
Visual Studio Code 拡張機能のメッセージを言語設定に合わせてローカライズしてみる
昨年の Visual Studio Code Advent Calendar 2016 で VS Code 拡張機能のコマンドタイトル名をローカライズしてみる という記事を書いてみました。
この時は、vscode-nls モジュールの存在などは知っていたものの、どのように利用するかまでは理解できていなかった...
拡張機能のサンプル
VS Code の API を利用して拡張機能を作成するにあたり参考になるのが Microsoft/vscode-extension-samples で公開されるサンプルです。
この中に、拡張機能で利用するメッセージをローカライズするためのサンプル i18n-sample が含まれており、このサンプルの手法を利用することで、拡張機能のメッセージをローカライズすることができます。
これで、やっと理解できた。
vscode-extension-samples の clone
サンプルから、いくつかのファイルを拝借するので、まずは、Microsoft/vscode-extension-samples リポジトリを git clone し、手元に置いておきます:
$ git clone https://github.com/Microsoft/vscode-extension-samples.git
hello world を利用してメッセージをローカライズしてみる
今回も、下記で公開されている入門用 “Hello World” 拡張機能を利用してみたいと思います。
yo code を実行し、拡張機能の雛形を作成します。
ここでは、拡張機能の名前に hello-world
とつけてみます。
この拡張機能は、Hello World
コマンドを追加し、このコマンドを実行すると上部に "Hello World!" と表示して終了するだけの拡張機能です。
今回は、Hello Wolrd
コマンド及びその実行結果として表示される "Hello World!" を、ローカライズしてみるお話です。
Hello World
コマンド:
Hello World
コマンドの実行結果:
ローカライズに必要な要件
ローカライズを提供するためには、下記のような要件が必要になります。ここでは、日本語へのローカライズを前提としています。
-
言語を構成する (Configure Language)
で、”locale”:”ja”
を設定し、VS Code の表示言語を日本語に設定します - ローカライズに利用される全てのファイルは
i18n
フォルダの下に配置します - このフォルダ自体は、手作業で作成します。(vscode-nls-dev モジュールを使って Transifix プロジェクトから、ローカライズされたファイルを pull することもできるように作られているようですが、プロジェクトなどは一切関係ないため今回は利用しません)
-
i18n
フォルダの下には、ローカライズする言語を表すサブフォルダを配置します。フォルダ名は、ISO 639-3 の規約に従います。例えば、日本語の場合は、jpn
となります - 言語名フォルダの下に、拡張機能のソースコードの配置と同じディレクトリ構造 (例えば、out/) に倣って
<ファイル名>.i18n.json
ファイルを作成します。この json ファイルの中身は、ローカライズ対象となるテキストの”key”:”value”
のペアとなり、このファイルから該当するkey
のペアとなるvalue
すなわち、ローカライズされたテキストが表示に利用されます - 拡張機能のトップレベルに
package.nls.json
ファイルがある場合は、package.i18n.json
というファイル名を持つ、各言語用のパッケージを用意する必要があります。(日本語メッセージを作成する場合:i18n/jpn/package.i18n.json
)
package.nls.json
については、Visual Studio Code Advent Calendar 2016 5日目 - VS Code 拡張機能のコマンドタイトル名をローカライズしてみる を参照してください
この条件に従い、メッセージをローカライズして行きます。
npm package のインストール
yo code
で拡張機能の雛形を作成し、すぐに実行することはできますが、それだけではメッセージをローカライズすることができません。
まずは、ローカライズに必要な下記の npm パッケージを “Hello World” 拡張機能のローカルリポジトリにインストールします。
$ cd hello-world
$ npm -SD install gulp gulp-typescript del run-sequence vsce vscode-nls-dev
- vsce は、拡張機能をパッケージにしたり Marketplace へ公開するためなどに利用されます。
- vscode-nls-dev は、Javascript や Typescript から外部にある文字列を抽出することを目的としたモジュールです。
続いて、配布に必要な下記の npm パケージを “Hello World” 拡張機能のローカルリポジトリにインストールします。
$ npm -S install vscode-nls
- vscode-nls は、ローカライズとそれに利用するリソースを外部化するための npm モジュールです。主に VS Code 拡張機能のローカライズに利用されます。
hello-world/package.json の devDependencies
と dependencies
は下記のようになります。
"devDependencies": {
"@types/mocha": "^2.2.42",
"@types/node": "^7.0.43",
"del": "^3.0.0",
"gulp": "^3.9.1",
"gulp-typescript": "^3.2.3",
"run-sequence": "^2.2.0",
"typescript": "^2.6.1",
"vsce": "^1.35.0",
"vscode": "^1.1.6",
"vscode-nls-dev": "^2.1.6"
},
"dependencies": {
"vscode-nls": "^2.0.2"
}
ファイルの配置
続いてローカライズを行うために必要なファイルを配置します。
ローカライズに必要な要件にもありましたが、ローカライズされたメッセージを格納するファイルを作成し配置する必要があります。
- hello-world/i18/jpn/out ディレクトリを作成します。このディレクトリに、コード内のメッセージをローカライズするために必要な
extension.i18n.json
ファイルを配置します(作成は後ほど)。また、拡張機能パッケージのメッセージ(コマンド名や設定情報など)をローカライズに必要なpackage.i18n.json
ファイル(こちらは、i18/jpn/package.i18n.json として)を配置します(作成は後ほど) - i18n-sample/gulpfile.js を hello-world ディレクトリのトップレベルに配置します
最終的なファイルの配置は下記のようになります:
hello-world
|—i18n/
|——jpn/
|———package.i18n.json (作成は後ほど)
|———out/
|————extension.i18n.json (作成は後ほど)
|-gulpfile.js
試しに、gulp task を実行して見ます。
メッセージとしては、特に何もなく、各タスクが実行されている事だけがわかります。
$ gulp
[18:32:39] Using gulpfile ~/hello-world/gulpfile.js
[18:32:39] Starting 'default'...
[18:32:39] Starting 'build'...
[18:32:39] Starting 'clean'...
[18:32:39] Finished 'clean' after 14 ms
[18:32:39] Starting 'internal-nls-compile'...
[18:32:40] Finished 'internal-nls-compile' after 932 ms
[18:32:40] Starting 'add-i18n'...
[18:32:40] Finished 'add-i18n' after 4.89 ms
[18:32:40] Finished 'build' after 953 ms
[18:32:40] Finished 'default' after 954 ms
この時、hello-world/out ディレクトリに変化があります。
明らかにローカライズに関連しそうなファイルができています。
hello-world
|—out
|——test/
|——extension.js
|——extension.js.map
|——extension.nls.ja.json // このファイルが作成される
|——extension.nls.json // このファイルが作成される
中身は、それぞれ下記のようになりますが、ローカライズに必要なファイルが作成されていないため、空に等しい内容となっています。
extension.nls.ja.json:
[]
extension.nls.json:
{
"messages": [],
"keys": []
}
でも、なんとなくローカライズの仕組みが見えてきました。
ローカライズ手順
準備が整ったので、'Hello World!' 拡張機能をローカライズして見ます。
まずは、extension.ts
を編集して行きます。extension.ts
には、コマンドを実行すると表示されるメッセージが実装されており、その部分を変更して行きます。
extension.ts に下記を追加
vscode-nls
モジュールを import し、nls.config() を localize として割り当てる記述を extension.ts に追加します。
import * as nls from 'vscode-nls';
const localize = nls.config(process.env.VSCODE_NLS_CONFIG)();
コメントを除いたコードは、下記のようになります。
'use strict';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls'; // 追加された行
const localize = nls.config(process.env.VSCODE_NLS_CONFIG)(); // 追加された行
export function activate(context: vscode.ExtensionContext) {
console.log('Congratulations, your extension "hello-world" is now active!');
let disposable = vscode.commands.registerCommand('extension.sayHello', () => {
vscode.window.showInformationMessage('Hello World!');
});
context.subscriptions.push(disposable);
}
export function deactivate() {
}
"Hello World" 拡張機能で表示されるメッセージ 'Hello World!' を出力する処理は下記のように実装されています。
vscode.window.showInformationMessage('Hello World!');
この 'Hello World!' の部分をローカライズします。
ソースコード上のこの部分を、'こんにちは世界!' に書き換えたら終了です。いや、それだとダメですね。
ローカライズしたいメッセージを localize() で囲う
まずは、ローカライズしたいメッセージを localize()
で囲います。localize()
は、key
と message
の 2 つの引数が必要になります。
key
には、message
を判別するための固有の文字列を。message
には、デフォルトで表示する文字列を割り当てます。
下記のように変更します:
vscode.window.showInformationMessage(localize('helloWorld.text', 'Hello World!'));
ここでは、helloWorld.text
という key
が設定されているならば、その値を表示し、設定されていなければ、'Hello World!' を表示するという意味になります。
書いただけでは何も起きません。
試しに実行して見ましょう。ここで一つ気をつけなければいけない事は、ローカライズを反映するには、通常の F5 キーを押したデバッグのトランスパイルではなく、都度、変更を反映させるために、必ず gulp build
を実行しなければならない点です。(本項の説明が、i18n-sample/gulpfile.js
の利用を想定しているため、このような手順になっています)
統合ターミナルで gulp build
を実行後、out/ ディレクトリ配下が再生成されます。その後、F5 キー
でデバッグ実行する事が可能です。
また、gulp build
実行時に、extension.js が書き換えられます。この時に、gulp から vscode-nls-dev
モジュールが呼び出されます。
localize() で囲んだ部分が下記のように変化している事がわかります:
out/extension.js:
vscode.window.showInformationMessage(localize(0, null));
どのようにローカライズを行なっているか?
-
ソースコード中の
vscode-nls
モジュールを利用した記述を対象に、vscode-nls-dev
モジュールを使って書き換えを行います。書き換えは、トランスパイルで生成された JavaScript ファイルを、gulp を使って、後から書き換えます -
例えば、下記のように記述された呼び出しは、
localize(‘helloWorld.text’, ‘Hello World!’)
このように書き換えられます:
localize(0、null)
最初のパラメータ (この例では 0) は、メッセージファイル内の
key
をあらわし、key
に設定されたvalue
に置き換えられます。localize()
が複数存在する場合は、最初のパラメータとなる数字が増えて行きます。 -
i18n
フォルダに配置されたファイルの内容は、”key”:”value”
のペアからなる配列に変換され利用されます
ローカライズファイルの配置
作成は後ほど
と説明していた 2 つのファイルを作成します。
hello-world
|—i18n/
|——jpn/
|———package.i18n.json (作成は後ほど)
|———out/
|————extension.i18n.json (作成は後ほど)
|-gulpfile.js
まずは、下記の内容で hello-world/i18n/jpn/out/extension.i18n.json
を作成します。
{
"helloWorld.text": "こんにちは世界!"
}
こレは、言語設定が、ja
の場合、jpn
ディレクトリ配下の extension.i18n.json
ファイルに設定されたhelloWorld.text
の値となる、こんにちは世界!
を表示することを想定しています。
実行してみる
ここまでくれば、もう少し。
あとは、ターミナルから gulp build
を実行します。
$ gulp build
そして、F5 キー
でデバッグを実行し、コマンドパレットから Hello World
コマンドを実行します:
表示できました。
gulp build
で生成される、out/extension.nls.ja.json
と out/extension.nls.json
ファイルの中身を見てみると下記のようになっています:
extension.nls.ja.json:
[
"こんにちは世界!"
]
extension.nls.json:
{
"messages": [
"Hello World!"
],
"keys": [
"helloWorld.text"
]
}
ちなみに、英語ロケールで実行すると、下記のように英語のメッセージが表示されます。
このように、ソースコード中のメッセージをローカライズして行きます。
ローカライズしたいメッセージを localize() で囲い、ローカライズしたいメッセージを判別するための固有の文字列を割り当てた key
を定義し、その値に表示する文字列を割り当てます。
コマンドのローカライズ
続いて、コマンドのローカライズを行います。
コマンドおよびコマンド名の定義は、package.json
内の "contributes"
で定義される、"commands"
で行われます。
'Hello World' 拡張機能は、下記のようになっています。これは、コマンド名として "Hello World"
を割り当て、これが選択された場合に実行されるコマンドは extension.sayHello
である事がわかります。
"contributes": {
"commands": [
{
"command": "extension.sayHello",
"title": "Hello World"
}
]
},
ここでも、テキストを直接書き換えれば対応完了ですね。
基本的な対応については、VS Code 拡張機能のコマンドタイトル名をローカライズしてみるの手順と大きく変わりませんので、パクって行きます。
まず、package.json の変更:
まずは、コマンドの title
を %extension.sayHello.title%
のように %
で囲まれた文字列に置き換えます。これがキーになります
"contributes": {
"commands": [
{
"command": "extension.sayHello",
"title": "%extension.sayHello.title%"
}
]
},
続いて packaje.nls.json の作成
package.json で設定したローカライズ用のキーにマッピングするための値を、下記のように追加します。
このファイルを用意することで、VS Code の言語が英語(en)に設定されているか、英語以外のローカライズ情報が用意されていない場合にこのファイルに記載されている情報が利用されることになります
{
"extension.sayHello.title": "Hello World"
}
最後にローカライズ用の値が格納された i18n/jpn/packahe.i18n.json を作成
ここだけが、前回の記事と異なる部分です。
ローカライズされたメッセージを格納するファイルは、packahe.i18n.json
として、i18n/jpn に配置し、言語名を含んだ package.nls.ja.json
ファイルを作成する必要はありません。
gulp build
の実行により、packahe.i18n.json
ファイルから package.nls.ja.json
ファイルを自動生成してくれます。
下記の例では、"extension.sayHello.title": に、"こんにちは世界!ってやってみよー" を指定することで、package.json に定義した "%extension.sayHello.title%" が置きかわるという仕組みです。
{
"extension.sayHello.title": "こんにちは世界!ってやってみよー"
}
gulp build を実行
最後に gulp build
を実行し、F5 キー
でデバッグを実行してみましょう。
下記のように、コマンドが "こんにちは世界!ってやってみよー" となります。
また、packaje.nls.json
でデフォルトとなるコマンド名を定義しているため、ローカライズされたコマンドの下に、"Hello World" とも表示されています。
そのため、コマンドパレットでは、日本語化されたコマンド名と英語のコマンド名のどちらでも検索して実行する事が可能です。
パッケージ化してみる
せっかくなので、作成した 'Hello World' 拡張機能を VS Code へインストールできるように、拡張機能パッケージ化してみましょう。
パッケージ化も、ローカライズのために利用している gulpfile.js を使って行う事が可能です。下記のように実行してください:
$ gulp package
拡張機能をシングルファイルにパッケージ化した hello-world-0.0.1.vsix
ファイルが生成されます。
拡張機能: VSIX からのインストール
コマンドを実行し、hello-world-0.0.1.vsix
を読み込むことで VS Code へ拡張機能をインストールする事ができます。
ちなみに、README.md が、ちゃんと編集されているかをチェックしており、そのままだとパッケージ化がエラーとなります。急いでいる場合は、冒頭にある下記の一文を削除すれば回避できます。
This is the README for your extension "hello-world". After writing up a brief description, we recommend including the following sections.