@k8ordo/i18n

うまく動かないとき

よくつまずく症状と、その原因、直し方をまとめています。

このページの内容

「no text for "en"」というエラーが出る

原因

型をすり抜けて、そのロケールの文が無い文言を読んでいます。JavaScriptで書いた文言や、asで型を通した文言、Registerを登録する前に書いた文言で起こります。

直し方

エラーの文面に、欠けているロケールと、文言が持っているロケールが出ています。欠けたロケールの文を足してください。Registerを登録しておけば、同じ欠けは宣言の時点で型エラーになります。

ロケールが欠けても型エラーにならない

原因

Registerにロケールの型が登録されていません。登録する前はRegisteredLocaleがstringなので、どのロケールの組み合わせでも通ります。

直し方

集合を定義するモジュールに、declare module '@k8ordo/i18n'でRegisterを書きます。そのモジュールがTypeScriptのプロジェクトに含まれているかも確かめてください。

言語を切り替えても、一部の文言だけが変わらない

原因

モジュールのトップレベルで文言を呼び、文字列にしています。文言は呼ばれた瞬間のロケールを読むので、モジュールを読み込んだときのロケールのまま固定されます。

直し方

文言をMessageのまま持ち、描くコンポーネントの中で呼びます。

日付がサーバーとブラウザで食い違う

原因

timeZoneを指定しないnew Intl.DateTimeFormatは、実行環境のタイムゾーンで書きます。サーバーとブラウザでタイムゾーンが違うと、日付や時刻がずれて、ハイドレーションで食い違います。

直し方

locales.dateTimeFormatで書きます。ロケールのtimeZoneで書くので、両側で同じ日付になります。訪問者のタイムゾーンで見せたいものは、ブラウザだけで描く部分に置きます。

ページが既定のロケールで描かれる

原因

[locale]のレイアウトがparamsSchemaをexportしていません。サーバーはスキーマが受け付けたロケールしか読まないので、/en/…でも既定のロケールで描かれます。一覧に無い/fr/…も、404になりません。

直し方

Server Componentのレイアウトにexport const { paramsSchema } = localesと書きます。'use client'を付けたモジュールからexportしても、スキーマとしては届きません。

「no AsyncLocalStorage to scope a locale to」というエラーが出る

原因

サーバーのランタイムが、process.getBuiltinModuleでAsyncLocalStorageを渡せません。受け付けたロケールを描画に結び付けられないので、既定のロケールで描く代わりにエラーを投げています。

直し方

process.getBuiltinModule('node:async_hooks')を持つランタイムで動かします。@k8ordo/staticと@k8ordo/serverが求めるNode 24は、これを持っています。

「in the browser the URL is the locale」というエラーが出る

原因

ブラウザでlocales.runを呼んでいます。jsdomやhappy-domのようにdocumentを定義するテスト環境も、ブラウザとして扱われます。

直し方

ブラウザでロケールを変えるには、そのロケールのURLへ移動します。テストでは、history.replaceStateでpathnameを変えます。

@k8ordo/uiのコンポーネントだけが英語になる

原因

集合を定義するモジュールが、ブラウザで読み込まれていません。集合が無い環境では、@k8ordo/uiは英語で描くので、サーバーのHTMLとも食い違います。

直し方

リンクのbindParamsや言語の切り替えのように、Client Componentからlocalesをimportします。

「@k8ordo/ui: no built-in text for "fr"」というエラーが出る

原因

@k8ordo/uiには、jaとenの文言しか入っていません。登録の無いロケールで描くと、エラーを投げます。fr-CAのような地域の付いたタグは、登録が無ければ言語のfrを探します。

直し方

集合を定義するモジュールで、@k8ordo/ui/i18nのregisterMessages('fr', fr)を呼びます。

静的ビルドが「static build needs pathnames for」で止まる

原因

/:locale/blog/:slugのように、ロケールのほかにもパラメータを持つパターンがあります。locales.pathsはロケールしか展開しないので、:slugが残ります。

直し方

pathsに渡す関数の中で、locales.pathsの結果に残ったパラメータを展開します。書き方は「静的に書き出す」にあります。

切り替え先のURLにロケールが2つ並ぶ

原因

ロケールの区間が付いたままのpathnameを、localizeに渡しています。localizeは、区間がすでにあるかを確かめません。

直し方

先にdelocalizeで区間を外し、そのpathnameをlocalizeに渡します。

404ページが既定の言語のまま変わらない

原因

静的なホストが返す404.htmlは、ビルドで1回だけ、既定のロケールで描かれます。Server Componentが描いた文は、既定のロケールのまま残ります。

直し方

not-found.tsxをClient Componentにして文言を描きます。ブラウザが訪問者のURLで描き直すときに、訪問者のロケールになります。

Server ComponentからClient Componentに文言を渡すと描画に失敗する

原因

文言は関数で、Reactは関数をpropsとしてClient Componentへ送れません。

直し方

呼んだ結果の文字列を渡すか、Client Componentの中で文言をimportして呼びます。

フォームのエラー文言がページの言語にならない

原因

zodに文言を呼んだ結果の文字列を渡しているか、formFieldsをモジュールのトップレベルで呼んでいます。どちらも、その時点のロケールで文字列が固定されます。

直し方

zodには{ error: m.talk.titleRequired }のように文言を関数のまま渡し、formFieldsはページの描画の中で呼びます。

k8ordo

Baselineに入った機能を、制限なく使うReactのライブラリ群。

© 2026 k8o — MIT License

組版:Noto Sans JP / M PLUS 2