Node core APIのi18nを活用しよう
用途
オフラインの時や共用サーバーで勝手にnpm install iconv-lite
などができない時、エクセルをワンライナーでサクッと処理したい時など
必要条件
- v8.3.0以上
- util.TextDecoderを使うため
- icudtXX[bl].datファイルが手元のマシンにある
- XXはICUのバージョン、bかlかはendian
- OSXなら
/usr/share/icu/
にプリインストールされてる(特定バージョンのみ)
確認方法
$node # REPLに入る
> process.version
'v8.3.0' # Node.jsのバージョンが満たしているか確認
> process.versions.icu
'59.1' # 必要なICUのバージョンを確認
上記の場合、icudt59b.datまたはicudt59l.datが必要
自分のMBPの場合、/usr/share/icu/icudt62l.dat
があり、
手元のNode.jsのversionはv10.15.3なので利用可能(下表)
対応表(2019-03, v8.x/v10.x/v11.xのみ)1
Node.js ver | ICU ver |
---|---|
v11.1.0 ~ | 63 |
v11.0.0, v10.7.0 ~ | 62 |
v10.0.0 ~ | 61 |
v8.10.0 ~ | 60 |
v8.3.0 ~ | 59 |
ICU dataが手元にない場合
いずれもオフラインは厳しい
-
npm i full-icu
/yarn add full-icu
- Node.js verに対応するICU verをビルドしてくれる
-
node --icu-data-dir=./node_modules/full-icu
で実行可
-
nodejs/nodeをfull ICUでbuild
- ICUデータはオンラインからダウンロードしている
- ICUのユーザーガイドを参考にbuildする
- etc...
やり方
ex, euc-jp.txtというeuc-jpエンコードされたファイルを読み込みUTF8で出力
no_npm.js
const {TextDecoder} = require('util');
const {readFileSync} = require('fs');
const d = new TextDecoder('euc-jp');
const s = d.decode(readFileSync(0)); // fd=0: 標準入力
console.log(s);
$cat ./euc-jp.txt
�ۤ�
$cat ./euc-jp.txt | node --icu-data-dir=/usr/share/icu/ no_npm.js
ほげ
解説
- encodingオプションを指定せず生のbufferで読み込む
- ここで'euc-jp'と指定できれば楽なのだが、TextDecoderでしかi18n対応がされておらず、encodingに指定できる値はENUM値で決まってしまっている
- ex, readFileでは第二引数のオプションで指定しなければencodeのデフォルトはnull
- cf, Buffer.from()の第二引数のencodeのデフォルトは'utf-8'
- TextDecoderでencodingオプションを指定する
- 'shift_jis'は'sjis'でも良い。下記公式docを参照
- https://nodejs.org/dist/latest-v10.x/docs/api/util.html#util_encodings_requiring_full_icu_data
-
--icu-data-dir
でicudtXX[bl].datがあるディレクトリを指定して実行する- これが指定できないとTextDecoderはデフォルトでは
utf-8
かutf-16le
しかサポートしていないのでできない
- これが指定できないとTextDecoderはデフォルトでは
できないこと
上記でUTF-8への変換はできたが、それをeuc-jpでencodeすることはできない。
同様にjsのstring(utf-16エンコードされるらしい)をeuc-jpで吐き出すことも自前で変換表を作らないと難しい。
Transcode(require('buffer').transcode()
)でできないかと期待したけど、指定可能なencodeは決まっていた。
https://github.com/nodejs/node/blob/master/src/node_i18n.cc
Appendix
Node verとICU verの対応の調べ方
$git clone git@github.com:nodejs/node.git
$cd node
$git log -p deps/icu-small/README-SMALL-ICU.txt
# 変更差分からICU verが更新(ex, commit messageに`bump`を含む、など)されたcommit番号をコピーし、下記でその番号を含むtagを検索
$git tag -l --contain 538acead6670d711ddb71c0b852089b792c996e3
v11.0.0
v11.1.0
v11.10.0
v11.10.1
v11.11.0
v11.12.0
v11.2.0
v11.3.0
v11.4.0
v11.5.0
v11.6.0
v11.7.0
v11.8.0
v11.9.0
# ただしこれだけだとmasterブランチ経由で変更されたものしか取得できない
# 例えばv8系の変遷を正しく知るには、v8系の最新のtagで調査する必要がある
$git checkout -b v8.15.1 refs/tags/v8.15.1
-
最新情報はAppendixを参考に調査ください ↩