First Working Translation In 5 Minutes
This guide is the shortest path to the good Palamedes feeling: write a message, extract it, translate it, and see it render without changing the mental model.
- one translated component
- one extraction run
- one
.poimport - one active runtime instance
It uses Vite plus React because that is the smallest copy-paste setup today.
The same Vite plugin, runtime model, and .po flow now also work with Solid
through @palamedes/solid and vite-plugin-solid.
1. Install the packages
pnpm add @palamedes/core @palamedes/react @palamedes/runtime @palamedes/vite-plugin
pnpm add -D @palamedes/cli @vitejs/plugin-react vite typescriptFor Solid, swap the host package pair:
pnpm add @palamedes/core @palamedes/solid @palamedes/runtime @palamedes/vite-plugin
pnpm add -D @palamedes/cli vite-plugin-solid vite typescript2. Add palamedes.yaml
locales: [en, de]
source-locale: en
catalogs:
- path: src/locales/{locale}
include: [src]3. Wire the Vite plugin
// vite.config.ts
import { defineConfig } from "vite"
import react from "@vitejs/plugin-react"
import { palamedes } from "@palamedes/vite-plugin"
export default defineConfig({
plugins: [palamedes(), react()],
})4. Register the runtime
// src/i18n.ts
import { createI18n } from "@palamedes/core"
import { setClientI18n } from "@palamedes/runtime"
const i18n = createI18n()
setClientI18n(i18n)
export { i18n }5. Add one translated component
// src/App.tsx
import { t } from "@palamedes/core/macro"
export function App() {
return <h1>{t`Welcome to Palamedes`}</h1>
}6. Extract catalogs
pnpm exec pmds extractYou should now have:
src/locales/en.posrc/locales/de.po
7. Add one translation
Open src/locales/de.po and change the translated string:
msgid "Welcome to Palamedes"
msgstr "Willkommen bei Palamedes"8. Load .po messages
TypeScript needs an ambient declaration for .po imports. Add it once:
// src/po.d.ts
declare module "*.po" {
import type { CatalogMessages } from "@palamedes/core"
export const messages: CatalogMessages
}// src/main.tsx
import React from "react"
import ReactDOM from "react-dom/client"
import { i18n } from "./i18n"
import { App } from "./App"
import { messages as enMessages } from "./locales/en.po"
import { messages as deMessages } from "./locales/de.po"
i18n.load("en", enMessages)
i18n.load("de", deMessages)
i18n.activate("de")
ReactDOM.createRoot(document.getElementById("root")!).render(<App />)Expected Result
After pnpm dev, the page should render:
Willkommen bei PalamedesThat proves the full local loop is working:
- macros transform correctly
- extraction works
- catalogs update correctly
.poimports compile- the runtime model is wired
From there, the same catalog flow can grow into CI audits, richer ICU diagnostics, and framework-specific app wiring without changing how messages are identified.