Démarrage rapide
React + i18next
Installez le SDK, enveloppez votre app dans <SonentaProvider />, et appelez useTranslation(). Les clés manquantes remontent à votre tableau de bord automatiquement, aucun branchement supplémentaire.
1. Installer
Une seule dépendance. Pas d'acrobaties peer-dep, le SDK contient tout côté React.
terminal 1npm i @sonenta/react-i18next 2. Envelopper votre app
SonentaProvider prend un projectUuid et une defaultLocale ; votre clé d’API se passe dans la prop token. Il n’y a pas de détection automatique de la locale, defaultLocale est requis. Les namespaces sont chargés à la demande depuis le CDN, et les clés manquantes sont envoyées par lots, toutes les 5 secondes ou tous les 50 événements, au premier des deux.
main.tsx 1// src/main.tsx2import { SonentaProvider } from "@sonenta/react-i18next";3import { createRoot } from "react-dom/client";4import { App } from "./App"; 6createRoot(document.getElementById("root")!).render(7 <SonentaProvider8 projectUuid="proj_xxx"9 token={import.meta.env.VITE_SONENTA_TOKEN}10 defaultLocale="en"11 namespaces={["common"]}12 >13 <App />14 </SonentaProvider>15); Toutes les props de SonentaProvider
| Prop | Type | Défaut |
|---|---|---|
| projectUuid | string | obligatoire |
| defaultLocale | Locale | obligatoire |
| children | ReactNode | obligatoire |
| token | string | req. unless transport |
| namespaces | Namespace[] | ["common"] |
| defaultNS | Namespace | - |
| keySeparator | string | false | "." (auto-detected) |
| nsSeparator | string | false | ":" |
| apiBase | string | https://api.sonenta.dev |
| cdnBase | string | https://cdn.sonenta.com |
| fetchImpl | typeof fetch | global fetch |
| env | "prod" | "dev" | "prod" |
| version | string | "main" |
| versionSlug (deprecated) | string | - |
| missingHandler | "send" | "log" | "off" | "send" |
| transport | (batch: MissingKeyEvent[]) => … | built-in POST |
| flushIntervalMs | number | 5000 |
| flushBatchSize | number | 50 |
| missingEventsBufferSize | number | 200 |
| initialBundles | Record<Locale, Record<...>> | - |
| languageCatalog | LanguageMeta[] | - |
| disableLanguageCatalog | boolean | false |
| disableLanguageManifest | boolean | false |
| fallbackLng | Locale | Locale[] | - |
| surface | Surface | - |
| surfaceBreakpoints | SurfaceBreakpoints | boolean | - |
| a11ySurfaces | A11ySurface[] | [] |
| plainLanguage | boolean | false |
| plugins | SonentaPlugin[] | - |
| interpolation | { format?: (…) => string } | - |
-
tokenest requis sauf si vous fournissez votre propretransport. N’en passer aucun des deux lève une erreur au montage. Il n’authentifie que le POST des clés manquantes, la sonde de style de clé, et le fetch runtime enenv: "dev". - Sous
interpolation, seulformatest configurable.escapeValuevaut toujoursfalse, React échappe déjà. - Les variantes régionales retombent déjà sur leur base (
fr-CAversfr) sans configuration.fallbackLngs’ajoute après cette chaîne, il ne la remplace pas.
3. Utiliser le hook
useTranslation() retourne { t, i18n }. Forme familière si vous avez utilisé react-i18next. i18n.ready indique quand les namespaces initiaux sont hydratés ; i18n.changeLanguage() change la locale à l'exécution.
Checkout.tsx 1// src/Checkout.tsx2import { useTranslation } from "@sonenta/react-i18next"; 4export function Checkout() {5 const { t, i18n } = useTranslation("common"); 7 if (!i18n.ready) return null; // first paint after hydration 9 return (10 <button onClick={() => i18n.changeLanguage("fr")}>11 {t("checkout.review.confirm")}12 </button>13 );14} Ce que vous obtenez gratuitement
- Capture des clés manquantes. Toute clé que vous appelez sans qu'elle soit au dictionnaire est mise en file, debouncée (5s par défaut), et POST vers la file de votre dashboard. Sans risque en prod, votre fallback continue de s'afficher.
- Namespaces servis depuis le CDN. Les bundles de traduction sont tirés de
cdn.sonenta.comavec cache HTTP et stale-while-revalidate. Aucun bundling au build requis. - Détection auto de la locale. Si vous ne passez pas
defaultLocale, le SDK litnavigator.languageet retombe sur la valeur par défaut de votre projet. - Exports ouverts. Tout ce que vous pushez dans Sonenta, vous pouvez le ré-exporter en JSON i18next, XLIFF, ou PO. Changez d'outil demain sans réécrire votre code.
Trois pannes qui ne disent rien
Chacune laisse votre page parfaitement normale. Aucune ne lève d’erreur que vous remarquerez.
- Un token cassé n’avertit presque pas, et ne plante jamais. Ne passer ni
tokennitransportlève une erreur au montage. Un token présent mais ayant la forme d’une variable d’environnement non définie ("undefined","null") produit unconsole.warn. Ces deux gardes n’existent qu’à partir de@sonenta/react-i18next2.6.1 (@sonenta/i18n-core1.1.3) ; en dessous, rien n’est signalé. Et une chaîne vide, le?? ""qu’on écrit pour satisfaire TypeScript, n’est couverte par aucun avertissement, à aucune version. Dans tous les cas le serveur répond 401, le SDK dégrade en douceur, le CDN continue de servir, et votre application reste non authentifiée. Ne cherchez pasApiKey undefineddans vos logs : avec un?? ""c’est un faux négatif garanti. Regardez plutôt l’en-têteAuthorizationde la requête réseau dans votre build déployé. - Un namespace absent ressemble à un namespace vide. Les bundles de namespace viennent du CDN uniquement quand
envvaut"prod"; en"dev"ils viennent de l’API runtime authentifiée. Et un 404 se résout en bundle vide, sans erreur ni nouvelle tentative : un namespace que vous n’avez pas encore publié est donc indiscernable d’un namespace réellement vide. - Des surfaces a11y non déclarées retombent en silence. Les accesseurs d’accessibilité ne lisent que les surfaces demandées au chargement, via
a11ySurfaces. Sans elle, l’overlay n’est jamais téléchargé ett.aria(key)renvoie simplement le texte visible, sans erreur ni avertissement. Le symptôme n’est pas un plantage, c’est unaria-labelqui duplique le libellé d’à côté.
Transport custom (avancé)
Besoin de logger les clés manquantes dans votre propre stack d'observabilité, de les protéger derrière votre auth, ou de les stubber dans les tests ? Passez une fonction transport. Le SDK debounce et batche toujours ; vous décidez ce qu'on fait du batch.
main.tsx 1// custom transport, useful for tests, edge cases, or auditing2<SonentaProvider3 projectUuid="proj_xxx"4 token={import.meta.env.VITE_SONENTA_TOKEN}5 flushIntervalMs={2000}6 transport={(batch) => fetch("/internal/i18n-misses", {7 method: "POST",8 body: JSON.stringify(batch),9 })}10/>