Instruction file imported from Open-Earth-Foundation/CityCatalyst (
.cursor/rules/i18n.mdc). Copyright stays with the author.
i18n Patterns
Client-Side Translation
import { useTranslation } from "@/i18n/client";
export default function MyPage(props: { params: Promise<{ lng: string }> }) {
const { lng } = use(props.params);
const { t } = useTranslation(lng, "namespace");
// namespace maps to src/i18n/locales/en/namespace.json
return <Text>{t("my-key")}</Text>;
}
Namespaces
Each JSON file in src/i18n/locales/en/ is a namespace:
auth.json— login, signup, passworddashboard.json— main dashboard UIcommon.json— shared termsemails.json— email templates
Adding Translations
- Add the key to the English file first:
src/i18n/locales/en/<namespace>.json - Other languages are auto-translated via CI (
web-translate.yml) - Use descriptive, kebab-case keys:
"inventory-not-found","save-changes"
Key Format
{
"page-title": "My Page Title",
"description": "This is a description with {{count}} items",
"nested": {
"key": "Nested value"
}
}
Interpolation
t("description", { count: 5 })
// "This is a description with 5 items"
Supported Languages
en (fallback), de, es, fr, pt
ESLint
The project uses eslint-plugin-i18next — all user-facing strings in TSX must use t() instead of hardcoded text.