msgai-cli
v1.2.0
Published
CLI that automatically translates all untranslated strings in gettext (.po) files using AI (LLM)
Maintainers
Readme
msgai
msgai is an AI-powered CLI for translating gettext .po files. It finds untranslated entries, sends them to an LLM, and writes the translated strings back into the same file.
🤖 Project Purpose
msgai is built for teams that already use gettext and want a simple way to translate missing strings without building a separate localization workflow.
Main features:
📝Works directly with gettext.pofiles🤖Translates only untranslated entries using AI🧠Uses OpenAIgpt-4oby default for translation🏷️Respects gettext context (msgctxt) when translating entries🔁Supports singular and plural translations⚠️Skips fuzzy entries by default🧭Can infer source language or use--source-lang💻Runs as a small CLI that updates files in place
⚙️ How It Works
- Read the
.pofile and parse its entries. - Find entries with empty or missing translations.
- Send those strings to OpenAI
gpt-4ofor translation while preserving gettext context such asmsgctxt. - Write the translated values back into the same
.pofile.
The translation API uses OpenAI json_schema structured outputs. Only models that support json_schema structured outputs are valid for msgai.
gpt-4ogpt-4o-minigpt-4.1gpt-4.1-minigpt-4.1-nanogpt-5gpt-5-minigpt-5-nanogpt-5-progpt-5.1gpt-5.2gpt-5-codexgpt-5.1-codexgpt-5.1-codex-minigpt-5.1-codex-maxgpt-5.2-codex
Dated snapshots are accepted where the model family supports them.
By default, entries marked as fuzzy are skipped. If you use --include-fuzzy, msgai will translate those entries too and remove the fuzzy flag after applying the result.
📦 Install
Install the CLI globally:
npm install -g msgai-cliSet your OpenAI API key before running translations:
export OPENAI_API_KEY=your_api_key_hereYou can also pass the key directly:
msgai messages.po --api-key sk-...OPENAI_API_KEY can be loaded from your environment or from a .env file in the current directory.
💻 CLI Usage
Usage:
msgai <file.po> [--dry-run] [--api-key KEY] [--source-lang LANG] [--model MODEL] [--include-fuzzy] [--fold-length N] [--debug]Options:
--dry-run: list untranslatedmsgidvalues only, with no API calls and no file changes--include-fuzzy: include fuzzy entries for translation and clear their fuzzy flag after translation--source-lang LANG: set the source language ofmsgidstrings as an ISO 639-1 code such asenoruk--model MODEL: set the OpenAI model used for translation; default isgpt-4o. Only models withjson_schemastructured outputs are supported.--api-key KEY: pass the OpenAI API key directly instead of usingOPENAI_API_KEY--fold-length N: set PO line fold length when writing files. Use0to disable folding and minimize formatting-only diffs. Default:0--debug: print debug logs for batch preparation, OpenAI request retries, request payloads, and raw response validation--help: print command usage
You can also enable the same debug logging with the environment variable DEBUG=1:
DEBUG=1 msgai messages.poIf no API key is provided for a non-dry run, the CLI exits with code 1 and prints an error message.
On API failures such as rate limits, quota issues, or server errors, the CLI exits with code 1 and shows a status-specific message. Validation errors for protected fields such as msgid, msgid_plural, or msgctxt now tell you whether a retry is reasonable and when to rerun with --debug or DEBUG=1 to inspect the request/response flow. For API error details, see OpenAI API error codes.
🧪 Development
Requirements:
- Node.js
20+ - npm
10+
Install dependencies:
npm installUseful scripts:
npm run build: compile TypeScript todist/npm test: build the project and run Jest testsnpm run test:integration: run integration testsnpm run test:watch: run tests in watch modenpm run lint: run ESLintnpm run lint:format: check formatting with Prettiernpm run format: format the repository with Prettiernpm run release:dry-run: preview thecommit-and-tag-versionrelease without writing filesnpm run release: run release checks, updateCHANGELOG.md, bump the npm version, create a release commit, and create a local tag
This repo follows Conventional Commits for commit messages.
Release Flow
Maintainer releases are local-first and use commit-and-tag-version. The release command does not publish to npm or push tags for you.
Preview the next release:
npm run release:dry-runCreate the release locally:
npm run releaseThis command:
- runs
build, unit tests, integration tests, lint, and formatting checks through theprereleaselifecycle hook - lets
commit-and-tag-versioninfermajor,minor, orpatchfrom Conventional Commits since the latestv*tag - updates
CHANGELOG.md - creates
chore(release): X.Y.Z - creates a local annotated tag
vX.Y.Z
For reliable version bumps and changelog entries, keep commits in Conventional Commit format.
If you need to override the inferred bump manually:
npm run release -- --release-as minorAfter the local release is created:
git push --follow-tags
npm publish