ローカライズ

キットの組み込み文字列すべて(77個のラベルセットにまたがる468個のラベル:aria-label、スクリーンリーダーの読み上げ、あなたが書いていないボタンのテキスト、プレースホルダー)を、ひとつのプロバイダーが翻訳します。言語パックと一緒に一度マウントすれば、すべてのgooduiコンポーネントがその言語で話し、数値・日付・通貨のフォーマットはIntlを通じて追従し、アラビア語とヘブライ語は書字方向も切り替わります。設定しないアプリは英語とen-USのフォーマットのままで、余計なものは何も読み込まれません。

インストール

npx shadcn@latest add https://goodui.dev/r/locale.json https://goodui.dev/r/locale-tr.json

localeはlib/goodui-locale.tsに置かれます(ラベルを持つコンポーネントはすべてこれに依存しているので、たいてい既に入っています)。パックはlib/goodui-locales/<lang>.tsに置かれ、他には何も依存しません。出荷する言語だけインストールしてください。

言語を設定

app/layout.tsx
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çe
  • locale-de: Deutsch
  • locale-fr: Français
  • locale-es: Español
  • locale-it: Italiano
  • locale-pt-BR: Português (Brasil)
  • locale-nl: Nederlands
  • locale-pl: Polski
  • locale-ru: Русский
  • locale-hi: हिन्दी
  • locale-id: Bahasa Indonesia
  • locale-vi: Tiếng Việt
  • locale-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オブジェクトで受け取ります。