Localisation
Chaque chaîne intégrée au kit (468 libellés répartis en 77 jeux de libellés : aria-labels, annonces pour lecteurs d’écran, texte des boutons que vous n’avez pas écrits, placeholders) est traduite par un seul provider. Montez-le une fois avec un pack de langue et chaque composant goodui parle cette langue ; les formats de nombres, de dates et de devises suivent via Intl, et l’arabe et l’hébreu reçoivent leur sens de lecture. Les apps qui ne le définissent jamais restent en anglais avec les formats en-US, sans rien charger de plus.
Installation
npx shadcn@latest add https://goodui.dev/r/locale.json https://goodui.dev/r/locale-tr.jsonlocale atterrit dans lib/goodui-locale.ts (chaque composant avec des libellés en dépend déjà, vous l’avez donc sûrement). Un pack atterrit dans lib/goodui-locales/<lang>.ts et ne dépend de rien d’autre ; n’installez que les langues que vous livrez.
Définir la langue
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 est un tag BCP 47 et pilote chaque format Intl du kit ("de-AT", "pt-BR", "en-GB" conviennent). labels est le pack. Pour un sélecteur de langue, gardez le tag dans un state et choisissez le pack dans une map d’imports lazy ; les providers imbriqués fonctionnent, un écran peut donc tourner dans une autre langue.
Packs
18 langues, un fichier chacune, chaque libellé de chaque composant. Noms natifs tels qu’un sélecteur les afficherait :
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 existe aussi : il est généré depuis les composants et sert de référence pour vérifier tous les autres packs. Importez-le pour changer les libellés anglais dans toute l’app.
RTL
Les composants lisent le sens d’écriture dans le DOM (propriétés logiques, :dir(rtl), icônes retournées), définissez-le donc vous-même sur le document : <html lang="ar" dir="rtl">. Le provider ne touche jamais à <html> ; il dérive seulement dir de lang (ar, he, fa, ur sont RTL) pour les composants qui le demandent, et vous pouvez passer dir pour le forcer. dirOf("ar") est exporté pour votre propre code de layout.
Formats Intl
Les composants qui formatent des valeurs (number-flow, counter-up, stat-card, meter, sparkline-draw, data-grid, date-picker, number-input) acceptent une prop locale. Non définie, elle vaut désormais la langue du provider plutôt que "en-US" ; une prop explicite l’emporte toujours. Les mêmes formateurs sont à vous via le hook :
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 €"Les instances sont mises en cache par langue et par options, les appeler dans le render ne pose donc aucun problème. Hors React, createFormatters(lang) renvoie les quatre mêmes fonctions.
Surcharger un libellé
La prop labels de n’importe quel composant l’emporte toujours sur le pack, une instance isolée peut donc dire autre chose. Pour un changement dans toute l’app, faites un spread du pack :
<Dialog labels={{ confirm: "Rezervasyonu iptal et" }} … /> {/* this dialog only */}
const labels = { ...tr, alert: { ...tr.alert, dismiss: "Kapat" } } // every alert
<GooduiLocaleProvider lang="tr" labels={labels}>Les libellés avec des valeurs sont des fonctions, les pluriels sont donc de vrais pluriels : results: (n) => plural("pl", n, { one: "1 wynik", few: `${n} wyniki`, many: `${n} wyników`, other: `${n} wyniku` }). plural() est livré dans lib/goodui-locale et encapsule Intl.PluralRules.
Ajouter une langue
Copiez lib/goodui-locales/en.ts dans un nouveau fichier et traduisez les valeurs ; conservez les clés et les signatures des fonctions. Le manifeste, lib/locales/labels-manifest.json dans le repo, liste chaque clé avec son type, ses paramètres et son usage (aria-label, lecteur d’écran, texte visible). Notre propre build lance node scripts/extract-labels.ts, qui régénère lib/goodui-locales/en.ts depuis les composants et échoue dès qu’un pack manque un composant, une clé ou un paramètre : les 18 packs ne peuvent donc jamais prendre de retard sur les composants. Les pull requests avec de nouvelles langues sont les bienvenues.
Essayez
Le Playground de chaque composant Core a un sélecteur de langue : l’aperçu se réaffiche dans cette langue (RTL pour l’arabe et l’hébreu) et le snippet affiché inclut le provider. Toute page d’aperçu accepte ?lang=tr (et &dir=rtl pour forcer un sens), par ex. /preview/c/pagination?lang=ar.
goodui Native
Les mêmes packs et le même manifeste sont prévus pour le kit React Native (un LocaleProvider dans foundation, les mêmes ids de composants) ; d’ici là, les composants Native reçoivent leurs chaînes via des props et des objets labels par écran.