Functional Specification: Multi-language Entity Binding & Mobile Deep-link Translation Routing
Last Updated: 16/07/2026
Type: Functional Specification ā Localization (i18n) & Routing
Scope: CMS Admin Panel (Translation Bindings) & Mobile App Navigation (Language Switcher)
Severity: š“ High ā Essential for international users; prevents navigation breakage when changing language in-app
Feedback Reference:
1. Overview & Business Requirementsā
The Golden Membership system serves multi-lingual customers (Vietnamese, English, Chinese, Korean, Japanese).
To ensure a seamless user experience:
- CMS Admin (Inline Translations): Admin should edit different language versions of the same banner, article, or event within the same form context. These translations must be bound together under a single group identifier.
- Mobile App (State Persistence on Translation): If a user is viewing a detail screen (e.g., an Article detail screen) and decides to switch the app language, the app must reload the current screen using the linked translation ID/slug. It must NOT crash, throw a 404, or force-exit the user back to the Home screen.
2. CMS Backend & Database Translation Architectureā
To link translations together, we use a Translation Group Model. Each article, event, or banner does not float independently; it is bound to a translation group:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Translation Group Card ā
ā (translationGroupId: 999) ā
āāāāāāāāāāāāāāāā¬āāāāāāāāāāāāāāāā
ā
āāāāāāāāāāāāāāāāāāāāāāāāā¼āāāāāāāāāāāāāāāāāāāāāāāā
ā¼ ā¼ ā¼
āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā
ā Locale: "vi" ā ā Locale: "en" ā ā Locale: "ko" ā
āāāāāāāāāāāāāāāāāā⤠āāāāāāāāāāāāāāāāāā⤠āāāāāāāāāāāāāāāāāāā¤
ā ID: 123 ā ā ID: 124 ā ā ID: 125 ā
ā Slug: uu-dai-he ā ā Slug: summer-pkgā ā Slug: summer-ko ā
āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā
2.1 Database Schema (Example)ā
interface TranslationGroup {
id: string;
type: 'article' | 'event' | 'banner';
createdAt: Date;
}
interface Article {
id: string;
translationGroupId: string; // ā
Links all translations together
locale: 'vi' | 'en' | 'zh' | 'ko' | 'ja';
title: string;
slug: string;
body: string;
// ...other fields
}
2.2 CMS Interface Requirementsā
- When editing a banner/article, changing the language dropdown (VI, EN, etc.) in the sidebar must save the current locale's fields and fetch the inputs for the selected locale within the same editing session (inline).
- If a translation does not exist yet for the selected language, show an empty form with an "Add Translation" button.
3. Mobile App Navigation & Translation Reloadingā
When the user changes the app language setting, the mobile app triggers a global language update. We must intercept this event to reload the active view parameters:
3.2 Dynamic Route Parameter Mappingā
Current Screen Stack: ArticleDetailScreen (params: { id: 123, slug: 'uu-dai-he' })
ā
User opens settings ā Change language to English ("en")
ā
App calls API: GET /api/translations/resolve?fromId=123&targetLocale=en
ā
API returns linked ID: { targetId: 124, targetSlug: 'summer-pkg' }
ā
App updates route params: navigate('ArticleDetail', { id: 124, slug: 'summer-pkg' })
ā
Current screen stays active and re-fetches the English content.
(User is NOT redirected to Home)
3.3 React Native Navigation Handler Exampleā
import React, { useEffect } from 'react';
import { useNavigation, useRoute } from '@react-navigation/native';
import { useLanguage } from '../context/LanguageContext';
export const ArticleDetailScreen = () => {
const route = useRoute();
const navigation = useNavigation();
const { currentLanguage } = useLanguage();
const { id } = route.params;
useEffect(() => {
const resolveAndSwitchTranslation = async () => {
try {
// Query the API to find the translation ID for the new language
const response = await api.resolveTranslationId({
currentId: id,
targetLocale: currentLanguage
});
if (response.targetId && response.targetId !== id) {
// Update the screen navigation stack in place with the correct translation ID
navigation.setParams({ id: response.targetId });
}
} catch (error) {
console.warn("Could not resolve translated entity ID", error);
// Fallback: stay on current id or handle gracefully. Do NOT force goBack() to Home.
}
};
resolveAndSwitchTranslation();
}, [currentLanguage]); // Triggers automatically when app language changes
// Fetch and render content normally based on route.params.id...
};
Technical Checklistā
CMS Backend & Database:
- Implement
translationGroupIdbinding on Article, Event, and Banner schemas. - Create a translation resolver endpoint:
GET /api/translations/resolve?fromId=<id>&targetLocale=<locale>. - Update the CMS save controller: ensure translating an entity updates/saves under the same
translationGroupIdrather than spawning unrelated items.
CMS Admin UI:
- Build the inline language selector panel. Tapping a new language must save current drafts and toggle local input fields inline.
Mobile App:
- Intercept language switch actions on detail screens (Articles, Events).
- Implement
navigation.setParams()or route updates to reload content with the matched translated ID instead of pushing to root/home. - Handle error states: if no translation exists for the target language, display the original version but wrap it in a notification banner (e.g. "This article is only available in Vietnamese").
- Validate on iOS and Android: open an article detail, change app language from settings, and confirm the details reload correct language content in place.