Translation Messages
Managing and using translation message files.
Translation messages in Raypx are organized as TypeScript objects in packages/i18n/src/messages/. Each supported locale has its own message file, and the AppMessages type is inferred from the English file to ensure type safety across all locales.
Message File Locations
The en-US.ts file is the source of truth for message keys. The AppMessages type is inferred from this file:
// packages/i18n/src/messages/index.ts
import type { SupportedLocale } from "../core/shared"
import enUS from "./en-US"
import zhCN from "./zh-CN"
export type AppMessages = typeof enUS
export const messages: Record<SupportedLocale, AppMessages> = {
"en-US": enUS,
"zh-CN": zhCN,
}Message Structure
Messages are organized as nested objects with dot-separated keys:
// packages/i18n/src/messages/en-US.ts
export default {
WelcomePage: {
title: "Welcome to Raypx",
subtitle: "Get started with your account",
},
Auth: {
signIn: "Sign In",
signOut: "Sign Out",
resetPassword: "Reset Password",
},
Dashboard: {
title: "Dashboard",
documents: "Documents",
settings: "Settings",
},
} satisfies AppMessagesLoading Messages
Use getMessages(locale) to load messages for a specific locale. If the requested locale is not found, English messages are returned as a fallback:
import { getMessages } from "@raypx/i18n"
const messages = getMessages("zh-CN")
console.log(messages.Auth.signIn) // "Sign In" (or Chinese equivalent)Using Translations in Components
Use the useTranslations hook from use-intl with a namespace:
import { useTranslations } from "use-intl"
function WelcomePage() {
const t = useTranslations("WelcomePage")
return (
<div>
<h1>{t("title")}</h1>
<p>{t("subtitle")}</p>
</div>
)
}Date and Number Formatting
Use getFormatter(locale) (via getRequestConfig) to format dates and numbers according to the locale's conventions:
import { getRequestConfig } from "@raypx/i18n"
const config = getRequestConfig("zh-CN")
// config.timeZone: "Asia/Shanghai"
// In a component, use the Intl.DateTimeFormat and Intl.NumberFormat APIs
// with the resolved timeZone from the request config.IntlProvider Setup
The IntlProvider from use-intl is configured at the root layout with the request config:
import { IntlProvider } from "use-intl"
import { getRequestConfig } from "@raypx/i18n"
export function RootLayout({ children }: { children: React.ReactNode }) {
const config = getRequestConfig(request)
return (
<IntlProvider locale={config.locale} messages={config.messages} timeZone={config.timeZone}>
{children}
</IntlProvider>
)
}Adding New Translation Keys
Add the new key to the English message file (packages/i18n/src/messages/en-US.ts). This is the source of truth and defines the AppMessages type.
Add the corresponding key to all other locale files (zh-CN.ts, etc.). TypeScript will warn you if any keys are missing since the type is inferred from en-US.ts.
Use the new key in your components with useTranslations:
const t = useTranslations("YourNamespace")
console.log(t("yourNewKey"))Since AppMessages is inferred from the English file, adding a key to en-US.ts without adding it to zh-CN.ts will cause a TypeScript error. This ensures all locales stay in sync.