このチュートリアルでは、アプリケーション向けの国際化・ローカライズエンジン(一般に i18n と l10n と呼ばれます)の例を作り、サイトのコンテンツを配信し、訪問者の所在地に応じて自動で翻訳します。
このチュートリアルでは、Cloudflare Workers ランタイムに組み込まれた HTMLRewriter クラスを使います。Cloudflare のグローバルネットワーク上で HTML の解析と書き換えができます。これにより、Workers アプリケーションを効率よく、透過的にカスタマイズできます。
すべてのフレームワークガイドは、Git ↗ の基本的な理解があることを前提としています。Git を初めて使う場合は、この Git ハンドブックの要約 ↗ で、ローカルマシンへの Git のセットアップ方法を確認してください。
SSH でクローンする場合は、GitHub に対して push または pull する各コンピューターで SSH キーを生成 ↗ する必要があります。
詳細は GitHub のドキュメント ↗ と Git のドキュメント ↗ を参照してください。
このチュートリアルは、既存のウェブサイトを使う前提です。手順を簡単にするため、HTML5 UP ↗ の無料 HTML5 テンプレートを使います。このサイトを土台に、Workers プラットフォームの HTMLRewriter で i18n レイヤーを重ね、ユーザーの言語に応じてサイトを自動翻訳します。
自分のバージョンをデプロイしたい場合は、ソースを GitHub ↗ で確認できます。デプロイ手順はプロジェクトの README にあります。
create-cloudflare を使って新しいアプリケーションを作成します。Cloudflare 向けのアプリケーション作成・デプロイ用 CLI です。
npm create cloudflare@latest -- i18n-exampleyarn create cloudflare i18n-examplepnpm create cloudflare@latest i18n-exampleセットアップでは、次の選択肢を選びます。
- What would you like to start with? では
Framework Starterを選びます。 - Which development framework do you want to use? では
Reactを選びます。 - Do you want to deploy your application? では
Noを選びます。
生成された i18n-example プロジェクトには、public と src の 2 つのフォルダーがあります。React アプリケーションのファイルが入っています。
cd i18n-example
lspublic src package.json生成されたプロジェクトを少し直します。まず public ディレクトリの中身を、デモのスクリーンショットにある HTML5 UP テンプレートのデフォルト HTML に置き換えます。このプロジェクトの リリース ↗(ZIP ファイル)をダウンロードし、public フォルダーを自分のプロジェクトにコピーして始めます。
次に、functions ディレクトリと index.js ファイルを作成します。アプリケーションのロジックはここに書きます。
mkdir functions
cd functions
touch index.jsさらに、このプロジェクトでは不要なため src/ ディレクトリを削除します。静的 HTML を更新したら、functions フォルダー内の index.js に集中できます。
Workers ランタイムの HTMLRewriter クラスを使うと、HTML を解析し、ページの各要素をクエリして変換する JavaScript を書けます。
このチュートリアルの例サイトは、public ディレクトリにある基本的な 1 ページの HTML プロジェクトです。テキスト Example Site の h1 要素と、異なるテキストの複数の p 要素があります。
このページの特徴は、HTML の data 属性 ↗ です。複数の要素に定義されたカスタム属性です。h1 タグと多くの p タグにある data-i18n-key は、対応する国際化キーがあることを示します。このキーで、テキストの翻訳を探します。
<!-- source clipped from i18n-example site -->
<div class="inner">
<h1 data-i18n-key="headline">Example Site</h1>
<p data-i18n-key="subtitle">This is my example site. Depending o...</p>
<p data-i18n-key="disclaimer">Disclaimer: the initial translations...</p>
</div>HTMLRewriter で、./public/index.html 内の HTML を解析します。data-i18n-key 属性が見つかったら、その値で strings オブジェクトから一致する翻訳を取得します。HTMLRewriter では、要素をクエリして data 属性を探すといった処理ができます。名前のとおり、翻訳した文字列を HTML に直接挿入して、要素を書き換えることもできます。
このプロジェクトのもう 1 つの機能は、受信リクエストの Accept-Language ヘッダーに基づきます。リクエストごとに翻訳言語を設定できるので、世界中のユーザーに、その地域向けに翻訳されたページを表示できます。
functions/index.js ファイルから始めます。このチュートリアルのアプリケーションは、すべてこのファイルに置きます。
このファイルの先頭に、Pages Function を動かすデフォルトのコードを追加します。
export function onRequest(context) {
return new Response("Hello, world!");
}重要な処理は onRequest 関数にあります。サイトを翻訳するには、env.ASSETS.fetch(request) で HTML レスポンスを取得します。これで Pages プロジェクトの静的アセットを取得できます。取得したレスポンスを、新しい HTMLRewriter インスタンスに渡します。
HTMLRewriter を生成するとき、on 関数でハンドラーを付けられます。このチュートリアルでは [data-i18n-key] セレクターを使います。高度な使い方は HTMLRewriter のドキュメント を参照してください。このセレクターで、data-i18n-key 属性を持つ要素をすべて探します。これらの要素は翻訳が必要です。
一致した要素は、翻訳ロジックを持つ ElementHandler クラスのインスタンスに渡されます。作成した HTMLRewriter の transform 関数は response を受け取り、クライアントに返せます。
export async function onRequest(context) {
const { request, env } = context;
const response = await env.ASSETS.fetch(request);
return new HTMLRewriter()
.on("[data-i18n-key]", new ElementHandler(countryStrings))
.transform(response);
}ElementHandler は、HTMLRewriter インスタンスが解析したすべての要素を受け取ります。表現力のある API なので、各要素の情報をクエリできます。
data-i18n-key を理解する では、ウェブサイトの UI 向けに対応する翻訳文字列を探すカスタム data 属性 data-i18n-key を説明しています。ElementHandler では element 関数を定義できます。各要素の解析時に呼ばれます。element 関数内で、getAttribute を使ってカスタム data 属性をクエリできます。
class ElementHandler {
element(element) {
const i18nKey = element.getAttribute("data-i18n-key");
}
}i18nKey が取れたら、対応する翻訳文字列を探せます。次に、data-i18n-key の値に対応するキーと値のペアを持つ strings オブジェクトを用意します。まずは 1 つの例として、ドイツ語の string "Beispielseite"("Example Site")を headline に定義し、element 関数で取得します。
const strings = {
headline: "Beispielseite",
};
class ElementHandler {
element(element) {
const i18nKey = element.getAttribute("data-i18n-key");
const string = strings[i18nKey];
}
}翻訳した string を、setInnerContent 関数で元の要素に挿入します。
const strings = {
headline: "Beispielseite",
};
class ElementHandler {
element(element) {
const i18nKey = element.getAttribute("data-i18n-key");
const string = strings[i18nKey];
if (string) {
element.setInnerContent(string);
}
}
}想定どおりか確認するには、Wrangler 組み込みのプレビュー機能を使います。wrangler pages dev ./public を実行すると、プロジェクトのライブプレビューが開きます。コードを変更するたびにプレビューが更新されます。
この翻訳機能を拡張して、受信リクエストの Accept-Language ヘッダーに基づく言語別の翻訳を提供できます。このヘッダーを解析し、解析した言語を ElementHandler に渡すと、strings に定義がある場合、ユーザーの使用言語で翻訳文字列を取得できます。
実装手順は次のとおりです。
stringsオブジェクトを更新し、キーと値のペアをもう 1 層追加します。文字列はstrings[country][key]の形式で探します。- 解析中に使えるよう、
countryStringsオブジェクトをElementHandlerに渡します。 - 受信リクエストから
Accept-Languageヘッダーを取得し、解析して、解析した言語をElementHandlerに渡します。
Accept-Language ヘッダーを解析するには、accept-language-parser ↗ npm パッケージをインストールします。
npm i accept-language-parserコードにインポートしたら、Accept-Language ヘッダーに基づいてクライアントに最も適した言語を解析し、ElementHandler に渡します。ドイツと日本向けのサンプル翻訳(Google 翻訳を使用)を含めた、プロジェクトの最終コードは次のとおりです。
import parser from "accept-language-parser";
// do not set to true in production!
const DEBUG = false;
const strings = {
de: {
title: "Beispielseite",
headline: "Beispielseite",
subtitle:
"Dies ist meine Beispielseite. Abhängig davon, wo auf der Welt Sie diese Site besuchen, wird dieser Text in die entsprechende Sprache übersetzt.",
disclaimer:
"Haftungsausschluss: Die anfänglichen Übersetzungen stammen von Google Translate, daher sind sie möglicherweise nicht perfekt!",
tutorial:
"Das Tutorial für dieses Projekt finden Sie in der Cloudflare Workers-Dokumentation.",
copyright: "Design von HTML5 UP.",
},
ja: {
title: "サンプルサイト",
headline: "サンプルサイト",
subtitle:
"これは私の例のサイトです。 このサイトにアクセスする世界の場所に応じて、このテキストは対応する言語に翻訳されます。",
disclaimer:
"免責事項:最初の翻訳はGoogle翻訳からのものですので、完璧ではないかもしれません!",
tutorial:
"Cloudflare Workersのドキュメントでこのプロジェクトのチュートリアルを見つけてください。",
copyright: "HTML5 UPによる設計。",
},
};
class ElementHandler {
constructor(countryStrings) {
this.countryStrings = countryStrings;
}
element(element) {
const i18nKey = element.getAttribute("data-i18n-key");
if (i18nKey) {
const translation = this.countryStrings[i18nKey];
if (translation) {
element.setInnerContent(translation);
}
}
}
}
export async function onRequest(context) {
const { request, env } = context;
try {
let options = {};
if (DEBUG) {
options = {
cacheControl: {
bypassCache: true,
},
};
}
const languageHeader = request.headers.get("Accept-Language");
const language = parser.pick(["de", "ja"], languageHeader);
const countryStrings = strings[language] || {};
const response = await env.ASSETS.fetch(request);
return new HTMLRewriter()
.on("[data-i18n-key]", new ElementHandler(countryStrings))
.transform(response);
} catch (e) {
if (DEBUG) {
return new Response(e.message || e.toString(), {
status: 404,
});
} else {
return env.ASSETS.fetch(request);
}
}
}Cloudflare Pages 上に作った i18n ツールは完成です。ドメインへデプロイします。
アプリケーションを *.pages.dev サブドメインにデプロイするには、配信する静的アセットのディレクトリを指定します。プロジェクトの Wrangler ファイルで pages_build_output_dir を設定し、値を ./public にします。
{
"$schema": "./node_modules/wrangler/config-schema.json",
"name": "i18n-example",
"pages_build_output_dir": "./public",
// Set this to today's date
"compatibility_date": "2026-09-20"
}"$schema" = "./node_modules/wrangler/config-schema.json"
name = "i18n-example"
pages_build_output_dir = "./public"
# Set this to today's date
compatibility_date = "2026-09-20"次に、プロジェクトの package.json にデプロイ用スクリプトを設定します。値が wrangler pages deploy の deploy スクリプトを追加します。
"scripts": {
"dev": "wrangler pages dev",
"deploy": "wrangler pages deploy"
}wrangler の deploy コマンドで、Cloudflare のネットワークにデプロイします。
npm run deploy
このチュートリアルでは、HTMLRewriter を使って i18n ツールを作り、デプロイしました。このアプリケーションのソースコード全体は、GitHub のリポジトリ ↗ を参照してください。
自分のプロジェクトを作りたい場合は、既存の Quickstart テンプレート の一覧を確認してください。