Better Translatebetter-translate
  • Docs
  • CLI
  • Changelog
  • Docs
  • CLI
  • Changelog
GitHub
Same config. Hosted or local models

One i18n setup for any TypeScript projectOne i18n setup for any TypeScript project

Same config. Same API. Use AI Gateway or local Ollama models across Next.js, Astro, React, TanStack Router, and plain Node. No rewrites.

View docs
View on GitHub
Sponsor the project
translate.ts
export const landingTranslationsConfig = {
  availableLocales: ["en", "es"] as const,
  defaultLocale: "en",
  fallbackLocale: "en",
  messages: { en, es },
} as const;

const translator = await configureTranslations(landingTranslationsConfig);

const { t } = createTranslationHelpers(translator);

t("hero.title")                    // -> "One i18n setup for any TypeScript project."
t("hero.descriptionParam", {
  params: {
    param1: "value1",
  }
})              // -> localized copy param
t("header.language", {
  locale: "es"
})                                 // -> "Idioma"
t("Write source strings", { bt: true })  // -> auto-extracted & keyed by CLI

Same config everywhere

Switch frameworks without rewriting your i18n setup

TSTypeScriptbun add @better-translate/core
Astrobun add @better-translate/astro
Bunbun add @better-translate/core
Node.jsbun add @better-translate/core
Reactbun add @better-translate/react
Next.jsbun add @better-translate/nextjs
TanStack Routerbun add @better-translate/tanstack-router

Same setup. Every environment

The same setup, the same API, the same experience, no matter which TypeScript environment you're in.

Same Config, Every Environment

Write your translation config once. It works identically in Next.js, Astro, React, TanStack Router, and plain Node. Switch environments, keep your setup.

Type-Safe by Default

Full TypeScript inference on translation keys and interpolation variables. Typos and missing keys become compile errors.

Autocomplete Everywhere

Your editor knows every key in your messages object. No more guessing because `t("home.` starts completing instantly.

Locale Switching

Switch locales at runtime without a page reload. Per-call overrides let you render any locale on demand.

Hosted or local. Same CLI

Generate locale files with the same CLI whether you're using AI Gateway or local Ollama models.

better-translate.config.ts
import { createOllama } from "ollama-ai-provider-v2";
import { defineConfig } from "@better-translate/cli/config";

const ollama = createOllama({
  baseURL: process.env.OLLAMA_BASE_URL ?? "http://127.0.0.1:11434/api",
});

export default defineConfig({
  sourceLocale: "en",
  locales: ["es", "fr"],
  model: ollama("qwen3:4b"),
  providerOptions: {
    ollama: {
      think: true,
    },
  },
  messages: {
    entry: "./src/messages/en.json",
  },
});

Your framework, your choice

Your translation config works the same way in every TypeScript environment. Native adapters, identical API.

TS

TypeScript

Strong types, autocomplete, and compile-time feedback from your messages.

bun add @better-translate/core

Astro

Request-scoped helpers and localized Astro content collections for .md and .mdx.

bun add @better-translate/astro

Bun

Native Bun runtime support with zero extra setup.

bun add @better-translate/core

Node.js

Zero-dependency core for scripts, servers, and background jobs.

bun add @better-translate/core

React

Context, hooks, and locale-aware client rendering for React apps.

bun add @better-translate/react

Next.js

Server components, App Router, and route-aware locale helpers.

bun add @better-translate/nextjs

TanStack Router

Type-safe routing support for TanStack Router projects, including TanStack Start apps.

bun add @better-translate/tanstack-router
Better Translate
DocsGitHubSponsornpm

MIT License · built with TypeScript