Recipe
i18n key namespacing & organization
A scalable convention for structuring translation keys across pages, components, and shared UI.
Namespace hierarchy
common:
actions:
save: "Save"
cancel: "Cancel"
delete: "Delete"
errors:
generic: "Something went wrong"
network: "Network error"
pages:
dashboard:
title: "Dashboard"
welcome: "Welcome back, {name}"
settings:
title: "Settings"
billing:
title: "Billing"
components:
modal:
confirm_title: "Are you sure?"
confirm_body: "This action cannot be undone."Rules
- common — shared across the entire app (buttons, errors, dates)
- pages — one subtree per route, mirroring the URL structure
- components — reusable UI blocks, named after the component
- Never nest deeper than 4 levels
- Use snake_case for all keys
- Placeholder syntax:
{variable}
Usage example
import { useTranslation } from "react-i18next";
function DashboardGreeting({ name }: { name: string }) {
const { t } = useTranslation();
return <h1>{t("pages.dashboard.welcome", { name })}</h1>;
}Tip: Run a lint rule that flags any key not matching common.* | pages.* | components.* to prevent ad-hoc keys from creeping in.