このページとあなたの好きなAIアシスタントを使ってドキュメントを要約します
バージョン履歴
- "remix-intlayer ミドルウェアとフックの使用"v9.5.52026/9/19
- "Remix 3 用の初期ドキュメント"v9.5.02026/9/9
このページのコンテンツはAIを使用して翻訳されました。
英語の元のコンテンツの最新バージョンを見るこのドキュメントを改善するアイデアがある場合は、GitHubでプルリクエストを送信することで自由に貢献してください。
ドキュメントへのGitHubリンクドキュメントのMarkdownをクリップボードにコピー
Intlayer を使用して Remix 3 Web サイトを翻訳する
このガイドでは、Remix 3 アプリケーションにおいて Intlayer を統合し、ロケール対応ルーティング、型安全なコンテンツ宣言、サーバーレンダリング対応の JSX コンポーネント、ならびに Node.js、Bun、Deno、Cloudflare Workers にわたるクロスランタイムサポートを備えたシームレスな国際化を実現する方法を解説します。
Remix 3 とは?
Remix 3 は、完全に Web 標準に基づいて構築された、コンポーザブルでランタイムに依存しない Web フレームワークへの根本的なアーキテクチャ刷新を表しています。特定のバンドラーや独自のサーバー API に依存することなく、単一目的のコンポーザブルなパッケージとして提供されます。
remix/fetch-router(またはremix/router): Fetch API (RequestおよびResponse) に基づく軽量で標準準拠のルーティング。remix/ui: JSX コンポーネントモデル (jsxImportSource: "remix/ui")。コンポーネントは Handle を受け取りレンダー関数を返すセットアップ関数であり、React に似ていますが状態はプレーンな JavaScript クロージャ内に保持されます。remix/middleware/render: 各リクエストにcontext.render(<Page />)を登録し、JSX ツリーを HTMLResponseとしてストリーミングします。remix/node-fetch-server: Bun、Deno、およびエッジランタイムをネイティブサポートする Node.js 用サーバーアダプター。remix/cookie: 暗号学的に安全な Cookie の解析とシリアル化。
Intlayer と remix-intlayer パッケージ(ロケールミドルウェアおよび Remix リクエストコンテキストにバインドされた react-intlayer と同じ useIntlayer / useDictionary / useLocale フック)を組み合わせることで、コンパイル時の安全性、AI による自動翻訳、オーバーヘッドのないサーバーレンダリング、シームレスなロケールルーティングを提供する完全な国際化システムが実現します。
目次
他の選択肢ではなく Intlayer を選ぶ理由
i18next や独自の翻訳ローダーなどの従来手法と比較して、Intlayer は現代の Web アーキテクチャに最適化された統合的な開発体験を提供します。
Intlayer はウェブ標準(Request、Response、Headers、URL)とシームレスに連携するように構築されています。remix-intlayer は軽量なミドルウェアとして Remix 3 の Fetch ルーターに組み込まれ、URL パス、Cookie、または Accept-Language ヘッダーからロケールを抽出し、引数として引き回すことなく、ハンドラー、ビュー、remix/ui コンポーネントなどのリクエスト全体に公開します。
曖昧な JSON キーや実行時のキー不足によるクラッシュとはお別れです。Intlayer は宣言されたすべての言語で TypeScript チェックを適用し、翻訳が欠落または無効な場合はビルド時に警告を発します。
Remix 3 はサーバー上で JSX コンポーネントをレンダリングし、HTML をクライアントへストリーミングします。リクエストされたロケールに対して解決されたテキストのみが出力ストリームに書き込まれます。コンポーネントが明示的に clientEntry としてマークされていない限り、クライアントハイドレーションバンドルや重い翻訳カタログは一切不要です。
Intlayer はコンテンツ宣言 (.content.ts) をルートロジックと同じ場所に配置し、大規模言語モデル (LLM) に必要なトークンコンテキストを削減します。intlayer fill や intlayer test などの組み込み CLI コマンドにより、選択した AI プロバイダーの実費のみで CI/CD パイプラインでの翻訳自動化が可能です。
コードファーストのワークフローだけでなく、Intlayer はセルフホスト可能な ビジュアルエディター と リモート CMS を提供し、開発者以外の編集者や翻訳者がコードを再デプロイすることなく文言を更新できるようにします。
ステップバイステップガイド
GitHub の アプリケーションテンプレート をご覧ください。
依存関係のインストール
お好みのパッケージマネージャーを使用して、
intlayer、remix-intlayer、およびremix(バージョン 3)をインストールします:bashコードをコピーコードをクリップボードにコピー
intlayer: 設定管理、辞書宣言 (t(),Dictionary)、CLI ツール、およびランタイムインタープリターを提供するコア国際化エンジン。remix-intlayer: Remix 3 統合: 各リクエストのロケールを解決するintlayer()ルーターミドルウェア、およびそれ以降の任意の場所で読み取るuseIntlayer、useDictionary、useLocaleフック。remix:remix/router、remix/routes、remix/ui、remix/middleware/render、およびremix/node-fetch-serverをエクスポートする統合 Remix 3 フレームワークパッケージ。
Intlayer の設定
アーキテクチャ
このアーキテクチャでは、
remix-intlayerのintlayer()ミドルウェアがrender()ミドルウェアの前にcreateRouter()に登録されます。ルーターがマッチングする前にロケールプレフィックスを削除するため、ルートは:localeセグメントなしでsrc/routes.tsに一度だけ宣言され、リクエストの残りの部分をAsyncLocalStorageスコープ内で実行します。これにより、ルートハンドラーやremix/uiビューで引数なしでuseIntlayer/useLocaleがロケールを読み取れるようになります。コンテンツ宣言はsrc/内のビューと一緒に配置されます:bashコードをコピーコードをクリップボードにコピー
設定
プロジェクトのルートに
intlayer.config.tsを作成し、サポートする言語と国際化設定を宣言します。intlayer.config.tsコードをコピーコードをクリップボードにコピー
import { Locales, type IntlayerConfig } from "intlayer"; const config: IntlayerConfig = { internationalization: { locales: [ Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH, Locales.JAPANESE, ], defaultLocale: Locales.ENGLISH, }, }; export default config;その他の設定オプションについては、設定ドキュメント を参照してください。
多言語コンテンツの宣言
.content.tsファイルでローカライズされたコンテンツを宣言します。src/home.content.tsコードをコピーコードをクリップボードにコピー
import { t, type Dictionary } from "intlayer"; const homeContent = { key: "home", content: { title: t({ ja: "Remix 3 へようこそ", en: "Welcome to Remix 3", fr: "Bienvenue sur Remix 3", es: "Bienvenido a Remix 3", }), description: t({ ja: "ネイティブ i18n 機能を備えた Web 標準準拠のコンポーザブルアプリケーション。", en: "A composable, web-standard application with native i18n.", fr: "Une application composable basée sur les standards web avec i18n native.", es: "Una aplicación componible basada en estándares web con i18n nativa.", }), switchLanguage: t({ ja: "言語を切り替える:", en: "Switch language:", fr: "Changer de langue :", es: "Cambiar idioma:", }), }, } satisfies Dictionary; export default homeContent;Intlayer は JSON、YAML、および CommonJS 形式もサポートしています。コンテンツ宣言ドキュメント をご覧ください。
Intlayer 辞書のビルド
辞書定義をコンパイルして TypeScript の型とランタイムレジストリを生成します。
bashコードをコピーコードをクリップボードにコピー
これにより、コンテンツが
.intlayerアーティファクトディレクトリにコンパイルされ、TypeScript による完全な自動補完と高速な辞書参照が可能になります。Intlayer ミドルウェアの追加
Remix 3 は、
createRouter({ middleware: [...] })を介して構成可能なミドルウェアパイプラインを提供します。remix-intlayerはintlayer()ミドルウェアを提供します。受信するリクエストごとに、以下を使用してロケールを解決します:no-prefix以外のすべてのルーティングモードにおける URL: パスプレフィックス(例:/jaまたは/en)または?locale=検索パラメータ。- クライアントによって永続化されたロケール: ストレージ Cookie(
INTLAYER_LOCALE)またはカスタムヘッダー(x-intlayer-locale)。 - 標準の
Accept-Languageネゴシエーション(設定されたdefaultLocaleへのフォールバック)。
結果は
locale、defaultLocale、availableLocalesとともに Remix リクエストコンテキストにcontext.intlayer(またはcontext.get(Intlayer))として保存されます。ミドルウェアはその後、そのコンテキストにバインドされたAsyncLocalStorageスコープ内でリクエストの残りを実行します。これにより、パッケージのフックはルートハンドラー、ビュー、remix/uiコンポーネントのいずれでも引数なしでロケールを読み取ることができます:typescriptコードをコピーコードをクリップボードにコピー
useIntlayer("home", "fr")またはuseIntlayer("faq", { item: 2 })は1回の呼び出しでリクエストロケールを上書きし、useDictionary(homeContent)はキーの代わりにインポートされた辞書を読み取ります。リクエスト外ではフックはデフォルトロケールにフォールバックします。ミドルウェアはサーバー起動時に Intlayer 辞書も準備するため、
intlayer buildが実行されていなくてもレジストリが空になることはありません。intlayer.config.tsでrouting.enableProxy: falseを設定すると、ロケールの解決のみを維持し、ルーティングは自分で処理できます。intlayer({ ignore })は一致するリクエスト(例えば API のプレフィックス)をそのまま通し、intlayer({ isDevServer })はデフォルトのenableProxy自動モードで保存されたロケールがリダイレクトを決定するかどうかを制御します。型安全なルートの定義
remix/routesのroute()を使用してアプリケーションルートを定義します。src/routes.tsコードをコピーコードをクリップボードにコピー
import { route } from "remix/routes"; export const routes = route({ // デフォルトロケールルート home: "/", // 動的な :locale セグメントを持つローカライズルート localizedHome: "/:locale", });route()を使用することで、アプリケーション全体で型安全な URL 生成が可能になります。typescriptコードをコピーコードをクリップボードにコピー
JSX を使用したローカライズページのレンダリング
Remix 3 は
remix/uiの JSX コンポーネントを使用して UI をレンダリングします。コンポーネントはHandleを受け取りレンダー関数を返すセットアップ関数です。セットアップはインスタンスごとに 1 回だけ実行され、レンダリングは更新ごとに実行され、props はhandle.propsを介して読み取られます。ミドルウェアによって解決されたロケールから
<html lang="..." dir="...">属性を設定する共有Documentシェルから始めます:src/views/document.tsxコードをコピーコードをクリップボードにコピー
import { getHTMLTextDir } from "intlayer"; import { useLocale } from "remix-intlayer"; import type { Handle, RemixNode } from "remix/ui"; type DocumentProps = { title: string; children?: RemixNode; }; export const Document = (handle: Handle<DocumentProps>) => () => { const { title, children } = handle.props; const { locale } = useLocale(); return ( <html lang={locale} dir={getHTMLTextDir(locale)}> <head> <meta charSet="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>{title}</title> </head> <body>{children}</body> </html> ); };次にホームページを作成します。
useIntlayerでローカライズされた辞書を読み取り、言語スイッチャーをレンダリングします:src/views/home.tsxコードをコピーコードをクリップボードにコピー
import { getLocaleName, getLocalizedUrl, getPathWithoutLocale } from "intlayer"; import { useIntlayer, useLocale } from "remix-intlayer"; import { Document } from "./document"; export const HomePage = () => () => { const { locale, availableLocales } = useLocale(); const home = useIntlayer("home"); const pathWithoutLocale = getPathWithoutLocale(); return ( <Document title={home.title}> <header> <nav aria-label="Languages"> <span>{home.switchLanguage}</span> <ul> {availableLocales.map((localeItem) => { const isActive = localeItem === locale; return ( <li key={localeItem} class="p-1"> <a href={getLocalizedUrl(pathWithoutLocale, localeItem)} class={isActive ? "active" : undefined} aria-current={isActive ? "page" : undefined} > {getLocaleName(localeItem, locale)} </a> </li> ); })} </ul> </nav> </header> <main> <h1>{home.title}</h1> <p>{home.description}</p> </main> </Document> ); };Remix JSX は React ではありません:
classはそのまま記述され(classNameも使用可能)、再レンダリングはhandle.update()で明示的にトリガーされます。補間された値は自動的にエスケープされます。Intlayer フックはリクエストスコープを読み取るプレーンな関数であるため、セットアップ関数またはレンダリング関数のどちらからでも呼び出すことができます。ルーターとサーバーの接続
Intlayer ミドルウェアの横に
remix/middleware/renderのrender()ミドルウェアを追加します。各リクエストにcontext.render(node, init)が組み込まれ、JSX ツリーを HTMLResponseにストリーミングします (先頭に<!DOCTYPE html>を付加し、Content-Typeヘッダーを設定します)。src/router.tsxコードをコピーコードをクリップボードにコピー
import { isDeclaredLocale } from "intlayer"; import { intlayer } from "remix-intlayer"; import { render } from "remix/middleware/render"; import { createRouter } from "remix/router"; import { routes } from "./routes"; import { HomePage } from "./views/home"; // 1. Initialize router with Intlayer + render middleware export const router = createRouter({ middleware: [intlayer(), render()], }); // 2. Map route handlers router.map(routes, { actions: { // Default locale route home(context) { return context.render(<HomePage />); }, // Localized route localizedHome(context) { if (!isDeclaredLocale(context.params.locale)) { return new Response("Not Found", { status: 404 }); } return context.render(<HomePage />); }, }, });context.renderは第2引数としてオプションのResponseInitを受け入れます(例:context.render(<NotFoundPage />, { status: 404 }))。解決されたロケールは、Response.jsonペイロードを作成する場合などに、ハンドラーからcontext.intlayer.localeとしてアクセスできます。最後に、標準の
fetchハンドラーを介してルーターを公開します。同じルーターが Node.js、Bun、Deno、および Cloudflare Workers 上で動作します。src/server.tsコードをコピーコードをクリップボードにコピー
import * as http from "node:http"; import { createRequestListener } from "remix/node-fetch-server"; import { router } from "./router"; const PORT = Number(process.env.PORT || 3000); // Node.js const server = http.createServer( createRequestListener((request) => router.fetch(request)) ); server.listen(PORT, () => { console.log(`サーバーが http://localhost:${PORT} で起動しました`); }); // Bun / Deno / Cloudflare Workers export default { port: PORT, fetch(request: Request) { return router.fetch(request); }, };翻訳の監査と自動補完
Intlayer は不足している翻訳を監査し、AI を使用して自動補完するための CLI を提供します。
bashコードをコピーコードをクリップボードにコピー
TypeScript 設定
JSX を remix/ui ランタイムに向け、tsconfig.json に生成された .intlayer の型が含まれていることを確認してください。
コードをクリップボードにコピー
jsxImportSource: "remix/ui"により、<HomePage />は React ではなく Remix のcreateElementに解決されます。
結論
Remix 3 と Intlayer を組み合わせることで、オープンな Web 標準に準拠した、スリムで完全に型付けされたポータブルな技術スタックを構築できます。シンプルなローカライズマーケティングページから、エッジでレンダリングされるグローバル分散サービスまで、柔軟にスケールさせることができます。
