lokit is a universal localization manager with AI-powered translation. It supports gettext PO, po4a documentation, i18next JSON, vue-i18n JSON, Android strings.xml, YAML, Markdown, Java .properties, Flutter ARB, JS-KV, desktop entries, and polkit policy files configured via lokit.yaml.
- Config-first workflow —
lokit.yamlis required and acts as the single source of truth - Multi-target support — one config can define many translation targets across different formats
- AI translation — 8 providers including GitHub Copilot, Gemini, OpenAI, Ollama, and more
- Translation statistics — per-target progress tracking
- Smart PO management — extract, merge, update with
xgettextandmsgmerge - Native auth flows — GitHub Copilot (device code), Gemini (browser), and OpenAI (browser OAuth or device code)
- Parallel translation — concurrent API requests with configurable chunking
| Format | Extension | Use case |
|---|---|---|
| gettext | .po / .pot |
Source code strings (shell, Python, C, Go) |
| po4a | .po + po4a.cfg |
Documentation / manpages |
| i18next | .json |
Web apps with i18next |
| vue-i18n | .json |
Vue apps with nested JSON locales |
| android | strings.xml |
Android resource files |
| yaml | .yaml / .yml |
YAML key-value translations |
| markdown | .md |
Markdown document translation |
| properties | .properties |
Java application translations |
| flutter | .arb |
Flutter Application Resource Bundle |
| js-kv | .js |
JavaScript assignment key-value translations |
| desktop | .desktop |
freedesktop desktop entry translations |
| polkit | .policy |
PolicyKit XML policy translations |
| Provider | Auth |
|---|---|
| GitHub Copilot | OAuth (device code) |
| Gemini Code Assist | OAuth (browser) |
| Google AI (Gemini) | API key |
| Groq | API key |
| OpenCode | API key (optional) |
| OpenAI | browser OAuth, device code, or API key |
| Ollama | none (local) |
| Custom OpenAI | API key |
curl -fsSL https://raw.githubusercontent.com/minios-linux/lokit/refs/heads/master/install.sh | bashgit clone https://github.com/minios-linux/lokit.git
cd lokit
make buildgo install github.com/minios-linux/lokit@latestlokit versionCreate lokit.yaml:
source_lang: en
languages: [ru, de]
targets:
- name: app
format: i18next
dir: public/translations
pattern: "{lang}.json"# Check project structure
lokit status
# Extract strings and create PO files
lokit init
# Authenticate
lokit auth login --provider copilot
# Translate all languages
lokit translate --provider copilot --model gpt-4.1Create a lokit.yaml in the project root:
languages: [de, es, fr, ru]
source_lang: en
targets:
- name: app
format: gettext
dir: po
- name: docs
format: po4a
root: manpages
config: po4a.cfg
- name: website
format: i18next
root: submodules/site
dir: public/translations
languages: [de, es, fr, pt-BR, ru]
- name: mobile
format: flutter
dir: lib/l10nThen:
lokit status # Shows all targets with stats
lokit translate --provider copilot --model gpt-4o # Translates everythinglokit.yaml is required. lokit uses it as the sole source of truth.
A JSON Schema is available for editor autocompletion and validation.
To enable it in VS Code, add to the top of your lokit.yaml:
# yaml-language-server: $schema=./lokit.schema.jsonReference:
# Default languages for all targets
languages: [de, es, fr, id, it, pt, pt-BR, ru]
# Source language (default: en)
source_lang: en
# Optional default provider for `lokit translate`
provider:
id: copilot
model: gpt-4o
# base_url is supported for custom-openai and ollama only
# base_url: http://localhost:11434
# prompt: "Translate to {{targetLang}} with concise style."
# settings:
# temperature: 0.3
# Translation targets
targets:
- name: my-app # Display name (required)
format: gettext # Format (required, see below)
root: . # Working directory relative to config (default: .)
# --- gettext options ---
dir: po # Base directory for this target (required)
pot: messages.pot # POT template filename in dir (required)
sources: [src/**/*.sh] # Source globs for xgettext
keywords: [_, N_, gettext] # xgettext keywords
# --- po4a options ---
config: po4a.cfg # po4a config path relative to root
# --- i18next / vue-i18n options ---
dir: public/translations # JSON directory
pattern: "{lang}/common.json" # Required per-language file layout
# --- android options ---
dir: app/src/main/res # Android res/ directory
# --- yaml / properties / flutter / js-kv options ---
dir: translations # Files directory
pattern: "locale_{lang}.yaml" # Required for yaml/properties/flutter/js-kv
# --- markdown options ---
dir: docs/translations # Files stored under dir/LANG/
# --- overrides ---
languages: [de, es, fr] # Override global language list
source_lang: en # Override source language
prompt: "Custom prompt" # Override system prompt for AIgettext — For code translation (shell, Python, C, Go). Reads .pot templates, translates to .po files.
po4a — For documentation (manpages, AsciiDoc). Works with po4a.cfg and its PO directory.
i18next — Flat JSON key/value translations with optional _meta and translations sections.
vue-i18n — For Vue applications with nested JSON locale files (for example buttons.save: "Save" in JSON object form).
For source-backed key/value formats (vue-i18n, yaml, properties, flutter, js-kv, markdown),
lokit translates only keys that have non-empty source text. Keys with missing/empty source
values are skipped (for example optional fields like longDescription that are absent in source records).
android — For Android applications. Translates strings.xml resource files.
yaml — For YAML key-value translation files. Define pattern (example: {lang}.yaml).
markdown — For Markdown document translation. Files organized as dir/LANG/file.md.
properties — For Java .properties files. Define pattern (example: messages_{lang}.properties).
flutter — For Flutter ARB files. Define pattern (example: app_{lang}.arb).
js-kv — JavaScript key/value files (for example window.i18n = { ... }). Define pattern (example: {lang}.js).
desktop — freedesktop .desktop files with per-language fields in one file.
polkit — PolicyKit .policy XML files with per-language localized tags in one file.
For file-per-language targets (i18next, vue-i18n, yaml, properties, flutter, js-kv),
you must define pattern.
patternis relative todir- it must contain
{lang} - examples:
{lang}.json,{lang}/common.json,locale_{lang}.properties,app_{lang}.arb
targets:
- name: frontend
format: i18next
dir: frontend/src/i18n
pattern: "{lang}/common.json"
- name: java
format: properties
dir: src/main/resources/i18n
pattern: "messages_{lang}.properties"For catalog-style projects (one source index file + many per-record translation files),
source can be an object instead of a string.
source.indexpoints to the source index filesource.records_pathselects the records array ($or$.field)source.key_fieldprovides values for{id}inpattern/targetsource.fieldslists translatable fields copied from each record
Example (minios-store style):
targets:
- name: recipes
format: vue-i18n
root: web/public/data
dir: recipe-translations
pattern: "{lang}/{id}.json"
languages: [de, es, fr]
source:
index: recipes.json
records_path: "$"
key_field: id
fields: [name, description, longDescription]In index mode, lokit writes flat JSON objects per record/language and skips missing or empty source fields.
Notes:
patternortargetmust include{id}in index mode.--target recipesselects all expanded records likerecipes/<id>.- You can still target a single record with
--target recipes/<id>.
Shows project info and translation statistics for targets defined in lokit.yaml.
lokit status # Current directory
lokit status --root ./my-project # Specific projectExtracts translatable strings and creates/updates translation files:
lokit init # All languages
lokit init --lang ru,de # Specific languages- Runs
xgettextfor gettext projects - Runs
po4a --no-translationsfor po4a projects - Creates missing language files for i18next, vue-i18n, yaml, properties, flutter, js-kv
- In index mode, creates per-record files from
source.indexfor each target language - Idempotent — safe to run repeatedly
Translates using AI:
lokit translate --provider copilot --model gpt-4o
# All flags:
--provider string AI provider (or set provider.id in lokit.yaml)
--model string Model name (or set provider.model in lokit.yaml)
--lang, -l string Languages (comma-separated, default: all untranslated)
--parallel[=N] Enable parallel translation (default workers: 3)
--chunk int Entries per API request (0 = all at once)
--all, -a Translate all entries, including already translated ones
--fuzzy Translate fuzzy entries (default: true)
--dry-run Show what would be translated
--force, -f Ignore lock file, re-translate all entries
--prompt string Custom system prompt ({{targetLang}}/{{sourceLang}} placeholders)
--proxy string HTTP/HTTPS proxy URL
--api-key string API key (or provider env var)
--base-url string Custom API endpoint (custom-openai, ollama)
--timeout duration Request timeout (0 = provider default)
--retries int Retries on rate limit (default: 3)
--delay duration Delay between translation requests
--verbose, -v Detailed loggingManage provider credentials:
# Interactive login
lokit auth login
# Specific provider
lokit auth login --provider copilot
lokit auth login --provider google
# List stored credentials
lokit auth list
# Remove credentials
lokit auth logout --provider copilot
lokit auth logout # Remove allShow version, commit hash, and build date.
# lokit.yaml
languages: [de, es, fr, id, it, pt, pt-BR, ru]
targets:
- name: scripts
format: gettext
dir: po
pot: messages.pot
- name: manpages
format: po4a
root: manpages
config: po4a.cfg
- name: cli-tool
format: gettext
root: submodules/my-tool
dir: po
pot: messages.potlokit translate --provider copilot --model gpt-4o --parallel=10# lokit.yaml
languages: [de, es, fr, ru, ja, zh]
source_lang: en
targets:
- name: app
format: flutter
dir: lib/l10n
pattern: app_{lang}.arblokit init
lokit translate --provider copilot --model gpt-4o# lokit.yaml
languages: [de, es, fr, ru]
source_lang: en
targets:
- name: app
format: properties
dir: src/main/resources
pattern: messages_{lang}.propertieslokit translate \
--provider copilot --model gpt-4.1 \
--parallel=10 --chunk 50 \
--proxy "http://proxy:8080"lokit translate --provider copilot --model gpt-4o --lang ru,delokit translate --provider ollama --model llama3lokit auth login --provider openai
lokit auth login --provider openai --headless
lokit auth login --provider openai --auth-method oauth
lokit auth login --provider openai --auth-method device
lokit auth login --provider openai --auth-method api-key
lokit translate --provider openai --model gpt-5OAuth/device auth uses ChatGPT Codex endpoint and supports GPT-5/Codex models. For gpt-4o/gpt-4.1 or custom OpenAI-compatible endpoints, use API key auth (or custom-openai).
lokit auth login --provider custom-openai
# or non-interactively:
# lokit auth login --provider custom-openai --api-key YOUR_KEY --base-url https://api.example.com/v1
lokit translate --provider custom-openai --model my-modellokit translate --provider copilot --model gpt-4o --dry-runAll user data is stored in ~/.local/share/lokit/ (respects $XDG_DATA_HOME):
auth.json— OAuth tokens and API keys (permissions:0600)
Lookup order (highest → lowest):
--api-keyflag- Provider-specific environment variable (
GOOGLE_API_KEY,GROQ_API_KEY,OPENAI_API_KEY,CUSTOM_OPENAI_API_KEY,OPENCODE_API_KEY) - Stored credentials in
auth.json
Each target format has a built-in system prompt optimized for its structure (gettext, po4a/docs, i18next, vue-i18n, android, yaml, markdown, properties, flutter, js-kv, desktop, polkit). Prompts can be customized in two ways:
- Per target — set
prompt:in the target config inlokit.yaml - Per run — use the
--promptflag on the command line
The --prompt flag takes priority over the lokit.yaml target prompt, which takes priority over the built-in default. Use {{targetLang}} as a placeholder for the target language name.
lokit tracks MD5 checksums of source strings in a lokit.lock file (stored next to lokit.yaml). On subsequent runs, only new or changed strings are sent to the AI provider, saving tokens and time.
- Automatic — no configuration needed. The lock file is created on the first
lokit translaterun and updated after each translation. - Lock commands — manage lock data explicitly when needed:
lokit lock status lokit lock init lokit lock clean --dry-run lokit lock reset --target ui --lang ru
- Per-target tracking — checksums are stored per target and language, so changes in one target don't trigger re-translation of others.
- Force re-translation — use
--forceto ignore the lock file and re-translate all entries:lokit translate --provider copilot --model gpt-4o --force
- Safe to delete — removing
lokit.locksimply causes a full translation on the next run. - Commit to VCS — it's recommended to commit
lokit.lockto version control so that CI and teammates benefit from incremental translation.
You can control which keys are translated per target in lokit.yaml:
targets:
- name: ui
format: i18next
dir: translations
pattern: "{lang}.json"
source_lang: en
languages: [ru, de, fr]
# Keys excluded from translation entirely (never sent to AI)
ignored_keys:
- debug_label
- internal_test_string
# Hand-curated translations preserved as-is (skipped even with --all)
locked_keys:
- app_name
- copyright_notice
# Regex patterns — matching keys treated as locked
locked_patterns:
- "^brand_.*"
- "^legal_"Semantics:
| Field | Effect | Overridden by |
|---|---|---|
ignored_keys |
Key is completely skipped, as if it doesn't exist | — |
locked_keys |
Existing translation is preserved, key is not re-translated | --force |
locked_patterns |
Same as locked_keys but matches keys by regex |
--force |
ignored_keysare always skipped, even with--force.locked_keysandlocked_patternsare skipped during normal and--allruns. Only--forceoverrides them.- These settings work with all formats: gettext PO, po4a, i18next, vue-i18n, Android, YAML, Markdown, .properties, Flutter ARB, js-kv, desktop, and polkit.
Built with Go 1.23+:
MIT License — see LICENSE file for details.
Contributions are welcome! Please feel free to submit a Pull Request.