Better Translation

Loading messages

Import loadMessages from the virtual module and pass its result to TranslateProvider.

The Vite plugin generates the virtual better-translation/messages module from your plugin config. Import loadMessages from that module to load a flat lookup id map for a Locale, then pass that map to TranslateProvider.

Everything below TranslateProvider can use the framework runtime helpers such as T, Var, useT, or getT.

messages.ts
import { loadMessages, locales, type Locale } from "better-translation/messages"

const messages = await loadMessages("es")
// { "m_abc123": "Pagar ahora", ... }

loadMessages has the same API in every mode. The difference is baked into the generated virtual module by the plugin:

Runtime configWhat loadMessages(locale) does
local + target: moduleImports generated JSON from your app source with Vite module imports.
local + target: publicFetches generated JSON from Vite public assets.
remoteFetches the hosted Runtime bundle for the resolved Project Branch.

App setup

Load messages before rendering the provider so the active Locale and its Runtime bundle are available to translated content.

vite.config.ts
betterTranslation({
  locales: ["en", "es", "fr"],
  defaultLocale: "en",
})
src/routes/__root.tsx
import { createRootRoute, Outlet } from "@tanstack/react-router"

import { loadMessages } from "better-translation/messages"
import { TranslateProvider } from "better-translation/react"

import { getLocale } from "./-locale"

export const Route = createRootRoute({
  beforeLoad: async () => {
    const locale = await getLocale()
    const messages = await loadMessages(locale)

    return { locale, messages }
  },
  component: RootComponent,
})

function RootComponent() {
  const { locale, messages } = Route.useRouteContext()

  return (
    <TranslateProvider locale={locale} messages={messages}>
      <Outlet />
    </TranslateProvider>
  )
}

One config, one loader

You do not keep separate state between the Vite plugin and app runtime code. The plugin config is the source for the generated better-translation/messages module, and your app imports that module. Change the runtime target in vite.config.ts, restart Vite, and the generated loader changes while your app code can keep calling loadMessages(locale).

In local development, TranslateProvider uses the active locale to apply completed translations through Vite HMR. The authored fallback remains visible while translation is in progress, then the translated value replaces it without a page reload or component remount.

On this page