Adding a New Locale
Step-by-step guide to adding support for a new language.
This guide walks through adding a new locale to Raypx. The process involves updating the app's i18n system and the docs i18n system separately.
Prerequisites
Before starting, choose a locale code that follows the BCP 47 format (e.g., fr-FR, ja-JP, ko-KR).
Steps
Update the routing configuration in packages/i18n/src/routing.ts:
export type SupportedLocale = "en-US" | "zh-CN" | "ja-JP"
export const routing = {
locales: ["en-US", "zh-CN", "ja-JP"] as const,
defaultLocale: "en-US" as SupportedLocale,
localeCookie: "raypx-locale",
localePrefix: "always" as const,
ignoredPathPrefixes: ["/api", "/__", "/llms"],
}
export const LOCALE_META: Record<SupportedLocale, LocaleMetadata> = {
"en-US": { code: "en-US", label: "English", nativeLabel: "English" },
"zh-CN": { code: "zh-CN", label: "Chinese (Simplified)", nativeLabel: "Simplified Chinese" },
"ja-JP": { code: "ja-JP", label: "Japanese", nativeLabel: "Japanese" },
}Also update LOCALE_TIMEZONE_MAP in packages/i18n/src/request.ts:
const LOCALE_TIMEZONE_MAP: Record<SupportedLocale, string> = {
"en-US": "America/New_York",
"zh-CN": "Asia/Shanghai",
"ja-JP": "Asia/Tokyo",
}Create the message file at packages/i18n/src/messages/ja-JP.ts by copying the English file and translating the values:
import type { AppMessages } from "./index"
const jaJP: AppMessages = {
WelcomePage: {
title: "Raypxへようこそ",
subtitle: "アカウントの設定を始めましょう",
},
Auth: {
signIn: "Sign In", // Translate as needed
signOut: "Sign Out",
resetPassword: "Reset Password",
},
// ... all keys from en-US.ts
} satisfies AppMessages
export default jaJPThen register it in packages/i18n/src/messages/index.ts:
import jaJP from "./ja-JP"
export const messages: Record<SupportedLocale, AppMessages> = {
"en-US": enUS,
"zh-CN": zhCN,
"ja-JP": jaJP,
}Update the Fumadocs i18n configuration in content/docs/source.config.ts (or equivalent Fumadocs config). Add the new locale to the i18n.locales array and provide navigation translations:
i18n: {
locales: ["en-US", "zh-CN", "ja-JP"],
defaultLocale: "en-US",
}Also add the navigation label for the new locale in the Fumadocs i18n dictionaries.
Create the docs directory for the new locale by copying the English docs:
mkdir -p content/docs/ja-JP
cp -r content/docs/* content/docs/ja-JP/Then translate the MDX files in content/docs/ja-JP/.
Test the new locale by navigating to /{new-locale}/ in the browser and verifying: the page renders with the translated messages, language switching works correctly, the raypx-locale cookie is set properly, and docs at /docs/{new-locale}/ render with translated content.
Run the type checker to verify all message keys are present:
pnpm run check-typesTypeScript will catch any missing keys in the new locale file since AppMessages is inferred from en-US.ts.
Completion Checklist
-
SupportedLocaletype updated inpackages/i18n/src/routing.ts -
routing.localesarray updated -
LOCALE_METAentry added withlabelandnativeLabel -
LOCALE_TIMEZONE_MAPentry added inpackages/i18n/src/request.ts - Message file created at
packages/i18n/src/messages/{locale}.ts - Message file registered in
packages/i18n/src/messages/index.ts - Fumadocs
i18n.localesupdated - Fumadocs navigation translations added
- Docs directory created at
content/docs/{locale}/ - All MDX files translated
-
pnpm run check-typespasses - Manual testing in browser succeeds