dialekt.
press 1 = laravel · 2 = paraglide · scroll for the readable version

llm cli · application translation

dialekt.

dialekt is a command-line tool that translates application strings with a large language model. It finds the keys that are missing from your target locale files, sends them to a model, and writes the translations back in the file format that your framework uses.

## what it does

When you add or edit a string in your source locale, the other locale files go out of sync. dialekt diffs every target locale against your source, detects the missing keys, and fills them with model-generated translations. It chunks large translation sets to stay under token limits, retries a chunk when the model returns malformed output, and writes the results back through an adapter for your framework. It does not touch keys that already exist.

01 · diff — scan the target, flag missing keys, translate, write
lang/en/auth.php · source
login'Log in'
logout'Log out'
forgot_password'Forgot your password?'
remember_me'Remember me'
lang/de/auth.php · target
login'Anmelden'
logout'Abmelden'
forgot_passwordmissing
remember_memissing
·

## the translation loop

Running dialekt translate puts every target locale through the same pipeline: diff it against the source, split the missing keys into chunks, send each chunk to the model, validate the response, and write the translations back through your framework's adapter. Chunks run concurrently, and a chunk that fails validation is retried with exponential backoff instead of aborting the run.

02 · the loop — every locale runs diff → chunk → model → write
dialekt translate · 4 target locales
diffchunkmodelwrite
de
·
fr
·
es
·
ja
·
·
03 · chunk — big files are cut into chunks and translated concurrently
lang/de/auth.php · 17 missing keys
chunk 1 · 6 keys
loginlogoutregisterforgot_passwordremember_meconfirm_password
chunk 2 · 6 keys
reset_passwordverify_emailalready_registeredsend_reset_linkthrottlefailed
chunk 3 · 5 keys
passwordemailnamesubmitcancel
04 · retry — malformed responses are rejected and retried with backoff
dialektmodel
chunk 2 · 6 keys → translate to de
✗ invalid JSON
backoff 1s
retry 1 · chunk 2
✗ keys missing from response
backoff 2s
retry 2 · chunk 2
✓ 6 translations · valid
✓ chunk 2 written → lang/de/auth.php

## commands

translate

Finds missing keys, chunks them, calls the model, and writes the results.

add

Inserts a new key in the source and translates it to every target locale.

missing

Lists every missing key without writing any files.

unused

Scans your source code and flags keys that nothing references.

validate

Exits with a non-zero code when any locale is missing keys, for CI.

languages

Prints the locales that each adapter detected.

## frameworks

dialekt reads and writes your translation files through an adapter. An adapter knows how to parse your framework's locale files, find the keys, and write the translations back.

## supported adapters

laravel

PHP array files (lang/{locale}/{domain}.php) and JSON locale files.

paraglide

Inlang message-format JSON (messages/{locale}.json).

json

Plain JSON locale files.

yaml

YAML locale files (.yml / .yaml).

xliff

XLIFF translation files (.xlf / .xliff).

po

GNU gettext .po files.

android

Android strings.xml resources.

ios

iOS .strings files.

arb

Flutter Application Resource Bundle (.arb).

csv

CSV locale tables.

properties

Java .properties files.

You can write an adapter for another framework by implementing one interface with four methods: listLocales, read, write, and findUsedKeys. See write your own adapter below.

## model providers

dialekt is built on the Vercel AI SDK, so any LLM provider with an AI SDK integration works. Configure a model in one of two ways:

A — provider + model id

model: { provider: "openai", modelId: "gpt-4o" },
model: { provider: "openrouter", modelId: "deepseek/deepseek-v4-flash" },
model: { provider: "anthropic", modelId: "claude-sonnet-4-20250514" },
model: { provider: "google", modelId: "gemini-2.5-flash" },

B — live Vercel AI SDK model

import { openai } from "@ai-sdk/openai";
import { createOpenAI } from "@ai-sdk/openai";

// any AI SDK factory works
export default defineConfig({
  model: openai("gpt-4o-mini"),
  // or bring your own OpenAI­compatible endpoint
  fastModel: createOpenAI({ baseURL: "https://your-proxy.com/v1" })("gpt-4o-mini"),
});

This means you can use providers like OpenAI, Anthropic, Google, Mistral, Groq, Together, Fireworks, DeepSeek, OpenRouter, Perplexity, xAI, and dozens more — just install the matching @ai-sdk/* package and pass the model.

## get started

1. install

npm install -D dialekt @dialekt/adapter-laravel

2. set an API key

dialekt gets its models through OpenRouter, so one key covers every provider. Put it in a .env file in your project root.

OPENROUTER_API_KEY=sk-or-...

3. configure

Create dialekt.config.ts in your project root. Point an adapter at your locale files, and load the key with env.

import { defineConfig } from "dialekt";
import { laravel } from "@dialekt/adapter-laravel";

export default defineConfig({
  env: [".env"],
  sourceLocale: "en",
  targetLocales: ["de", "fr", "es"],
  model: { provider: "openrouter", modelId: "anthropic/claude-opus-4" },
  adapters: [
    laravel({ langDir: "./lang", scanPaths: ["./app", "./resources/views"] }),
  ],
});

4. translate

npx dialekt translate

To use a different model, change modelId to any model OpenRouter lists — for example openai/gpt-4o or google/gemini-2.0-flash. You can also point a command at a second config with --config path/to/other.config.ts.

## write your own adapter

An adapter teaches dialekt how to read and write your framework's translation files. Implement the TranslationAdapter interface — four methods:

listLocales()

Return the locale codes that the adapter finds on disk.

read(locale)

Return all keys and their strings for a locale.

write(locale, entries)

Write translated keys back to the locale's files.

findUsedKeys()

Scan source code and return the keys that are referenced.

dialekt handles the rest — the diffing, chunking, retries, and model calls. The adapter only knows about files.

import type { TranslationAdapter } from "dialekt";

export function myFramework(): TranslationAdapter {
  return {
    name: "my-framework",
    async listLocales() {
      // read your locale directory, return ["en", "de", ...]
    },
    async read(locale) {
      // parse the locale's files, return a flat key → string map
    },
    async write(locale, entries) {
      // write the translated keys back in your format
    },
    async findUsedKeys() {
      // scan your source for translation calls, return the keys
    },
  };
}

Register it in your config's adapters array and dialekt treats it like a first-party adapter. See packages/adapter-laravel/src/adapter.ts for a full reference.