コンテンツにスキップ

コンパイル済みカタログの読み込み

lingui compile を実行すると、各ロケールごとにコンパイル済みカタログファイル(.ts または .js)が生成されます。 このガイドでは、それらのファイルをどうインポートし、Lingui の実行時へどう接続するかを説明します。

すべてのロケールのインポートと SupportedLocale 型を 1 か所にまとめます。

src/lib/i18n/catalog.ts
import { messages as en } from "./locales/en";
import { messages as ja } from "./locales/ja";
export const catalog = {
en,
ja,
} as const;
export type SupportedLocale = keyof typeof catalog;

SupportedLocale 型はオブジェクトのキーから導出されるため、ロケールを追加、削除すると型も自動で更新されます。 lingui.config と別にロケール一覧を同期し続ける必要はありません。

静的インポートは最も単純な方法です。 すべてのカタログファイルが初期バンドルに含まれ、切り替えも同期的に行えます。

完全なカタログマップを setupI18n に渡します。すべてのメッセージがすぐ利用可能になります。 切り替えには activate() を使います。load() を呼ぶ必要はありません。

src/lib/i18n/instance.ts
import { setupI18n } from "@lingui/core";
import { catalog, type SupportedLocale } from "./catalog";
export const i18n = setupI18n({
locale: "en",
messages: catalog,
});
export function switchLocale(next: SupportedLocale): void {
i18n.activate(next);
}

この共有インスタンスをルートレイアウトでインポートし、setLinguiContext に渡します。

src/routes/+layout.svelte
<script lang="ts">
import { setLinguiContext } from "lingui-for-svelte";
import { i18n } from "$lib/i18n/instance";
const { children } = $props();
setLinguiContext(i18n);
</script>
{@render children()}

全カタログを静的にインポートしつつ、loadAndActivate では 1 度に 1 つのロケールだけを渡す方法です。 バンドルサイズは全ロケールをバンドルする方式と同じですが、あとで遅延読み込みへ移行する予定があるなら API の形式を揃えられます。

const i18n = setupI18n();
i18n.loadAndActivate({ locale: "en", messages: catalog.en });
function switchLocale(next: SupportedLocale): void {
i18n.loadAndActivate({ locale: next, messages: catalog[next] });
}

動的インポートを使うと、バンドラが各カタログを別チャンクへ分割できます。 要求されたロケールだけを取得するため、初期バンドルサイズを抑えられます。

const i18n = setupI18n();
async function loadLocale(locale: SupportedLocale): Promise<void> {
const { messages } = await import(`./locales/${locale}.ts`);
i18n.loadAndActivate({ locale, messages });
}

Svelte の <script> ブロックではトップレベル await は使えません。 そのため、初期ロケールは静的インポートで読み込み、セットアップを同期的に保ったまま、後続のロケール切り替えだけ動的インポートを使うのがよいです。

src/routes/+layout.svelte
<script lang="ts">
import { setupI18n } from "@lingui/core";
import { setLinguiContext } from "lingui-for-svelte";
// 初期ロケールは静的インポートにして、セットアップを同期的に保つ
import { messages as enMessages } from "$lib/i18n/locales/en";
import type { SupportedLocale } from "$lib/i18n/catalog";
const i18n = setupI18n();
i18n.loadAndActivate({ locale: "en", messages: enMessages });
setLinguiContext(i18n);
async function switchLocale(next: SupportedLocale): Promise<void> {
const { messages } = await import(`$lib/i18n/locales/${next}.ts`);
i18n.loadAndActivate({ locale: next, messages });
}
</script>

Astro のミドルウェアは非同期関数で動くため、追加の工夫なしで動的インポートを使えます。

src/middleware.ts
import { defineMiddleware } from "astro:middleware";
import { setupI18n } from "@lingui/core";
import { setLinguiContext } from "lingui-for-astro";
import type { SupportedLocale } from "./lib/i18n/catalog";
export const onRequest = defineMiddleware(async (context, next) => {
const locale = resolveLocale(context) as SupportedLocale;
const { messages } = await import(`./lib/i18n/locales/${locale}.ts`);
const i18n = setupI18n();
i18n.loadAndActivate({ locale, messages });
setLinguiContext(context.locals, i18n);
return next();
});
静的インポート動的インポート
初期バンドルサイズ全ロケールを含む最初のロケールだけ
切り替え同期的非同期(await が必要)
Svelte の初期セットアップそのまま扱いやすい初期ロケールは静的インポートが必要
Astro ミドルウェアそのまま扱いやすいそのまま扱いやすい(もともと async
向いているケース多くのアプリの標準カタログサイズが気になるとき