Drupal は多言語対応 CMS の一つです。つまり、URL・ユーザーアカウント・ドメインなど、様々な条件をトリガーに、Web ページ単位もしくはフィールド単位で翻訳することができます。公式サイトでも説明されているように、必要なモジュールをインストールし (有効にし)、言語設定から対応させたい言語を有効にすれば、その言語向けのコンテンツを作成できるようになります。
しかしそれだけだと、PHP などで動的に生成されたページに対応できません。そのため、動的生成に関連した一部の言語向けに、Drupalの翻訳システムを利用するための関数が提供されています。
Translation API overview | Translation API (Code text) | Drupal Wiki guide on Drupal.org
この記事によると、PHP 言語の場合、Drupal に組み込みの t() 関数を使用することで翻訳を行えます。また、 JavaScript においても同様に、Drupal.t()
メソッドが利用可能です。ただ、このDrupal.t()
メソッドが曲者だったので、使い方のコツについてまとめました。
そもそも、Drupal.t()
はどのように「翻訳」しているのでしょうか。
「DurpalサーバーにJavaScriptがHTTPリクエストを送っている?」
否。それだとawait
などで待たないと描画されませんし、そんな記述をせずとも動作します。つまり、Drupal で当該 JavaScript を含むWebページを表示する際は、クライアントサイドで翻訳作業を行っているわけです。
「あれ、特別なコードを書いた覚えはないんだけど?」
ごもっとも。先ほども書いたように、ドキュメントを読んだ限り、次のような単純なコードで動作します。
Drupal.t('Hello, world!');
しかし、次のようなコードは思ったように動作しません。
const a = 'Hello, world!';
Drupal.t(a);
しかししかし、次のようなコードだと正常に動作します。1行目のような、「一見すると無駄なコード片」の有無により、同じコード (Drupal.t(a);
) の可否が決まってしまうのです。
Drupal.t('Hello, world!'); // !?
const a = 'Hello, world!';
Drupal.t(a);
この奇妙な挙動の正体は、先程挙げた公式ドキュメントをじっくり読むと見えてきます。
There are exceptions where you could call t($variable):
- If all possible values of the $variable have previously been passed into t() as literal strings.
- If the value of the $variable is coming from a recognized source of translatable text (see sections below), such as a YML or Twig file.
つまり、「DrupalシステムがJavaScriptやYAMLやTwigを読み込んで、翻訳できる文字列の対応表を作成し、そこに当てはまったもののみ翻訳される」のです。言い換えると、この問題をJavaScriptだけで解決しようとした場合、先ほど挙げた例のように、 「『Drupal.t('Hello, world!');』のような行を大量に並べたJavaScriptを用意する」 必要があります。
具体的なコーディング例まず、「翻訳したい対象のワード」をただ羅列したファイルを用意します (以下「翻訳サンプル」と呼ぶ)。ビルド対象として仕込みたいので、例えばtranslation.js
やtranslation.ts
といったファイル名で保存します。
Drupal.t("Account");
Drupal.t("Document");
Drupal.t("User");
Drupal.t("User Data");
次に、先ほどのファイルをどこかでimport
しつつ、Drupal.t()
を用いて普通に開発します。翻訳サンプルのご利益により、普通のJavaScriptのように、文字結合でもなんでも使って大丈夫になります。
const func = (text, args) => {
return Drupal.t(text, args); // OK
}
console.log(Drupal.t('Document')); // OK
console.log(Drupal.t('User' + ' Data')); // OK
ここで気になるのは、TypeScriptで開発する際のことです。Drupal
の型定義がないと、TypeScriptのコンパイラがそれを検知し、コンパイルエラーになってしまいます。そのため、Drupal
の型定義を外部から追加する必要があります。手動でDrupal.d.ts
を書いてもいいですが、ありがたいことに、自作して公開してくださっている方もいらっしゃいました。
Drupal の翻訳システムを JavaScript から利用する際は、少々トリッキーな記述が必要になると分かりました。クセさえ理解すれば問題なく動作するのですが……。
おまけ: Drupal.t() の定義を読んでみよう具体的には、/core/misc/drupal.js
のことを指します。
Drupal.t = function (str, args, options) {
options = options || {};
options.context = options.context || '';
// Fetch the localized version of the string.
if (
typeof drupalTranslations !== 'undefined' &&
drupalTranslations.strings &&
drupalTranslations.strings[options.context] &&
drupalTranslations.strings[options.context][str]
) {
str = drupalTranslations.strings[options.context][str];
}
if (args) {
str = Drupal.formatString(str, args);
}
return str;
};
ここで「str = drupalTranslations.strings[options.context][str];
」という記述をよく見てください。前述の if 文から、「drupalTranslations
が定義されている」「翻訳したい文字列 (str
) に対応する翻訳データ (drupalTranslations.strings[options.context][str]
) が存在する」条件を満たさないと、翻訳されないのだということが分かります。「// Fetch the localized version of the string.
」などとコメントに書かれていますが、別に Fetch API なんて使っていないのです。
ちなみに、キーワードに対応した置換処理 (「Hello, @username .
」の「@username
」を置換する場合など) については、同ファイル内の Drupal.formatString()
の実装に詳しく書かれています。
- 閲覧数 26
コメントを追加