Skip to main content

Step 10: Settings, localisation, and validation

What we are building​

A small Patient settings screen, a persisted app-language preference, and a final validation checklist for registration, FINDRISC, Bluetooth measurement, history, and sign-out.

What you should already have​

  • The authenticated Patient app from steps 1–9.
  • Published English CMS translations.
  • A second approved app language available in CMS.
  • Sandbox accounts and a compatible TeleBGM meter for the device path.

The implementation​

Complete app-owned translations in Ovok CMS​

Move every string your app introduced into the CMS translations collection. Cover:

  • welcome, sign-in, registration, validation, and error copy;
  • screening home, questionnaire status, submit state, and result explanation;
  • device discovery, permission, connection, save, and retry states;
  • glucose values and units, history labels, Settings, and sign-out.

Publish a second language only after the product’s localization owner has supplied approved translations. The questionnaire itself is clinical content and must use an approved instrument translation; do not translate those questions as ordinary UI copy. The native system Bluetooth permission text also needs a reviewed platform-specific translation in app configuration.

See Use Ovok CMS with i18n for locale names, string fallback, public content, and the CMS translation lifecycle.

Persist a non-secret language preference​

Create src/localization/use-app-language.ts:

import AsyncStorage from "@react-native-async-storage/async-storage";
import { useEffect } from "react";
import { useTranslation } from "react-i18next";

const LANGUAGE_KEY = "ovok-findrisc-language";

export function useAppLanguage() {
const { i18n } = useTranslation();

useEffect(() => {
void AsyncStorage.getItem(LANGUAGE_KEY).then((language) => {
if (language && ["en", "de"].includes(language)) {
return i18n.changeLanguage(language);
}
});
}, [i18n]);

async function setLanguage(language: "en" | "de") {
await AsyncStorage.setItem(LANGUAGE_KEY, language);
await i18n.changeLanguage(language);
}

return { language: i18n.language, setLanguage };
}

Because CmsTranslations is mounted once at the root, changing the i18next language causes the Native SDK hook to load the corresponding published CMS locale. AsyncStorage contains only a language code, not a credential or health record.

Add the Settings screen​

Create app/(patient)/settings.tsx:

import { useSession } from "@ovok/native";
import { useRouter } from "expo-router";
import { useTranslation } from "react-i18next";
import { Button, Text, View } from "react-native";

import { useAppLanguage } from "../../src/localization/use-app-language";

export default function SettingsScreen() {
const router = useRouter();
const { logout } = useSession({ sessions: false });
const { language, setLanguage } = useAppLanguage();
const { t } = useTranslation("translation", { keyPrefix: "settings" });

async function signOut() {
await logout();
router.replace("/sign-in");
}

return (
<View>
<Text>{t("title", "Settings")}</Text>
<Text>{t("language", "Language")}: {language}</Text>
<Button title={t("english", "English")} onPress={() => void setLanguage("en")} />
<Button title={t("german", "Deutsch")} onPress={() => void setLanguage("de")} />
<Text>{t("devices", "Connected devices are managed in the Devices tab.")}</Text>
<Text>{t("data", "Screening answers and readings are stored in the Ovok project.")}</Text>
<Button title={t("signOut", "Sign out")} onPress={() => void signOut()} />
<Text>{t("about", "About this app")}</Text>
</View>
);
}

Publish the settings keys shown in the example in the CMS translations group for each app locale. The fallback text is for development only. The German app UI does not imply that a German FINDRISC Questionnaire is available: use only a separately approved instrument translation, or keep the clinical form in its approved source language. Keep Patient profile and consent screens limited to data and workflows that the project actually supports. Do not add alert, medication, diagnostic, or permission settings that this sample does not implement.

Validate the sandbox journey​

Run the scoring unit tests:

npm test -- --runInBand

Then exercise the complete app with synthetic data:

  1. Register a test Patient and sign in.
  2. Confirm the active project and Patient profile.
  3. Open the approved Questionnaire and verify its canonical URL, version, all stable linkIds, and answer ordering.
  4. Complete and submit the Questionnaire. Confirm a FHIR QuestionnaireResponse is created with the active Patient as subject.
  5. Check the calculated score against the clinical owner’s approved test fixtures and all category boundaries. A changed or unknown Questionnaire version must display no score.
  6. Use $populate only if approved prefill has been configured. Use $extract only if the Questionnaire’s supported extraction configuration and the project’s required feature are in place.
  7. Deny Bluetooth permission, then grant it. Confirm the screen explains how to recover.
  8. Pair TeleBGM, capture a reading, verify the normalized mg/dL value, and confirm the Observation belongs to the active Patient.
  9. Turn off network access during a save. The sample must show that an unsaved reading is not confirmed; it does not promise durable offline delivery.
  10. Confirm screening history and glucose history remain separate, then change language, restart the app, and sign out.

Important Ovok decisions​

  • Ovok CMS is the source for app-owned interface text; validated Questionnaire translations remain part of the reviewed clinical artifact.
  • The language preference is local UX state. It does not affect the FHIR resource language or change project authorization.
  • Standard FHIR responses are stored through the SDK and shown by resource type. The score is app-calculated from the reviewed response/questionnaire pair.
  • The sample does not enable the optional durable offline queue. If durable offline delivery is required, follow offline measurement saves and the Bluetooth background delivery guide, then test queue acknowledgement and duplicate delivery.
  • Before any real-patient use, complete the product’s clinical, privacy, regulatory, localization, and security review. This tutorial is not a clinical protocol.

Expected result​

The Patient can register, sign in, complete and revisit a FINDRISC assessment, pair TeleBGM, save and review blood-glucose readings, change the UI language, and sign out. The interface does not diagnose or recommend treatment.

Common errors and troubleshooting​

  • A language is selectable but remains English: publish the matching locale in the same CMS environment and wait for CMS cache updates.
  • Language resets after restart: check that AsyncStorage is installed and that useAppLanguage loads the saved supported locale.
  • A score changes unexpectedly: stop displaying it, compare Questionnaire URL/version/options with the reviewed release, and rerun approved scoring fixtures.
  • A queued measurement is described as saved: distinguish queued from saved; this tutorial does not configure a durable queue.
  • Bluetooth permission copy is untranslated: update the native config plugin text for each platform and rebuild.
  • A reading is treated as a diagnosis: remove that behavior. Neither one glucose reading nor this risk assessment establishes a diagnosis.

Previous / Next​

Previous: build results and history · Return to the tutorial overview