🦾

Vue I18n で翻訳がなくても表示したかったのでできるようにした

2022/08/25に公開

多言語化、してますか?
翻訳用のメソッドかませるだけでしょ、余裕余裕と思って心を殺して数百ファイルの翻訳対応を始めたんですが、Vue I18n でちょっと困った話です。

遭遇した事態

<p>{{ $t('こんにちは、{userName}さん!', { userName: 'Zenn太郎' }) }}</p>

Vue I18n を使って文字列を翻訳するとき、翻訳したいテキストをそのままキーとして使用する場合は上記のような書き方をするんですが、例えば辞書ファイルに以下のような記述があれば…

{
  "こんにちは、{userName}さん!": "Hello, {userName}!"
}

実際の表示は、翻訳後テキストの {userName} が展開されてこのようになります。

<p>Hello, Zenn太郎!</p>

ところが、辞書ファイルに該当する翻訳がない場合はそのまま、このように表示されてしまいます。

<p>こんにちは、{userName}さん!</p>

そう、翻訳がない場合はキーをそのまま出力するんですが、キーに含まれる変数は展開されないのです。

辛いので対応した

諸般の事情により後追いで辞書ファイルを作成する運びのため、これだと困ります。
こんなんみんな困るやろと思ってちょっと探したんですが、意外とみんな困ってないのか、いい感じのソリューションは見つかりませんでした(あったら教えて下さい)。
見つからなかったので、翻訳用のプラグインを書きました(本題)。

import VueI18n from 'vue-i18n';

Vue.use(VueI18n);

Vue.use({
  install(Vue) {
    /**
     * 翻訳が設定されていない場合、キーに含まれる変数を展開してそのまま返却する
     *
     * @param {string} keypath
     * @param {object} values
     * @returns {string}
     */
    Vue.prototype.$tv = function tv(keypath, values) {
      if (!this.$te(keypath) && values) {
        // $te は翻訳があれば true、なければ false
        Object.keys(values).forEach((key) => {
          keypath = keypath.replaceAll(`{${key}}`, values[key]);
        });

        return keypath;
      }

      return this.$t(keypath, values);
    };
  },
});

単純にキーの中に引数で渡されたオブジェクトのキー(変数名)があるかを見て、あったら置換するというシンプルなやつです。
これを使うと、翻訳がない状態でこのように書いても…

<p>{{ $tv('こんにちは、{userName}さん!', { userName: 'Zenn太郎' }) }}</p>

こうなります

<p>こんにちは、Zenn太郎さん!</p>

やったね。

というわけで、大した話ではないのですが、zenn のアカウントを作る口実としてネタにした話でした 🙏

Discussion