Better TranslateHome
GitHub
Getting Started
  • Introduction
  • Mission
  • Installation
  • CLI
  • Skills
  • RTL
  • Changelog
Adapters
  • Core
  • React
  • Expo
  • Astro
  • MD & MDX
  • Next.js
  • TanStack Router

Core

@better-translate/core works in any TypeScript project. No framework dependency, no runtime requirement. The same config and the same API apply whether you're in Next.js, Astro, React, Bun, Node.js, a script, or any other TypeScript environment.

Adapters are extensions of core that add framework-specific helpers: locale-aware routing, React context, per-request helpers, etc. But everything is built on top of the same core.

When to use core directly

Use core without an adapter when you don't need framework-specific helpers. This includes servers, APIs, scripts, shared libraries, or any TypeScript environment where no adapter exists for your setup.

1. Install the package

npm install @better-translate/core

2. Create one translator file

Create src/i18n.ts:

ts
1import { configureTranslations } from "@better-translate/core";23const en = {4  home: {5    title: "Hello",6    description: "This is the English version.",7  },8} as const;910const es = {11  home: {12    title: "Hola",13    description: "Esta es la version en espanol.",14  },15} as const;1617export const translator = await configureTranslations({18  availableLocales: ["en", "es"] as const,19  defaultLocale: "en",20  fallbackLocale: "en",21  messages: { en, es },22});

3. Use the translator anywhere

ts
1import { translator } from "./i18n";23translator.t("home.title"); // "Hello"4translator.t("home.title", { locale: "es" }); // "Hola"5translator.t("home.description", { locale: "es" });

4. Add another locale later

ts
1const fr = {2  home: {3    title: "Bonjour",4    description: "Ceci est la version francaise.",5  },6} as const;78export const translator = await configureTranslations({9  availableLocales: ["en", "es", "fr"] as const,10  defaultLocale: "en",11  fallbackLocale: "en",12  messages: { en, es, fr },13});

Fallback behavior

If the active locale doesn't have a key, better-translate tries the fallback locale. If the fallback doesn't have it either, it returns the key string itself.

  • → Missing locale value → fallback locale value
  • → Missing fallback value → key string

Async loaders

Register locale loaders for languages you don't want to preload. Loaded locales are cached after the first successful load.

ts
1const translator = await configureTranslations({2  availableLocales: ["en", "fr"] as const,3  defaultLocale: "en",4  messages: { en },5  loaders: {6    fr: async () => import("./messages/fr").then((m) => m.default),7  },8});910// loads fr on demand and caches it11await translator.loadLocale("fr");

5. Auto-extract strings with the CLI

Instead of naming keys by hand, mark strings with { bt: true } and let the CLI extract and key them automatically:

ts
1import { t } from "@better-translate/core";23// Write the source string directly — CLI converts it to a proper key4t("Hello world", { bt: true });

Run npx bt extract to sync the strings into your source locale file and rewrite calls to proper keys. See the CLI docs for the full setup.

Continue with

  • React provider and hooks
  • Next.js App Router setup
  • Astro request helpers

Examples

  • core-elysia-example — plain TypeScript/Node.js setup