Integrations
TanStack Start
TanStack Start on the Vite plugin, with per-request locale middleware
TanStack Start runs on Vite, so it uses best-i18n/vite
unchanged, plus the plain server binding for SSR. This page is the wiring that
is specific to Start: the plugin order, a request middleware, and router URL
rewriting.
A full app is in
playground/tanstack-start.
// vite.config.ts
import process from 'node:process'
import { fileURLToPath } from 'node:url'
import { tanstackStart } from '@tanstack/react-start/plugin/vite'
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',
staticLocale: process.env.I18N_STATIC_LOCALE,
}),
tanstackStart(),
// react's plugin has to come after start's
],
})Wrap the request so every t below it sees the right locale — route
components, loaders, server functions — with no per-component call:
// src/start.ts
import {
createCsrfMiddleware,
createMiddleware,
createStart,
} from '@tanstack/react-start'
import { withRequestLocale } from 'best-i18n/server'
import { i18n } from './i18n'
const csrfMiddleware = createCsrfMiddleware({
filter: (ctx) => ctx.handlerType === 'serverFn',
})
const localeMiddleware = createMiddleware().server(({ next, request }) =>
withRequestLocale(request, i18n, () => next()),
)
export const startInstance = createStart(() => ({
requestMiddleware: [csrfMiddleware, localeMiddleware],
}))The route tree stays unprefixed. Strip /zh on the way in and put it back on
the way out, so a plain <Link to="/about"> renders /zh/about while Chinese
is active:
// src/router.tsx
import { deLocalizeUrl, localizeUrl } from 'best-i18n/locale-url'
import { getLocale } from 'best-i18n/runtime'
import { i18n } from './i18n'
createTanStackRouter({
routeTree,
rewrite: {
input: ({ url }) => deLocalizeUrl(url, i18n),
output: ({ url }) => localizeUrl(url, getLocale(), i18n),
},
})Resolve the client locale before hydration so the first paint matches SSR — see Server rendering.