あけおめ一発目です. フロントエンドテックリードやってるみゅーとんです.
年末年始はひたすら Unity と Blender で遊んでました.
弊プロジェクトのフロントエンドではもともと vue-i18n を導入しており, 後に多言語対応をサポートできるようにしていました.
これを, サポートできるように見直そうとしたところだったのですが, 課題が多く見つかり, 書き直すことになりました. その際に見通しのよい書き方に直せたので, これを共有します.
TL;DR
- 文言を引き当てるキーには, 表示する文言を設定すること
- なるべく 1文まとめて文言を作ること
- コーディング時に, そこに何が書いてあるかわかりやすくなった
前提
- vue-i18n, nuxt-i18n の使い方は解説しません.
- 同様の仕組みであれば真似できる話です.
背景
元々以下のように単語ごとに翻訳し, 文字列結合するようなロジックになっていました.
(極端な例なので, 実際はここまで酷くはないです)
// 言語リソース { "label": { "this_month": "今月", "today": "本日", "more": "あと", "times": "回" } }
<template> <p> <template v-if="remainingType === 'thisMonth'"> <!-- 今月あと N 回 --> {{ $t('label.this_month') }} {{ $t('label.more') }} {{ remain }} {{ $t('label.times') }} </template> <template v-else-if="remainingType === 'today'"> <!-- 本日あと N 回 --> {{ $t('label.today') }} {{ $t('label.more') }} {{ remain }} {{ $t('label.times') }} </template> <template v-else> <!-- あと N 回 --> {{ $t('label.more') }} {{ remain }} {{ $t('label.times') }} </template> </p> </template>
同じ文言で再利用したい気持ちはわかるのですが, これは翻訳が考慮されていません.
- 今月あと N 回
- 本日あと N 回
- あと N 回
この 3文をとりあえず適当に DeepL などで翻訳かけてみるとこうなります.
英語:
- N more times this month
- N more times today
- N times left
中国語 (簡体字):
- 本月 N 多次
- 今天 N 多次
- N 多次
韓国語:
- 이번 달에 N 번 더
- 오늘 N 번 더
- 앞으로 N 번 더
私は言語に詳しくないので, これが正しいかどうかはイマイチわかりませんが,
少なくとも今のロジックでこれに対応できないことはわかります.
上記, や他言語も考慮すると, 以下のように組まれるべきでした.
// 言語リソース { "label": { "n_more_times_this_month": "今月あと{remain}回", "n_more_times_today": "本日あと{remain}回", "n_times_left": "あと{remain}回" } }
<template> <p> <template v-if="remainingType === 'thisMonth'"> <!-- 今月あと N 回 --> {{ $t('label.n_more_times_this_month', { remain }) }} </template> <template v-else-if="remainingType === 'today'"> <!-- 本日あと N 回 --> {{ $t('label.n_more_times_today', { remain }) }} </template> <template v-else> <!-- あと N 回 --> {{ $t('label.n_times_left', { remain }) }} </template> </p> </template>
本題
さて, 多言語周りを見直す際に色々調べて回ってたところ, 以下のソースコードに行き着きました.
https://github.com/Tokyo-Metro-Gov/covid19
なんでここに行き着いたんだろう・・・? 全く関係ないですね, 経緯も覚えてません.
ただ, ここにある locale のコードが最も重要でした.
https://github.com/Tokyo-Metro-Gov/covid19/blob/development/assets/locales/ja.json
一部抜粋
{ "詳細を見る(東京都福祉保健局)": "詳細を見る(東京都福祉保健局)", "相談方法は、症状や状況別で3つに分かれます": "相談方法は、症状や状況別で3つに分かれます", "かかりつけ医がいて症状のある方": "かかりつけ医がいて症状のある方", "かかりつけ医がいない症状のある方": "かかりつけ医がいない症状のある方", ...
{ "詳細を見る(東京都福祉保健局)": "Details:See the website (of Tokyo Metropolitan Government Bureau of Social Welfare and Public Health)", "相談方法は、症状や状況別で3つに分かれます": "Which of the following is your situation?", "かかりつけ医がいて症状のある方": "You are experiencing symptoms and have a primary care doctor", "かかりつけ医がいない症状のある方": "You are experiencing symptoms and do not have a primary care doctor", ...
あっ・・わかりやすい!!!
json には key に日本語を設定しちゃって良いのでした. 完全に失念していました.
つまり, 問題としていたコードは, この方式を真似すると以下のようになります.
// 言語リソース { "label": { "今月あと{remain}回": "今月あと{remain}回", "本日あと{remain}回": "本日あと{remain}回", "あと{remain}回": "あと{remain}回" } }
<template> <p> <template v-if="remainingType === 'thisMonth'"> {{ $t('今月あと{remain}回', { remain }) }} </template> <template v-else-if="remainingType === 'today'"> {{ $t('本日あと{remain}回', { remain }) }} </template> <template v-else> {{ $t('あと{remain}回', { remain }) }} </template> </p> </template>
可読性が格段に上がりました. 表示文言がキーになっているので, コメントで補足しなくても何が書いてあるか推測しやすいです.
まとめ
背景で説明した通り, 弊プロジェクトでは多言語対応の処理が翻訳困難なロジックになっており, 全体的に改修が必須になっていました.
改修をどうせするなら, この方式を導入しても工数的にはなんら差はなく, 方向性だけ決めて現在はスムーズに変更ができている状況です.
json のキーに日本語を設定できる. 仕様としては知ってましたが, こういうときに使えるとは思っておらず, 目からウロコでした.
public repository を眺めてるだけで, こういう改善のアイデアがいっぱい拾えるのいいですね.
どんどんコードを良くしていきたいです.
おわり
株式会社hacomonoでは一緒に働く仲間を募集しています!
採用情報や採用ウィッシュリストも是非ご覧ください!