lokit — Localization Kit
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.
Features
- Config-first workflow —
lokit.yaml is 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
xgettext and msgmerge
- 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 |
Supported AI Providers
| 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 |
Installation
One-line installer (recommended)
curl -fsSL https://raw.githubusercontent.com/minios-linux/lokit/refs/heads/master/install.sh | bash
From source
git clone https://github.com/minios-linux/lokit.git
cd lokit
make build
Using go install
go install github.com/minios-linux/lokit@latest
Check version
lokit version
Quick Start
Minimal project (lokit.yaml required)
Create 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.1
Multi-target project (lokit.yaml)
Create 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/l10n
Then:
lokit status # Shows all targets with stats
lokit translate --provider copilot --model gpt-4o # Translates everything
Configuration File (lokit.yaml)
lokit.yaml is required. lokit uses it as the sole source of truth.
Schema
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.json
Reference:
# 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 AI
gettext — 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.
Custom file layouts with pattern
For file-per-language targets (i18next, vue-i18n, yaml, properties, flutter, js-kv),
you must define pattern.
pattern is relative to dir
- 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"
Index source mode (source object)
For catalog-style projects (one source index file + many per-record translation files),
source can be an object instead of a string.
source.index points to the source index file
source.records_path selects the records array ($ or $.field)
source.key_field provides values for {id} in pattern / target
source.fields lists translatable fields copied from each record
Example (catalog index mode):
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:
pattern or target must include {id} in index mode.
--target recipes selects all expanded records like recipes/<id>.
- You can still target a single record with
--target recipes/<id>.
Commands
lokit status
Shows project info and translation statistics for targets defined in lokit.yaml.
lokit status # Current directory
lokit status --root ./my-project # Specific project
lokit init
Extracts translatable strings and creates/updates translation files:
lokit init # All languages
lokit init --lang ru,de # Specific languages
- Runs
xgettext for gettext projects
- Runs
po4a --no-translations for po4a projects
- Creates missing language files for i18next, vue-i18n, yaml, properties, flutter, js-kv
- In index mode, creates per-record files from
source.index for each target language
- Idempotent — safe to run repeatedly
lokit translate
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 logging
lokit auth
Manage 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 all
lokit version
Show version, commit hash, and build date.
Examples
Translate a monorepo with submodules
# 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.pot
lokit translate --provider copilot --model gpt-4o --parallel=10
Flutter application
# lokit.yaml
languages: [de, es, fr, ru, ja, zh]
source_lang: en
targets:
- name: app
format: flutter
dir: lib/l10n
pattern: app_{lang}.arb
lokit init
lokit translate --provider copilot --model gpt-4o
Java application with .properties
# lokit.yaml
languages: [de, es, fr, ru]
source_lang: en
targets:
- name: app
format: properties
dir: src/main/resources
pattern: messages_{lang}.properties
Parallel translation with proxy
lokit translate \
--provider copilot --model gpt-4.1 \
--parallel=10 --chunk 50 \
--proxy "http://proxy:8080"
Translate specific languages
lokit translate --provider copilot --model gpt-4o --lang ru,de
Use local Ollama
lokit translate --provider ollama --model llama3
OpenAI
lokit 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-5
OAuth/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).
Custom OpenAI endpoint
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-model
Dry run
lokit translate --provider copilot --model gpt-4o --dry-run
User Data Storage
All user data is stored in ~/.local/share/lokit/ (respects $XDG_DATA_HOME):
auth.json — OAuth tokens and API keys (permissions: 0600)
Credentials
Lookup order (highest → lowest):
--api-key flag
- 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
System Prompts
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 in lokit.yaml
- Per run — use the
--prompt flag 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.
Incremental Translation (lokit.lock)
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.
Key Filtering (locked_keys / ignored_keys / locked_patterns)
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_keys are always skipped, even with --force.
locked_keys and locked_patterns are skipped during normal and --all runs. Only --force overrides them.
- These settings work with all formats: gettext PO, po4a, i18next, vue-i18n, Android, YAML, Markdown, .properties, Flutter ARB, js-kv, desktop, and polkit.
Development
Built with Go 1.23+:
- cobra — CLI framework
- yaml.v3 — YAML config parsing
- Native OAuth for GitHub Copilot and Gemini
License
MIT License — see LICENSE file for details.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.