INTEGRITY Документация

Локализация веб-сайта с помощью HTMLRewriter

В этом руководстве вы создадите пример движка интернационализации и локализации (обычно называемого i18n и l10n) для вашего приложения, обслуживать содержимое вашего сайта и автоматически переводить его в зависимости от местоположения посетителей в мире.

В этом руководстве используется HTMLRewriter класс, встроенный в среду выполнения Cloudflare Workers, который позволяет разбирать и переписывать HTML прямо в глобальной сети Cloudflare. Это даёт разработчикам возможность эффективно и прозрачно настраивать свои приложения Workers.

Пример сайта, который был успешно локализован на японский, немецкий и английский языки

Прежде чем продолжить

Все руководства по фреймворкам предполагают, что у вас уже есть базовое понимание Git. Если вы новичок в Git, обратитесь к этому краткое руководство по Git о том, как настроить Git на локальном компьютере.

Если вы клонируете по SSH, необходимо сгенерировать ключи SSH на каждом компьютере, с которого вы отправляете или получаете данные из GitHub.

См. документация GitHub и Документация Git, где это описано подробнее.

Предварительные требования

Это руководство рассчитано на использование существующего веб-сайта. Чтобы упростить процесс, вы используете бесплатный шаблон HTML5 от HTML5 UP. Взяв этот сайт за основу, вы будете использовать HTMLRewriter функциональность платформы Workers, чтобы наложить слой i18n, автоматически переводя сайт в зависимости от языка пользователя.

Если вы хотите развернуть собственную версию сайта, исходный код можно найти на GitHub. Инструкции по развертыванию этого приложения можно найти в файле README проекта.

Создайте новое приложение

Создайте новое приложение с помощью create-cloudflare, CLI для создания и развертывания новых приложений в Cloudflare.

npm create cloudflare@latest -- i18n-example

Для настройки выберите следующие параметры:

Только что созданный i18n-example проект будет содержать две папки: public и src они содержат файлы для приложения React:

cd i18n-example
ls
public src package.json

Внесём несколько изменений в сгенерированный проект. Сначала заменим содержимое внутри public директория со стандартным сгенерированным HTML кодом шаблона HTML5 UP, как показано на демонстрационном скриншоте: загрузите релиз (ZIP-файл) с кодом этого проекта и скопируйте public папку в свой проект, чтобы начать работу.

Далее создайте каталог functions, содержащий index.js файл, именно здесь будет находиться логика приложения.

mkdir functions
cd functions
touch index.js

Кроме того, мы удалим src/ директорию, так как её содержимое не требуется для этого проекта. После обновления статического HTML для этого проекта можно сосредоточиться на скрипте внутри functions папка, по адресу index.js.

Основные сведения о data-i18n-key

HTMLRewriter класс, предоставляемый средой выполнения Workers, позволяет разработчикам разбирать HTML и писать код на JavaScript для запроса и преобразования каждого элемента страницы.

Пример сайта в этом руководстве представляет собой базовый одностраничный HTML-проект, расположенный в public директория. Она включает h1 элемент с текстом Example Site и ряд p элементы с разным текстом:

Демонстрационный код в Chrome DevTools с элементами, описанными выше

Особенность этой страницы заключается в добавлении атрибуты данных в HTML: пользовательские атрибуты, определённые для ряда элементов на этой странице. data-i18n-key на h1 тег на этой странице, а также многие из p тегов означает, что существует соответствующий ключ интернационализации, который следует использовать для поиска перевода этого текста:

<!-- 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, вы разберете HTML внутри ./public/index.html странице. Когда data-i18n-key атрибут найден, используйте значение атрибута, чтобы получить соответствующий перевод из strings объект. С HTMLRewriter, вы можете запрашивать элементы для таких задач, как поиск атрибута данных. Однако, как следует из названия, вы также можете переписывать элементы, вставляя переведённую строку прямо в HTML.

Ещё одна особенность этого проекта основана на Accept-Language заголовок, который присутствует во входящих запросах. Вы можете задавать язык перевода для каждого запроса, что позволяет пользователям со всего мира видеть локально релевантную и переведённую страницу.

Использование HTML Rewriter API

Начните с functions/index.js файл. В этом руководстве всё приложение будет находиться в этом файле.

В этом файле для начала добавьте код по умолчанию для запуска Pages Function.

export function onRequest(context) {
	return new Response("Hello, world!");
}

Важная часть кода находится в onRequest функция. Чтобы реализовать переводы на сайте, возьмите HTML-ответ, полученный из env.ASSETS.fetch(request) это позволяет получить статический ресурс из вашего проекта 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);
}

Преобразование HTML

Ваш ElementHandler будет получать каждый элемент, обработанный HTMLRewriter экземпляр, и благодаря выразительному API вы можете запрашивать информацию о каждом входящем элементе.

В Как это работает, в документации описывается data-i18n-key, пользовательский атрибут данных, который можно использовать для поиска соответствующей переведённой строки интерфейса сайта. В ElementHandler, вы можете определить element функция, которая вызывается при разборе каждого элемента. Внутри element функции вы можете запросить пользовательский атрибут данных с помощью getAttribute:

class ElementHandler {
	element(element) {
		const i18nKey = element.getAttribute("data-i18n-key");
	}
}

С i18nKey определён, его можно использовать для поиска соответствующей переведённой строки. Теперь настройте strings объект с парами ключ-значение, соответствующими data-i18n-key значение. Пока что определите одну примерную строку, headline, с немецким string, "Beispielseite" ("Example Site"), и получить его в 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.

Чтобы это реализовать:

  1. Обновите strings объект, добавляя второй уровень пар ключ-значение и позволяя искать строки в формате strings[country][key].
  2. Передайте countryStrings объект в наш ElementHandler, чтобы её можно было использовать в процессе разбора.
  3. Скопируйте Accept-Language заголовок из входящего запроса, разберите его и передайте распознанный язык в ElementHandler.

Чтобы обработать Accept-Language заголовок, установите accept-language-parser npm-пакет:

npm i accept-language-parser

После импорта в код используйте пакет, чтобы определить наиболее подходящий язык клиента на основе Accept-Language заголовок и передайте его в ElementHandler. Итоговый код проекта с примером перевода для Германии и Японии (с использованием Google Translate) выглядит так:

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);
		}
	}
}

Развернуть

Инструмент i18n на основе Cloudflare Pages готов, пришло время развернуть его на вашем домене.

Чтобы развернуть приложение в *.pages.dev поддомен, вам нужно указать каталог со статическими ресурсами для раздачи, настроить pages_build_output_dir в файле Wrangler вашего проекта и укажите значение ./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-08-28"
}
"$schema" = "./node_modules/wrangler/config-schema.json"
name = "i18n-example"
pages_build_output_dir = "./public"
# Set this to today's date
compatibility_date = "2026-08-28"

Далее настройте скрипт развёртывания в package.json файл в проекте. Добавьте скрипт деплоя со значением wrangler pages deploy:

"scripts": {
  "dev": "wrangler pages dev",
  "deploy": "wrangler pages deploy"
}

Использование wrangler, разверните в сети Cloudflare с помощью deploy команда:

npm run deploy
Пример сайта, который был успешно локализован на японский, немецкий и английский языки

В этом руководстве вы создали и развернули инструмент i18n с помощью HTMLRewriter. Чтобы посмотреть полный исходный код этого приложения, обратитесь к репозиторий на GitHub.

Если вы хотите начать создавать собственные проекты, ознакомьтесь с существующим списком Шаблоны для быстрого старта.