Skip to main content

Use Ovok CMS with i18next

Store app interface text in the Ovok CMS, then load the published translations into i18next when the app starts and when its language changes. Translators can update the strings in the Ovok Console without a new app release.

The SDK's useTranslations() hook loads the published translations collection into a nested object, and toCmsLocale() maps an application locale to a CMS locale. This guide uses those helpers with i18next. For CMS behavior and language rules, also see the platform's CMS i18n guide.

Prepare translation groups​

Enable CMS for the project, find its tenant code, and publish translations in the same environment the app reads. See the CMS overview for environment and access details.

In the Ovok Console, create one document in the translations collection per group of UI text, usually one group per screen or feature. For example:

FieldExample
slugsign-in
statuspublished
strings{ key: 'title', value: 'Sign in' } and { key: 'errors.required', value: 'Required' }

The group slug must not contain dots. Dots in a string key create nested objects: errors.required becomes errors.required in the i18next resource tree. Publish the document; drafts are not delivered. Add English text first, then add translations in the CMS-supported languages: de, en, fr, and es. A missing translated value falls back to English for that key.

If you reuse a shared group slug such as sign-in, your tenant's document replaces the shared group as a whole. Include every key your app needs from that group.

Load translations in a React app​

Install and configure i18next with react-i18next, then render a small loader component below OvokProvider. Set bindI18nStore: 'added' so React components update when the loader adds a resource bundle.

import i18n from 'i18next';
import * as React from 'react';
import { initReactI18next, useTranslation } from 'react-i18next';
import { toCmsLocale, useTranslations } from '@ovok/core';

i18n.use(initReactI18next).init({
lng: 'de-DE',
fallbackLng: 'en',
resources: {
en: { translation: { app: { name: 'My app' } } },
},
react: { bindI18nStore: 'added' },
});

export function CmsTranslations() {
const { i18n: currentI18n } = useTranslation();
const { data, loading, error, reload } = useTranslations({
tenantCode: 'your-tenant-code',
locale: currentI18n.language,
environment: 'staging',
});

React.useEffect(() => {
if (data) {
currentI18n.addResourceBundle(
toCmsLocale(currentI18n.language),
'translation',
data,
true,
false,
);
}
}, [data, currentI18n]);

React.useEffect(() => {
if (error) reportTranslationLoadError(error);
}, [error]);

if (loading) return <TranslationLoadingIndicator />;
if (error) return <button onClick={() => void reload()}>Retry</button>;
return null;
}

Render <CmsTranslations /> inside OvokProvider. The example's tenant code, reportTranslationLoadError(), and TranslationLoadingIndicator are application-provided. reload() is available when the app needs to retry a failed request.

useTranslations accepts tenantCode, locale, environment, and allowSignedOut. A signed-out screen needs tenantCode; allowSignedOut is on by default for the public translations collection. environment accepts dev, staging, or prod; if omitted, the API host's default environment is used.

Locale mapping and fallback​

The CMS currently supports the bare locale codes de, en, fr, and es, with English as its default. toCmsLocale() maps a regional language such as de-DE to de and maps an unsupported language to en. The hook applies this mapping when reading. Use the same helper when adding the response to i18next so the bundle is stored under the locale the CMS returned.

When the user changes from de-DE to de-CH, both map to de, so the hook does not need to fetch the same CMS language again. Changing to a different CMS language triggers a read. If your app adds a language, make sure the CMS contains that language first; until then, the app falls back to English.

For a given key, keep app-defined i18next strings as the highest-priority values, then add CMS strings for keys the app does not define. Configure fallbackLng to point to the English resources your app provides. The deep merge uses addResourceBundle(locale, 'translation', data, true, false), which keeps existing strings on conflicts.

Loading state, offline behavior, and caching​

Use loading, error, and reload to represent the request state in the app. Translation data is not persisted on the device by this hook. If the CMS cannot be reached, the hook reports an error and the app can continue with its own strings and available SDK defaults.

Published edits usually appear after the CMS cache expires, about 60 seconds, and can take longer behind a CDN. Removing a CMS key does not remove a bundle already merged into the running i18next instance. See the platform's CMS caching guide.

Keep CMS translations separate from project localization​

useTranslations reads the CMS translations collection. It does not call the project's separate localization API under /localization/ and /locales. Those systems store different strings and use different language lists and fallback rules. Choose one source for a given app workflow; see the platform's CMS i18n guide for the distinction.