Raypx

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 AppMessages

Loading 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.

On this page