Configuration Translation(構成の翻訳)モジュールの挙動をできるだけきちんと理解しようと思って調べたことをまとめてみた。Drupal Advent Calendar 2023に寄稿する記事である。
入り口のドキュメントはTranslating configurationとなる。ここには
Configuration translation relies on having a correct configuration schema to provide translations. So, every module must provide a correct schema.
構成の翻訳は、正しいコンフィギュレーション・スキーマを必要とする。故に、各モジュールは正しいスキーマを定義しなければならない。
と書かれている。結論から言えば、Configuration schemaを見て、翻訳可能な要素を特定してその翻訳の値をデータベースに保管し、描画時に表示言語に基づいて表示を上書きする機能を持っているという事だ。
まずはConfigurationとは何かが問題となる。Overview of Configuration (vs. other types of information)を読むと、Drupal8で6種類のデータ型に整理されていることがわかる。
Content
Information meant to be displayed on your site, and edited by users: article, basic page, images, files, etc.
Session
Information about individual users' interactions with the site, such as their current selection for a Views exposed filter. This is ephemeral and personalized to a single user.
Information that can change frequently and/or without user intervention. Examples: the time when Cron was last run, whether node access permissions need rebuilding, etc.
Information about your site that is not content and changes infrequently, such as the name of your site, the content types and views you have defined, etc.
Information about your site that is also stored elsewhere. Caches exist only to speed up data retrieval. They never store canonical data.
Read-only information for your site hardcoded within settings.php.
4番目に書かれているConfiguration(構成)がデータベースに納められていて、構成変更が可能になっている。説明を訳すと、
サイトの名前、定義したコンテンツタイプやビューなど、コンテンツではなく、頻繁に変更されないサイトに関する情報。
となる。読み替えると、頻繁に変更するような要素ではないが、変更可能な構成情報ということになる。「サイトの名前」が最初に出てくるが、これは下図のenに相当する部分となる。
管理画面で環境設定>システム>サイトの基本設定を確認するとサイト名が変更可能なのがわかる。サイト名やスローガンはしばしば変えるものではないが、サイト立ち上げ時には暫定のサイト名を与えておいて、後で変えられるのは便利である。
サイトビルダーの観点では、ここで値を変えればサイト名を変えられることを理解していれば十分なのだが、こういった単純なConfigurationならともかくViewsのようなConfigurationは非常に複雑なので、そもそもConfiguration(Configuration entity)って何かを理解したいというのが本稿の関心事である。
多言語観点では、複数言語が定義され、構成の翻訳モジュールが有効になっていると、このSite nameは翻訳が可能になる。ConfigurationとConfiguration Translationはどう関わっているのかも気になるところである。
構成定義は関数のパラメータのようなものと考えれば良く、パラメータには型がある。型定義について書かれているのが、Configuration schema/metadataである。実際のCoreのスキーマ定義はsystem.schema.ymlで見ることができる。site情報スキーマは以下の通り。環境設定>システム>サイトの基本設定には出てこない項目は、uuid、admin_compact_modeなどがある。
system.site:
type: config_object
label: 'Site information'
mapping:
uuid:
type: uuid
label: 'Site UUID'
constraints:
Uuid: []
NotNull: []
name:
type: label
label: 'Site name'
mail:
type: email
label: 'Email address'
slogan:
type: label
label: 'Slogan'
page:
type: mapping
label: 'Pages'
mapping:
403:
type: path
label: 'Default 403 (access denied) page'
404:
type: path
label: 'Default 404 (not found) page'
front:
type: path
label: 'Default front page'
admin_compact_mode:
type: boolean
label: 'Compact mode'
weight_select_max:
type: integer
label: 'Weight element maximum value'
default_langcode:
type: langcode
label: 'Site default language code'
mail_notification:
type: string
label: 'Notification email address'
環境設定>開発>同期の単一の構成項目のエクスポートで対応する構成の値を見ると、
_core:
default_config_hash: VDJxTZtQR21qB4lvOq8zszJZLvLKrSPQpdn2E3T71Ww
langcode: en
uuid: cca5b951-9877-4cdb-9c06-eb259a9f1bfd
name: en
mail: XXX@ulslab.com
slogan: ''
page:
403: ''
404: ''
front: /node
admin_compact_mode: false
weight_select_max: 100
default_langcode: en
のようになっている。さらにmysqlnのデータベースを見ると、configテーブルにその値が納められているのがわかる(多少加工してある)。
MariaDB [en]> select collection, name,data from config where name="system.site";
| collection | name | data| | system.site | a:10:{s:5:"_core";a:1:
{s:19:"default_config_hash";
s:43:"VDJxTZtQR21qB4lvOq8zszJZLvLKrSPQpdn2E3T71Ww";}
s:8:"langcode";s:2:"en";s:4:"uuid";
s:36:"cca5b951-9877-4cdb-9c06-eb259a9f1bfd";
s:4:"name";s:2:"en";s:4:"mail";s:18:"XXX@ulslab.com";s:6:"slogan";s:0:"";s:4:"page";
a:3:{i:403;s:0:"";i:404;s:0:"";s:5:"front";s:5:"/node";}
s:18:"admin_compact_mode";b:0;
s:17:"weight_select_max";i:100;
s:16:"default_langcode";s:2:"en";} |
| language.ja | system.site | a:1:{s:4:"name";s:6:"英語";} 2 rows in set (0.001 sec)
スキーマに基づいて値が保存されているのが想像できる。
やや踏み込んでしまうが、この例のサイトでは、英語がデフォルト言語で、日本が足してあり、サイト名は日本語では「英語」と翻訳したので、s:4:"name";s:2:"en"とs:4:"name";s:6:"英語"が出てきている。表示言語を日本語にすると、language.jaが優先されて、サイト名が「英語」に翻訳できることが想像できる。
日本語をデフォルト言語にして英語を足すと、language.enのレコードができるが、ここにデフォルト値が設定されるとは限らないのがつらいところである。私は、多言語サイトを立ち上げる時は、この問題を嫌って、英語をデフォルト言語にして日本語を足す形にしているが、そうしたらそうしたで、Viewsの名前などが英語表示になってしまったり別の悩ましさが出る。プログラマはもちろんサイトビルダーも中の人だから、ある程度は英語に向かい合う必要があることを痛感させられる。
ちなみに、サイト基本情報の翻訳ではSite nameとSloganしか対象になっていない。
なぜその2項目だけが対象になっているかと言えば、それはスキーマでそれらの項目がlabelで定義されているからである。
name:
type: label
label: 'Site name'…
slogan:
type: label
label: 'Slogan'
Configuration schema/metadataには以下のように書かれている。
translatable: Whether the defined type is translatable; Note: not all types can be made translatable. To make a type: string translatable, change it to type: label instead of adding translatable: true, or it will not show up in translation forms.
もう少し細かく見るためには、core.data_types.schema.ymlを見る必要がある。このファイルで、「translatable: true」は4つ(5回)しかない。label、text、date_format、text_formatである。実質的にはlabelとtextが対象と考えればよいだろう。ここまで見てくれば、Configurationと翻訳の関係がどうなっているのかがわかる。
なお、Configuration Translationが見ているConfigurationはドキュメントにある28種類とはやや異なっている。
これらが全てのConfigurationをカバーしているわけではないが、翻訳対象となるものは網羅しているのだろう。
Configuration translationは機械的にスキーマからlabelやtextなどの翻訳可能要素を抽出して提示するので、それが一般ユーザーがサイトに触れた時に出てくるラベルやメッセージなのか、管理者の編集画面で現れるラベルやヘルプなどのテキストなのかは区別されない。例えば、コンテンツタイプの記事(Article)の場合は、以下のように一般ユーザーの目に触れる要素は全く含まれない。
このため、Configuration Translationを管理画面の翻訳と誤解してしまうケースはあるが、サイト名やフィールドラベルなどは一般ユーザーの目に触れる重要なインタフェース要素となる。
網羅的に扱うには、Translation Management Toolを使うと良い。プロジェクトページでは
Nodes
Entities
I18n Strings (Menu, Terms etc.)
が対象とあるが、実際にはConfigurationはConfiguration Entityなので翻訳対象になっている。プラグインをインストールすれば機械翻訳もかけられるので、いちいちConfiguration Translationの機能を利用して翻訳していくよりは、一斉にかけてしまって承認していくほうがずっと楽になる。
改めて、ドキュメントやデータをさらってみると、意外とConfiguration translationの機能は単純である。
結論を繰り返せば、Configuration schemaを見て、翻訳可能な要素を特定してその翻訳の値をデータベースに保管し、描画時に表示言語に基づいて表示を上書きする(レンダリング要素を生成する)比較的単純な機能を持っているという事だ。逆に言えば「すべてのモジュールは正しいスキーマを提供しなければなりません」は非常に重い。翻訳可能要素に正しいデータ型を与えなければ機能しないのである。モジュールを書く時に多言語対応に失敗してしまうと面倒なことになる。
Drupalの多言語対応機能は良く考えられていると思う。一方、メッセージなどをどこまでConfiguration側に置き、どこまでをt()で書くかは悩ましい。個人的にはConfigurationに寄せてほしい気がしている。コード量は増えてしまうだろうが柔軟性は増すだろう。パフォーマンスには影響が出るかも知れない。エキスパートの人達のコメントを求めたいところである。