Skip to main content

Step 10: Complete localisation with Ovok CMS

What we are building​

The finished app loads all patient-facing UI text from published Ovok CMS translations documents. English and German values are authored in the Console; no app translation JSON files are created or bundled. Changing language with the Settings screen makes the Native SDK fetch the matching CMS locale and update i18next.

What you should already have​

  • CMS enabled for the sandbox project and LocalizationGate mounted in the root layout.
  • English text in the app translation group from step 3.
  • useTranslation() in the onboarding, measurement, device, and Settings screens.
  • LanguageSwitcher in Settings with en and de options.

The implementation​

Publish one translations document for each group​

In the Ovok Console, open the sandbox project's CMS and add the groups below to the built-in translations collection. Each row is one i18next key. Enter the English and German value for every key, then publish each group to staging.

Document slugKeys to add
apptitle, welcome, description
commoncontinue, retry
authsignInFailed, registrationFailed, checkEmailTitle, checkEmailForInvitation, sessionUnavailable
errorstryAgain
tabshome, devices, settings
readingstitle, devicePrompt, saving, saved, saveFailed, loadFailed, empty, preview, timeUnavailable, bloodPressure, bodyWeight, ecg, bloodPressureValue, pulseValue, weightValue, ecgDeviceResult, ecgWaveformUnavailable, ecgDisclaimer
devicestitle, intro, connected, notConnected, supportedDevice, battery, connectionProblem, lastUpload, noRecentUpload, addTitle, addDescription, noneNearby, pair, pairingCodePrompt, pairingCode, pairing, paired, remembered, pairingFailed, remove, catalogPrompt, openCatalog, status.Connected, status.Disconnected, status.Measuring, status.LowBattery, pairStatus.idle, pairStatus.pairing, pairStatus.code-required, pairStatus.paired, pairStatus.error
settingstitle, loading, profile, firstName, lastName, profileSaved, language, devices, manageDevices, privacyAndConsent, privacyDescription, privacyPolicy, consentDescription, notificationsNotConfigured, signOut, signOutFailed, appVersion
profilesave, form.error.network, form.error.generic
languagesenglish, german
sign-intitle, subtitle, email, password, button, forgot-password, dont-have-account, mfa.code, mfa.verify, errors.invalid-credentials, errors.unavailable, errors.network, errors.generic, form.email.invalid, form.email.required, form.password.required, form.password.min
registertitle, subtitle, name, surname, email, password, password-confirm, button, already-have-account, errors.network, errors.generic, form.email.invalid, form.email.required, form.confirm-password.required, form.confirm-password.mismatch, form.password.special-character, form.password.min, form.password.number, form.password.lowercase, form.password.uppercase, form.password.no-spaces, form.password.max, form.name.required, form.name.min, form.name.max, form.surname.required, form.surname.min, form.surname.max, clinician-invite.title, clinician-invite.message

The dots in a key create nested i18next paths. For example, status.Connected in the devices group becomes devices.status.Connected. Keep group slugs free of dots.

Here is a small example of the values to enter in the readings document:

KeyEnglish (en)German (de)
titleYour readingsIhre Messwerte
ecgECG recordingEKG-Aufzeichnung
ecgDeviceResultDevice-reported result: {{value}}Vom Gerät gemeldetes Ergebnis: {{value}}
ecgWaveformUnavailableWaveform is not available for this recording.Für diese Aufzeichnung ist keine Kurve verfügbar.
ecgDisclaimerDevice data for review; not a diagnosis.Gerätedaten zur Prüfung; keine Diagnose.
bloodPressureBlood pressureBlutdruck
bodyWeightBody weightKörpergewicht

Keep the i18next interpolation variable names value, systolic, and diastolic intact when translating interpolated strings. Use the clinical/product team's approved German wording for the rest of the catalog.

Add translations for the Native SDK authentication forms​

The sign-in and register groups intentionally use the Native SDK's group names. A tenant group with one of these slugs replaces the shared group as a whole. Add every key listed above that the forms use; otherwise omitted shared keys will no longer be available from that group. The SDK's built-in English strings remain the final fallback if a CMS group or key is missing.

Do not translate authentication errors into a promise that the account exists or that a login succeeded. Keep the meaning of the SDK-provided messages and validation requirements.

Change language from the app​

The Settings screen already calls i18n.changeLanguage(language). useCmsTranslations observes the active i18next language, requests the matching CMS locale, and merges that response into the translation namespace. The app does not fetch each group itself and does not need locale files or an API key.

Use the CMS language codes in the switcher: en and de. If the app requests a regional tag such as de-DE, the Native SDK maps it to the CMS locale de. The selection in this tutorial is in memory; persist it only if the application defines where patient language preferences belong.

The CMS returns published content only. A missing German value falls back to English field by field. The collection is public by default and the request includes the app's tenant code, so never store PHI, secrets, or tenant configuration as translation content. Published edits normally become visible after about a minute and may remain cached for several more minutes; see CMS caching.

Localize operating-system permission text separately​

App screens and the Ovok authentication components use CMS-backed i18next text. iOS and Android system permission prompts are native platform UI and cannot be changed by CMS or an over-the-air text update. Localize the iOS Bluetooth usage description in the native app configuration for each supported system language and rebuild the app. Localize the in-app explanation shown before Android's permission prompt through CMS.

Important Ovok decisions​

  • Store application translations in CMS, not in local JSON or other bundled translation catalogs.
  • Publish every group in the same sandbox environment the app requests (staging here).
  • A group named sign-in or register replaces the shared group whole; keep the full set of keys required by the SDK forms.
  • Missing CMS translation values fall back to English. A CMS outage is different: the root LocalizationGate shows its retry state rather than rendering a screen full of untranslated keys.
  • CMS translations are public tenant content. Never place patient-specific or otherwise confidential information in them.
  • The CMS hook refetches on language changes, but cached published content can take several minutes to update after an edit.
  • The ECG viewer shows device waveform samples and a source-reported label. Translating its surrounding UI does not add clinical interpretation.

Expected result​

On launch, the app waits for its first CMS translation response. Sign-in, registration, onboarding feedback, blood-pressure/ECG/weight cards, device pairing, and Settings use published English or German text. Choosing another language in Settings triggers a CMS locale read and updates the UI without shipping a new native binary.

Common errors and troubleshooting​

  • The app stays on the translation loading screen: confirm CMS is enabled and each required group is published to sandbox staging for the configured tenant code.
  • One section displays raw keys: check that a translation document's slug matches the group name, that the key spelling matches the t() call, and that the group is published.
  • Sign-in or registration labels are missing: make sure your sign-in or register group contains the full set of required keys; each tenant group replaces the shared group whole.
  • German falls back to English: verify the German values are set on the published CMS strings and the app selects de.
  • A recent edit has not appeared: allow for CMS and CDN caching, then retry the translation request.
  • System permission copy is still English: update native localized permission resources and rebuild; the CMS cannot change OS-owned prompts.

Tutorial complete​

You now have an Expo patient app that registers and authenticates through Ovok, pairs the supported BP2 and F4 devices, saves blood-pressure, ECG, and weight readings, loads recent observations, renders available ECG waveform samples, manages paired hardware and profile settings, and loads its English and German UI text from Ovok CMS.

Continue with the deeper references for Native SDK, Bluetooth, supported devices, authentication, Access Policies, ECG measurements, blood pressure, body weight, CMS, and CMS-backed i18n.