AI-powered translation automation for PublishPress plugins using Potomatic, OpenAI, and Weblate.
- AI-powered translations using OpenAI GPT models
- Weblate integration for translation management and human review
- Automatic upload/download to/from Weblate
- Merges with existing translations (preserves manual edits)
- Cost-effective (~$0.03 per language for 1,744 strings)
- Supports 10+ languages by default
- Dry-run mode for cost estimation
- Automatic detection of
.potfiles
- PHP 7.2.5 or higher
- Node.js 18+ and npm (for Potomatic CLI tool)
- OpenAI API key (Get one here)
- Weblate account and API token (Sign up here)
- Plugin must have a
languages/directory with.potfiles
Note: This setup works the same whether you're working from the plugin root or inside dev-workspace.
{
"repositories": [
{
"type": "vcs",
"url": "https://github.com/publishpress/publishpress-translator.git"
}
],
"require": {
"publishpress/translations": "^1.0"
},
"scripts": {
"translate": "vendor/bin/publishpress-translate",
"translate:dry-run": "vendor/bin/publishpress-translate --dry-run",
"translate:download": "vendor/bin/publishpress-translate --download",
"translate:upload": "vendor/bin/publishpress-translate --upload",
"translate:custom": "vendor/bin/publishpress-translate --languages",
"translate:force": "vendor/bin/publishpress-translate --force",
"translate:force-custom": "vendor/bin/publishpress-translate --force --languages"
}
}composer updateOnce on Packagist: You can remove the custom repositories section and keep only the dependency and scripts:
{
"require": {
"publishpress/translations": "^1.0"
},
"scripts": {
"translate": "vendor/bin/publishpress-translate",
"translate:dry-run": "vendor/bin/publishpress-translate --dry-run",
"translate:download": "vendor/bin/publishpress-translate --download",
"translate:upload": "vendor/bin/publishpress-translate --upload",
"translate:custom": "vendor/bin/publishpress-translate --languages",
"translate:force": "vendor/bin/publishpress-translate --force",
"translate:force-custom": "vendor/bin/publishpress-translate --force --languages"
}
}Before using the translation tools, set your API keys as environment variables:
Windows (PowerShell):
$env:OPENAI_API_KEY="sk-proj-your-openai-key"
$env:WEBLATE_API_TOKEN="wlu_your-weblate-token"Windows (CMD):
set OPENAI_API_KEY=sk-proj-your-openai-key
set WEBLATE_API_TOKEN=wlu_your-weblate-tokenMac/Linux:
export OPENAI_API_KEY=sk-proj-your-openai-key
export WEBLATE_API_TOKEN=wlu_your-weblate-tokenOr create a .env file in your plugin root (don't commit this!):
OPENAI_API_KEY=sk-proj-your-openai-key
WEBLATE_API_TOKEN=wlu_your-weblate-token
Get your Weblate API token:
- Sign up at weblate.publishpress.com
- Go to your profile: https://weblate.publishpress.com/accounts/profile/#api
- Copy your personal API key
The following environment variables control advanced behaviour:
-
OPENAI_API_KEY(required for live translation) Used to call the OpenAI API. If it is missing:- In dry run mode, the tool prints a warning but continues so you can verify the workflow without incurring cost.
- In live mode, the tool prints a clear warning and exits before making any API calls.
-
WEBLATE_API_TOKEN(optional for AI generation, required for Weblate sync) If not set, Weblate integration is disabled:- You can still generate local translations.
- Upload/download with Weblate will be skipped and a warning will be printed.
-
WEBLATE_API_URL(optional, default:https://weblate.publishpress.com/api/) Override this if you use a self-hosted Weblate instance. -
WEBLATE_API_TIMEOUT(optional, default:120seconds) HTTP timeout used for Weblate API requests. For large projects or slow connections this may be too short. You can increase it, for example:export WEBLATE_API_TIMEOUT=300
From dev-workspace:
# Enter dev-workspace
./run
# Dry run (preview cost, no API calls)
composer translate:dry-run
# Full translation cycle
composer translateFrom plugin root:
# Dry run
composer translate:dry-run
# Full translation cycle
composer translateWhat happens when you run composer translate:
- π₯ Download - Pulls existing translations from Weblate (if project exists)
- π€ AI Translate - Potomatic adds translations for new/missing strings
- π€ Upload - Pushes updated translations back to Weblate
This ensures:
- Existing translations are preserved
- Only new/missing strings are translated by AI
- Weblate always has the latest translations
After running translate, we then can:
- Visit https://weblate.publishpress.com/projects/YOUR-PLUGIN/
- Review and improve AI-generated translations
- Use Weblate's translation memory and suggestions
- Collaborate with community translators
If you just want to download the latest translations without running AI translation:
# Download latest from Weblate (no AI translation)
composer translate:downloadUse this when:
- Translators made changes in Weblate
- You want to sync before building plugin
- You don't need to add new translations
Advanced options:
# Custom languages only
lib/vendor/bin/publishpress-translate --languages=de_DE,fr_FR,es_ES
# Force re-translate all strings (ignore existing translations)
lib/vendor/bin/publishpress-translate --force
# Download specific languages
lib/vendor/bin/publishpress-translate --download --languages=de_DE,fr_FRNote: The library automatically detects your environment (dev-workspace vs plugin root) and uses the correct vendor path.
The tool translates into these languages by default:
- German (de_DE)
- Brazilian Portuguese (pt_BR)
- Indonesian (id_ID)
- Filipino (fil)
- Russian (ru_RU)
- Yoruba (yo)
- Finnish (fi)
- Japanese (ja)
- Korean (ko_KR)
Step 1: Download from Weblate
- Pulls existing translations from Weblate
- Preserves human edits and community contributions
- Creates project if it doesn't exist yet
Step 2: AI Translation with Potomatic
- Scans your plugin's
languages/directory for.potfiles - Generates AI translations for new/missing strings only
- Merges with existing translations (preserves manual edits)
- Creates/updates
.poand.mofiles for each target language
Step 3: Upload to Weblate
- Creates project on Weblate (using plugin slug as project slug)
- Creates component for each text domain
- Uploads POT template and all PO translations
- Provides link to view/edit in Weblate
- Connects to Weblate using your API token
- Finds your plugin's project and components
- Downloads latest
.pofiles for all languages - Converts to
.mofiles for WordPress - Saves to your
languages/folder
Use this when:
- You want to sync translations before building
- Translators made changes in Weblate
- You don't need to run AI translation
- Automatic sync - Download β Translate β Upload in one command
- Preserves human edits - Existing translations are never overwritten
- Automatic project creation - Uses plugin slug as project name
- Component per text domain - Each
.potfile becomes a component - Optional - Works without Weblate if token not set
Set your API keys permanently:
Windows:
[System.Environment]::SetEnvironmentVariable('OPENAI_API_KEY', 'sk-proj-your-key', 'User')
[System.Environment]::SetEnvironmentVariable('WEBLATE_API_TOKEN', 'wlu_your-token', 'User')Mac/Linux (add to ~/.bashrc or ~/.zshrc):
export OPENAI_API_KEY=sk-proj-your-key
export WEBLATE_API_TOKEN=wlu_your-tokenThis shouldn't happen if you installed via Composer. If it does, please report it as a bug.
If OPENAI_API_KEY is not configured:
- In dry run (
composer translate:dry-run), the tool prints a warning but continues so you can verify configuration without any API calls. - In live mode (
composer translate), the tool prints a clear message and exits before attempting any OpenAI requests.
Make sure you've set the environment variable before running live translations.
This appears when running --download without WEBLATE_API_TOKEN set. Weblate integration is optional for generation but required for download.
Ensure your plugin has a languages/ directory with .pot translation template files. Generate these using tools like:
If Weblate upload fails, the translation process continues (translations are still saved locally). Check:
- API token is correct
- You have permissions on Weblate
- Project/component names are valid (no special characters)
git clone https://github.com/publishpress/translations.git
cd translations
composer installTo test the library before publishing:
- In your plugin's
composer.json, add a repository:
{
"repositories": [
{
"type": "path",
"url": "../publishpress-translations"
}
],
"require": {
"publishpress/translations": "@dev"
}
}- Run
composer install
GPL-3.0-or-later
Built with Potomatic by GravityKit.