ローカライズ
キットの組み込み文字列すべて(77個のラベルセットにまたがる468個のラベル:aria-label、スクリーンリーダーの読み上げ、あなたが書いていないボタンのテキスト、プレースホルダー)を、ひとつのプロバイダーが翻訳します。言語パックと一緒に一度マウントすれば、すべてのgooduiコンポーネントがその言語で話し、数値・日付・通貨のフォーマットはIntlを通じて追従し、アラビア語とヘブライ語は書字方向も切り替わります。設定しないアプリは英語とen-USのフォーマットのままで、余計なものは何も読み込まれません。
インストール
npx shadcn@latest add https://goodui.dev/r/locale.json https://goodui.dev/r/locale-tr.jsonlocaleはlib/goodui-locale.tsに置かれます(ラベルを持つコンポーネントはすべてこれに依存しているので、たいてい既に入っています)。パックはlib/goodui-locales/<lang>.tsに置かれ、他には何も依存しません。出荷する言語だけインストールしてください。
言語を設定
import { GooduiLocaleProvider } from "@/lib/goodui-locale"
import tr from "@/lib/goodui-locales/tr"
export default function RootLayout({ children }) {
return (
<html lang="tr">
<body>
<GooduiLocaleProvider lang="tr" labels={tr}>{children}</GooduiLocaleProvider>
</body>
</html>
)
}langはBCP 47タグで、キット内のすべてのIntlフォーマットを決めます("de-AT", "pt-BR", "en-GB"も使えます)。labelsがパックです。言語スイッチャーを作るなら、タグをstateに持ち、遅延importのマップからパックを選びます。プロバイダーは入れ子にできるので、ひとつの画面だけ別の言語で動かすこともできます。
パック
18言語、1言語1ファイル、全コンポーネントの全ラベル。スイッチャーに表示される現地語の名前:
locale-tr: Türkçelocale-de: Deutschlocale-fr: Françaislocale-es: Españollocale-it: Italianolocale-pt-BR: Português (Brasil)locale-nl: Nederlandslocale-pl: Polskilocale-ru: Русскийlocale-hi: हिन्दीlocale-id: Bahasa Indonesialocale-vi: Tiếng Việtlocale-th: ไทยlocale-ja: 日本語locale-ko: 한국어locale-zh-CN: 中文(简体)locale-ar: العربية (RTL)locale-he: עברית (RTL)
locale-enもあります。コンポーネントから生成され、他のすべてのパックはこれと照合されます。英語のラベルをアプリ全体で変えたいときにimportしてください。
RTL
コンポーネントは書字方向をDOMから読み取る(論理プロパティ、:dir(rtl)、反転したアイコン)ので、documentには自分で設定してください:<html lang="ar" dir="rtl">。プロバイダーは<html>には触れません。langからdirを導出する(ar、he、fa、urがRTL)だけで、必要なコンポーネントに渡し、dirを渡せば上書きできます。dirOf("ar")は自前のレイアウトコード向けにエクスポートされています。
Intlフォーマット
値をフォーマットするコンポーネント(number-flow、counter-up、stat-card、meter、sparkline-draw、data-grid、date-picker、number-input)はlocale propを受け取ります。未指定なら、"en-US"ではなくプロバイダーの言語になりました。明示したpropが優先されるのは変わりません。同じフォーマッターはフックから使えます:
import { useGooduiLocale } from "@/lib/goodui-locale"
const { lang, dir, formatNumber, formatDate, formatRelative, formatCurrency } = useGooduiLocale()
formatNumber(12345.6) // "12.345,6" in de
formatDate(booking.start) // "3 Kas 2026" in tr; pass Intl.DateTimeFormat options for other styles
formatRelative(-2, "hour") // "vor 2 Stunden"
formatCurrency(49, "EUR") // "49,00 €"インスタンスは言語とオプションごとにキャッシュされるので、render内で呼んでも問題ありません。Reactの外では、createFormatters(lang)が同じ4つの関数を返します。
ラベルを1つだけ上書き
どのコンポーネントでもlabels propはパックより優先されるので、1つのインスタンスだけ別の文言にできます。アプリ全体で変えるなら、パックをスプレッドします:
<Dialog labels={{ confirm: "Rezervasyonu iptal et" }} … /> {/* this dialog only */}
const labels = { ...tr, alert: { ...tr.alert, dismiss: "Kapat" } } // every alert
<GooduiLocaleProvider lang="tr" labels={labels}>値を取るラベルは関数なので、複数形も本物です:results: (n) => plural("pl", n, { one: "1 wynik", few: `${n} wyniki`, many: `${n} wyników`, other: `${n} wyniku` })。plural()はlib/goodui-localeに含まれ、Intl.PluralRulesをラップしています。
言語を追加
lib/goodui-locales/en.tsを新しいファイルにコピーして値を翻訳します。キーと関数のシグネチャはそのまま残してください。リポジトリ内のマニフェストlib/locales/labels-manifest.jsonには、すべてのキーの種類、パラメータ、使用箇所(aria-label、スクリーンリーダー、表示テキスト)が載っています。私たちのビルドではnode scripts/extract-labels.tsが走り、コンポーネントからlib/goodui-locales/en.tsを再生成して、どれかのパックにコンポーネント、キー、パラメータが欠けていれば失敗します。だから18のパックがコンポーネントから遅れることはありません。新しい言語のプルリクエストを歓迎します。
試す
CoreコンポーネントのPlaygroundには言語セレクトがあります。プレビューがその言語で再描画され(アラビア語とヘブライ語はRTL)、出力されるスニペットにプロバイダーが含まれます。どのプレビューページも?lang=tr(方向を強制するなら&dir=rtl)を受け付けます。例: /preview/c/pagination?lang=ar.
goodui Native
同じパックとマニフェストをReact Nativeキットにも予定しています(foundationのLocaleProvider、同じコンポーネントID)。それまでは、Nativeコンポーネントは文字列をpropsと画面ごとのlabelsオブジェクトで受け取ります。