embryo

エンジニアの備忘録

言語ファイルの命名規則と管理方法

今日は言語ファイルの管理方法及び命名規則に関してです。技術書典5でデザインシステムの本を書く予定なんですが、その中でも言語は重要な要素なので一度整理しておこうと思います。

なぜ言語ファイルを管理するのか

実際のところ本当に多言語対応するつもりなのであれば言語ファイルの管理だけでは厳しいところが多いです。言語以外の差異も数多くある上に、UI上で日本語と同じように再現することも簡単ではないからです。それでも言語ファイルを管理したい理由は2点あって

  • 用語の更新を簡単にしたいから
  • 表記揺れを無くしたいから

です。つまるところUIを再利用可能なコンポーネントの組み合わせで作りたいという欲求と変わりません。

どのように管理すべきか

色々なアプローチがあるのですが、現状私が確認してるもので大きい区分で分けると

  • コード中にある文字列を抽出して言語ファイルとして出力する
  • 別途言語用のファイルを定義してコード中から呼び出す

の2点があります。前者は何も考えずに渡されたデザインに記述された文字列を記述できるが、表記ゆれは起こりやすい。後者は文字列を別途定義する分コストが高いが設計次第ではサービス内で使用している用語を整理するソースになり得る。といったメリット・デメリットがありそうです。

ちなみに再利用性を考えない設計にした場合には、前者のようなアプローチが良いかなと思います。 どちらの方針を取るかは言語管理の目的を用語の整理とするか、多言語化のための単なる定数とするかで異なります。

どのように設計するか

キーに関してルールがない場合、再現なくネストしていくため、現状私の開発時は <コンテキスト>.<書式>.<適当なキー> としています。

コンテキスト

コンテキストはスコープを表します。今開発しているプロダクトでは 共通部分のcommon, ドメイン知識を持つdomain, 表示領域を表すmodule で分けています。

  • common : ドメインに依存しないような用語、例えば「メールアドレス」などもそれに当たります。
  • domain : ドメインに依存するような用語、例えば「ユーザー」、「ユーザーの氏名」などです。
  • module : 表示領域、Viewに依存します。例えば「ユーザー一覧」などがこれにあたります。

コンテキストを用意している理由は適用の範囲を表すことはもちろん、文脈を意識するようにするためです。同じ単語でも文脈が異なれば別の意味を持っている可能性があります。

書式(タイプ)

以下のようなタイプを定義しています。

  • label
  • button
  • message
  • placeholder

書式をなぜ用意しているかというと、言語の検索をする際に必要な情報になるからです。また書式のバリデーションの用途も兼ねています。 例えば button の場合、あとで見返したときに一律して「〜する」という書式になっているのかなどを確認するためです。

コンテキスト間の依存関係

f:id:sue71:20180924204601p:plain

言語間の依存関係は図のようになるはずで、例えばユーザーデータが次のように表される場合

interface User {
    id: string;
    name: string;
    email: string;
}

このメールアドレスのキー管理は

const user = {
    "domain.user.label.email": "ユーザーのメールアドレス"
};

としたいのですが、「メールアドレス」の表記がコンテキストによって「Eメール」、「メール」と表記が異なるのはサービスとしてまずいので

const common = {
    "common.label.email": "メールアドレス"
};

const user = {
    "domain.user.label.email": "ユーザーの{common.label.email}"
};

の関係であるべきです(参照の形式は適当です)。同様にユーザー一覧用の言語ファイルは

const userList = {
    "module.userList.label.user_email": "{domain.user.label.email}",
    "module.userList.button.ok": "{common.label.ok}", 
    "module.userList.message.hint": "ユーザー一覧でユーザーを追加できます"
};

となり、commonmoduleから参照可能なものは参照し、固有のものは個別に定義します。

これはモジュールなのかドメインなのか

最早言語ファイルに限った話ではないのですが抽象的なレイヤーが挟まるとどれに入れるべきか迷うことがあるはずです。 例えば「ユーザーを追加する」リンクやボタンの文言はモジュール、ドメインどちらに入れるのか、などです。

正直なところドメインオブジェクトがきちんと分析されているか左右されるのですが、ドメインオブジェクトの振る舞いとしてドメイン配下に定義するのがいいと思っています。 しかしそれをチーム全体に浸透させるのは難易度が高いのも事実なので迷うくらいなら機能の用語としてしまってモジュールに定義するのが良いかと思います。

まとめ

現状実践している言語ファイル管理の方法について簡単にまとめました。言語ファイルを管理する目的によって管理方法は様々なので、まずは目的を整理する必要がありそうです。