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

CLI

Use @better-translate/cli when you want Better Translate to build and update locale files for you.

You do not need the CLI to use the runtime packages. It is optional.

1. Install the package

npm install -D @better-translate/cli

The CLI stays provider-agnostic. Your app installs and configures the AI SDK provider package directly.

2. Create a source locale file

Create src/messages/en.json:

json
1{2  "home": {3    "title": "Hello",4    "description": "Welcome to the app"5  }6}

You can also start with an empty {} and let bt extract populate it.

3. Create the CLI config

Create better-translate.config.ts:

ts
1import { createOllama } from "ollama-ai-provider-v2";2import { defineConfig } from "@better-translate/cli/config";34const ollama = createOllama({5  baseURL: process.env.OLLAMA_BASE_URL ?? "http://localhost:11434/api",6});78export default defineConfig({9  sourceLocale: "en",10  locales: ["es", "fr"],11  model: ollama("qwen3:4b"),12  providerOptions: {13    ollama: {14      think: true,15    },16  },17  messages: {18    entry: "./src/messages/en.json",19  },20});

If you use Ollama, install ollama-ai-provider-v2. If you use a hosted provider, install that provider package instead, such as @ai-sdk/openai, @ai-sdk/anthropic, or @ai-sdk/moonshotai.

The default Ollama API URL is local: http://localhost:11434/api.

This works the same with hosted providers such as OpenAI, Anthropic, and Moonshot AI. The CLI does not bundle provider helpers anymore.

4. Mark strings in your code

Instead of naming translation keys by hand, write the source text directly and add { bt: true }:

ts
1import { t } from "@better-translate/core";23export function navLabel() {4  return t("Home", { bt: true });5}

At runtime, { bt: true } returns the string unchanged. The CLI will replace these calls with proper keys on the next extract.

You can also pass other options like params — they are preserved after extraction:

ts
1// You write:2t("Hello world", { bt: true })3t("Hello {name}", { bt: true, params: { name: "" } })45// After bt extract rewrites the file:6t("components.nav.helloWorld")7t("components.nav.helloName", { params: { name: "" } })

The key namespace comes from the source file path (components/nav.tsx → components.nav). bt: true is always removed on rewrite.

5. Extract source keys

npx bt extract

This scans for t(..., { bt: true }) calls, adds the missing keys to your source locale file, and rewrites the calls to plain strict keys.

The CLI automatically finds better-translate.config.ts in your project root. The --config flag is only needed if your config file is in a different location.

6. Run the generator

npx bt generate

This creates the target locale files next to your source file.

If markdown.rootDir is enabled and the run would create or overwrite translated .md or .mdx files, the CLI asks for confirmation before making changes. Use --yes or -y to skip the prompt:

npx bt generate --yes

Non-interactive runs that need to write translated markdown files must pass --yes.

7. Use the generated files in your app

After the files exist, import them into your @better-translate/core config just like any hand-written locale file.

Markdown

If you also want localized markdown generation, add the markdown.rootDir option:

ts
1import { createOllama } from "ollama-ai-provider-v2";2import { defineConfig } from "@better-translate/cli/config";34const ollama = createOllama({5  baseURL: process.env.OLLAMA_BASE_URL ?? "http://localhost:11434/api",6});78export default defineConfig({9  sourceLocale: "en",10  locales: ["es", "fr"],11  model: ollama("qwen3:4b"),12  messages: {13    entry: "./src/messages/en.json",14  },15  markdown: {16    rootDir: "./content/docs",17  },18});

Examples

Full working examples are in the GitHub repo:

  • nextjs-example
  • react-vite-example
  • core-elysia-example