Skip to content

minios-linux/lokit

Repository files navigation

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 workflowlokit.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

Supported Formats

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

Target formats

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 (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:

  • 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):

  1. --api-key flag
  2. Provider-specific environment variable (GOOGLE_API_KEY, GROQ_API_KEY, OPENAI_API_KEY, CUSTOM_OPENAI_API_KEY, OPENCODE_API_KEY)
  3. 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.

  • Automatic — no configuration needed. The lock file is created on the first lokit translate run 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 --force to ignore the lock file and re-translate all entries:
    lokit translate --provider copilot --model gpt-4o --force
  • Safe to delete — removing lokit.lock simply causes a full translation on the next run.
  • Commit to VCS — it's recommended to commit lokit.lock to version control so that CI and teammates benefit from incremental translation.

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.

About

Localization Kit: gettext PO file manager with AI translation support

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors

Languages