بداية سريعة
React + i18next
ثبّت SDK، ولفّ تطبيقك بـ <SonentaProvider />، ثم استدعِ useTranslation(). تنتقل المفاتيح الناقصة إلى لوحة التحكم تلقائياً, دون أي توصيلات إضافية.
1. التثبيت
تبعية واحدة فقط. لا حاجة لمعاناة peer-dep, يضم SDK كل ما يلزم على جانب React.
terminal 1npm i @sonenta/react-i18next 2. لفّ تطبيقك
SonentaProvider يأخذ projectUuid وdefaultLocale؛ ومفتاح الـ API يُمرَّر في الخاصية token. لا يوجد اكتشاف تلقائي للغة، وdefaultLocale مطلوب. تُحمَّل الـ namespaces عند الطلب من الـ CDN، وتُرسَل المفاتيح الناقصة على دفعات، كل 5 ثوانٍ أو كل 50 حدثاً، أيهما أسبق.
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); كل props الخاصة بـ SonentaProvider
| Prop | النوع | القيمة الافتراضية |
|---|---|---|
| projectUuid | string | مطلوب |
| defaultLocale | Locale | مطلوب |
| children | ReactNode | مطلوب |
| 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. استخدم الـ hook
يُعيد useTranslation() الكائن { t, i18n }. شكل مألوف لمن استخدم react-i18next. يخبرك i18n.ready متى اكتمل تحميل الـ namespaces الأولية، ويبدّل i18n.changeLanguage() اللغة في الـ 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} ما تحصل عليه مجاناً
- التقاط المفاتيح الناقصة. أي مفتاح تستدعيه وغير موجود في القاموس يُضاف إلى الطابور، يمر بـ debounce (افتراضياً 5 ثوانٍ)، ثم يُرسل POST إلى طابور missing في لوحة التحكم. آمن للإنتاج, يستمر عرض النص الاحتياطي.
- namespaces مُقدَّمة عبر CDN. تُجلب حِزم الترجمة من
cdn.sonenta.comمع تخزين HTTP المؤقت وstale-while-revalidate. لا حاجة لأي تجميع وقت البناء. - اكتشاف اللغة تلقائياً. إذا لم تمرّر
defaultLocale، يقرأ SDK قيمةnavigator.languageويرجع إلى لغة المشروع الافتراضية عند الإخفاق. - تصدير مفتوح. أي شيء ترسله إلى Sonenta يمكن تصديره مجدداً إلى JSON i18next أو XLIFF أو PO. بدّل أداتك غداً دون إعادة كتابة الكود.
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.
نقل مخصص (متقدم)
تحتاج إلى تسجيل المفاتيح الناقصة في منظومة الرصد الخاصة بك، أو حمايتها خلف المصادقة، أو محاكاتها في الاختبارات؟ مرّر دالة transport. يستمر SDK في تنفيذ debounce والتجميع، وأنت تقرر ما يحدث للدفعة.
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/>