Szybki start
React + i18next
Zainstaluj SDK, opakuj aplikację w <SonentaProvider /> i wywołaj useTranslation(). Brakujące klucze trafiają do panelu automatycznie, bez dodatkowego okablowania.
1. Instalacja
Jedna zależność. Bez akrobacji peer-dep, SDK zawiera wszystko po stronie React.
terminal 1npm i @sonenta/react-i18next 2. Opakuj aplikację
SonentaProvider przyjmuje projectUuid i defaultLocale; klucz API przekazujesz w propsie token. Nie ma automatycznego wykrywania locale, defaultLocale jest wymagany. Namespacy są ładowane na żądanie z CDN, a brakujące klucze są wysyłane partiami, co 5 sekund lub co 50 zdarzeń, zależnie od tego, co nastąpi pierwsze.
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); Wszystkie propsy SonentaProvider
| Prop | Typ | Domyślnie |
|---|---|---|
| projectUuid | string | wymagane |
| defaultLocale | Locale | wymagane |
| children | ReactNode | wymagane |
| 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 } | - |
-
tokenis required unless you supply your owntransport. Passing neither throws at mount. It authenticates only the missing-key POST, the key-style probe, and the runtime fetch inenv: "dev". - Only
formatis configurable underinterpolation.escapeValueis alwaysfalse, because React escapes already. - Regional variants already fall back to their base (
fr-CAtofr) with no configuration.fallbackLngis appended after that chain, it does not replace it.
3. Użyj hooka
useTranslation() zwraca { t, i18n }. Znajomy kształt, jeśli używałeś react-i18next. i18n.ready mówi, kiedy początkowe namespacy są zhydratowane; i18n.changeLanguage() zmienia locale w runtime.
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} Co dostajesz za darmo
- Wyłapywanie brakujących kluczy. Każdy wywołany klucz spoza słownika trafia do kolejki, jest debounced (domyślnie 5s) i wysyłany POST-em do kolejki braków w panelu. Bezpieczne na produkcji, twój fallback dalej się renderuje.
- Namespacy z CDN. Paczki tłumaczeń pobierane są z
cdn.sonenta.comz cache'owaniem HTTP i stale-while-revalidate. Bez bundlowania w buildzie. - Auto-detekcja locale. Jeśli nie podasz
defaultLocale, SDK czytanavigator.languagei wraca do domyślnej wartości projektu. - Otwarte eksporty. Cokolwiek wypchniesz do Sonenta, możesz wyeksportować z powrotem jako JSON i18next, XLIFF lub PO. Zmień narzędzie jutro bez przepisywania kodu.
Three failures that stay silent
Each of these leaves your page looking perfectly fine. None of them raises an error you will notice.
- A broken token barely warns, and never throws. Passing no
tokenand notransportthrows at mount. A token that is present but shaped like an unset environment variable ("undefined","null") produces aconsole.warn. Both guards exist only from@sonenta/react-i18next2.6.1 (@sonenta/i18n-core1.1.3); below that, nothing is reported at all. And an empty string, the?? ""you write to satisfy TypeScript, is covered by no warning at any version. In every case the server returns 401, the SDK degrades gracefully, the CDN keeps serving, and your app stays unauthenticated. Do not grep your logs forApiKey undefined: with?? ""that is a guaranteed false negative. Read theAuthorizationheader of the network request in your deployed build instead. - A missing namespace looks like an empty one. Namespace bundles are fetched from the CDN only when
envis"prod"; in"dev"they come from the authenticated runtime API instead. And a 404 resolves to an empty bundle, with no error and no retry, so a namespace you have not published yet is indistinguishable from one that is genuinely empty. - Undeclared a11y surfaces fall back quietly. The accessibility accessors only read surfaces you asked for at load time, via
a11ySurfaces. Without it the overlay is never downloaded andt.aria(key)simply returns the visible text, with no error and no warning. The symptom is not a crash, it is anaria-labelthat duplicates the label next to it.
Własny transport (zaawansowane)
Chcesz logować brakujące klucze do własnego stacka obserwowalności, schować je za swoją autoryzacją albo zastubować w testach? Podaj funkcję transport. SDK dalej debounce'uje i batchuje; ty decydujesz, co dzieje się z batchem.
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/>