Vite
best-i18n/vite — for Vite and everything built on it
The Vite plugin covers Vite itself and anything running on it: TanStack Start, React Router, SvelteKit, Astro. rolldown-vite keeps the Vite plugin API, so it uses this plugin unchanged.
// vite.config.ts
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { i18n } from 'best-i18n/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [
i18n({
messagesDir: fileURLToPath(new URL('./messages', import.meta.url)),
locales: ['en', 'zh'],
baseLocale: 'en',
// set (e.g. from an env var) to build a single locale as pure literals
staticLocale: process.env.I18N_STATIC_LOCALE,
}),
// ...other plugins
],
})The .po files under messagesDir are the source of truth — the plugin reads
them directly, no compile step in between. Editing a message file in dev
triggers a full reload.
With staticLocale set, the build inlines that one locale as plain string
literals — one deployable bundle per locale, each with zero i18n overhead. See
Writing messages for what compiles, and
Extract and translate for the catalog workflow.
TanStack Start
TanStack Start uses this plugin unchanged, with a request middleware and router URL rewriting on top. It has its own page: TanStack Start.
Svelte 5 and SvelteKit
Svelte runs on this same plugin with one extra option, svelte: true, plus a
few hooks on the SvelteKit side. It has its own page:
Svelte.
Solid and SolidStart v2
Solid runs on this same plugin with one extra option, solid: true, plus a
middleware and a router hook on the SolidStart side. It has its own page:
Solid.
Vue 3 and Nuxt 4
Vue runs on this same plugin with one extra option, vue: true; Nuxt gets a
module, best-i18n/nuxt, that adds the plugin and binds the locale per
request. Both have their own page: Vue.