PHPackages                             publishpress/translations - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. publishpress/translations

ActiveLibrary[Localization &amp; i18n](/categories/localization)

publishpress/translations
=========================

AI-powered translation automation for PublishPress plugins using Potomatic

v1.5.0(1mo ago)02.2k↑87.9%[5 issues](https://github.com/publishpress/library-publishpress-translator/issues)[2 PRs](https://github.com/publishpress/library-publishpress-translator/pulls)4GPL-3.0-or-laterJavaScriptPHP &gt;=7.2.5CI failing

Since Dec 8Pushed 1w agoCompare

[ Source](https://github.com/publishpress/library-publishpress-translator)[ Packagist](https://packagist.org/packages/publishpress/translations)[ RSS](/packages/publishpress-translations/feed)WikiDiscussions development Synced today

READMEChangelog (10)Dependencies (33)Versions (21)Used By (4)

PublishPress Translations
=========================

[](#publishpress-translations)

AI-powered translation automation for PublishPress plugins using Potomatic, OpenAI, and Weblate.

Features
--------

[](#features)

- **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 `.pot` files
- **Translation audit** (`--audit`) to review `.po` health (empty/fuzzy entries, POT alignment, version headers), verify source i18n coverage in POT files, and optionally judge AI worthiness of changed strings

Requirements
------------

[](#requirements)

- PHP 7.2.5 or higher
- PHP extensions: `json`, `zip` (usually enabled by default)
- Node.js 18+ and npm (for Potomatic CLI tool)
- OpenAI API key ([Get one here](https://platform.openai.com/api-keys))
- Weblate account and API token ([Sign up here](https://hosted.weblate.org/))
- Plugin must have a `languages/` directory containing one or more `.pot` files

Installation
------------

[](#installation)

**Note:** This setup works the same whether you're working from the plugin root or inside dev-workspace.

**Recommended setup:**

### Step 1: Add to root `composer.json`

[](#step-1-add-to-root-composerjson)

```
{
    "require-dev": {
        "publishpress/translations": "^1.0.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",
        "translate:repair-plurals": "vendor/bin/publishpress-translate --repair-plurals",
        "translate:clean-po": "vendor/bin/publishpress-translate --clean-po",
        "translate:sync-files": "vendor/bin/publishpress-translate --sync-files",
        "translate:audit": "vendor/bin/publishpress-translate --audit",
        "translate:audit:report": "vendor/bin/publishpress-translate --audit --audit-mode=report"
    }
}
```

### Step 2: Install

[](#step-2-install)

```
composer update
```

Usage
-----

[](#usage)

### Set Environment Variables

[](#set-environment-variables)

Before using the translation tools, set your API keys as environment variables: Create a `.env` file in your plugin root with your API keys:

```
OPENAI_API_KEY=sk-proj-your-openai-key
WEBLATE_API_TOKEN=wlu_your-weblate-token

```

The `.env` file is automatically loaded when you run the translation tool. No additional configuration needed.

Values can be quoted or unquoted:

```
OPENAI_API_KEY="sk-proj-your-openai-key"
WEBLATE_API_TOKEN='wlu_your-weblate-token'

```

Alternatively, you can set environment variables directly in your shell:

**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-token
```

**Mac/Linux:**

```
export OPENAI_API_KEY=sk-proj-your-openai-key
export WEBLATE_API_TOKEN=wlu_your-weblate-token
```

Or 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
# Optional: short plugin description for translation audit AI text check (see Additional configuration)
# PLUGIN_AI_CONTEXT=PublishPress Future — schedule and automate post status changes.
# Optional: exclude source paths from source-i18n audit check (comma-separated fragments)
# AUDIT_SOURCE_EXCLUDE_PATHS=vendor,node_modules,tests/fixtures,build

```

> **Note:** Shell environment variables take precedence over `.env` file values.

**Get your Weblate API token:**

1. Sign up at [weblate.publishpress.com](https://weblate.publishpress.com/)
2. Go to your profile:
3. Copy your personal API key

### Additional configuration

[](#additional-configuration)

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.
- **`PLUGIN_AI_CONTEXT`** (optional; translation audit **`text`** check only) Short free-text description of the plugin or product under audit (for example what it does, who it is for, or official product naming). When set and non-empty after trimming, it is sent to the OpenAI worthiness judge as `plugin_context` alongside the diff batch so judgments can use domain and terminology context. If unset, empty, or whitespace-only, nothing extra is sent. Values longer than 4000 bytes are truncated before the request.
- **`AUDIT_SOURCE_EXCLUDE_PATHS`** (optional; translation audit **`source-i18n`** check only) Comma-separated list of path fragments to exclude from source scanning in the source i18n coverage check. Any PHP/JS/JSX file whose normalized relative path contains one of these fragments is skipped.

    Defaults: `dev-workspace-cache,vendor,lib/vendor,node_modules`.

    ```
    export AUDIT_SOURCE_EXCLUDE_PATHS="vendor,node_modules,tests/fixtures,build"
    ```
- **`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://hosted.weblate.org/api/`) Set this to your Weblate base URL (ending in `/api/`) when using a self-hosted instance.
- **`WEBLATE_SKIP_VCS`** (optional, default: `true`) Skip all VCS (repository) operations when interacting with Weblate. By default, VCS is skipped to avoid requiring repository configuration. Set to `false` or `0` to enable VCS operations if your project has a configured repository URL in Weblate.
- **`WEBLATE_API_TIMEOUT`** (optional, default: `120` seconds) 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
    ```
- **`WEBLATE_UPLOAD_DELAY`** (optional, default: `2` seconds) Delay between uploading translation files to Weblate. Useful to avoid rate limiting or server overload when uploading many languages.

    ```
    export WEBLATE_UPLOAD_DELAY=5
    ```
- **`WEBLATE_PROJECT_SLUG`** (optional) Override the Weblate project slug. By default, uses the plugin slug from `composer.json`.
- **`WEBLATE_COMPONENT_SLUG`** (optional) Override the Weblate component slug. By default, uses the text domain from the `.pot` file.
- **`WEBLATE_GIT_BRANCH`** (optional, default: `development`) Specify which Git branch Weblate should use for the component.
- **`WEBLATE_REPO_TYPE`** (optional, default: `https`) Repository access type: `https` or `ssh`. Use `ssh` if you have SSH keys configured in Weblate.
- **`WEBLATE_REPO_URL`** (optional) Override the repository URL for Weblate. Useful for private repositories or custom Git hosting. Examples:

    - HTTPS with credentials: `https://username:token@github.com/owner/repo.git`
    - SSH: `git@github.com:owner/repo.git`
- **`WEBLATE_PUSH_URL`** (optional) Override the push URL separately from the repository URL. Only needed if push and pull URLs differ.
- **`WEBLATE_PREFER_BASE_LANGUAGE`** (optional, default: `false`) When downloading from Weblate, prefer base language codes (e.g., `de` over `de_DE`) when duplicate locale variants exist. Set to `true` or `1` to enable.

    ```
    export WEBLATE_PREFER_BASE_LANGUAGE=true
    ```
- **`WEBLATE_CLEAN_EXISTING_TRANSLATIONS`** (optional, default: `false`) Delete all existing `.po` files before downloading from Weblate. Useful for a clean slate when syncing translations. Set to `true` or `1` to enable.

    ```
    export WEBLATE_CLEAN_EXISTING_TRANSLATIONS=true
    ```
- **`SKIP_LANGUAGES`** (optional, default: `it_IT,es_ES,fr_FR`) Comma-separated list of language codes to skip during translation and upload (downloads are still allowed). These languages are typically handled by human translators on Weblate. The default skipped languages are merged with any custom ones you specify.

    ```
    export SKIP_LANGUAGES=it_IT,es_ES,fr_FR
    ```

```
SKIP_LANGUAGES=it_IT,es_ES,fr_FR,de_DE
```

### Complete Translation Workflow

[](#complete-translation-workflow)

#### 1. Run Translation (Full Cycle)

[](#1-run-translation-full-cycle)

**From dev-workspace:**

```
# Enter dev-workspace
./run

# Dry run (preview cost, no API calls)
composer translate:dry-run

# Full translation cycle
composer translate
```

**From plugin root:**

```
# Dry run
composer translate:dry-run

# Full translation cycle
composer translate
```

**What happens when you run `composer translate`:**

1. **📥 Download** - Pulls existing translations from Weblate (if project exists)
2. **🤖 AI Translate** - Potomatic adds translations for new/missing strings
3. **📤 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

#### 2. Review &amp; Improve in Weblate

[](#2-review--improve-in-weblate)

After running `translate`, you can visit your project in Weblate:

1. Hosted Weblate:
2. Self-hosted Weblate:
3. Review and improve AI-generated translations
4. Use Weblate's translation memory and suggestions
5. Collaborate with community translators

#### 3. Download Only

[](#3-download-only)

If you just want to download the latest translations without running AI translation:

```
# Download latest from Weblate (no AI translation)
composer translate:download
```

Use this when:

- Translators made changes in Weblate
- You want to sync before building plugin
- You don't need to add new translations

**Advanced options:**

```
# Translate custom languages only
vendor/bin/publishpress-translate --languages=de_DE,fr_FR,es_ES

# Force re-translate all strings (ignore existing translations)
vendor/bin/publishpress-translate --force

# Download specific languages only
vendor/bin/publishpress-translate --download --languages=de_DE,fr_FR

# Upload specific languages only (no AI translation)
vendor/bin/publishpress-translate --upload --languages=de_DE,fr_FR

# Repair malformed plural entries in existing .po files
vendor/bin/publishpress-translate --repair-plurals

# Clean duplicate entries from all .po files
vendor/bin/publishpress-translate --clean-po

# Verify .po files are present (external tools compile to .mo, .json, .l10n.php)
vendor/bin/publishpress-translate --sync-files

# Run all translation audit checks (see "Translation audit" below)
vendor/bin/publishpress-translate --audit
```

#### 4. Repair Malformed Plural Entries

[](#4-repair-malformed-plural-entries)

If you have existing `.po` files with malformed plural entries (a known issue with older Potomatic versions where `msgstr[0]` contains `"singular|plural"` instead of separate `msgstr[0]`/`msgstr[1]` lines), you can fix them:

```
# Scan and repair all .po files in the languages directory
vendor/bin/publishpress-translate --repair-plurals
```

**What this fixes:**

- Detects plural entries where `msgstr[0]` contains pipe-delimited forms
- Splits them into proper separate `msgstr[N]` lines

**Note:** New translations are automatically repaired during the translation process, so you only need this for existing files.

**Note:** The library automatically detects your environment (dev-workspace vs plugin root) and uses the correct vendor path.

#### 5. Clean Duplicate Entries

[](#5-clean-duplicate-entries)

Remove duplicate extracted comments from all `.po` files:

```
# Clean duplicates from all .po files in the languages directory
vendor/bin/publishpress-translate --clean-po
```

**What this does:**

- Scans all `.po` files for duplicate extracted comments (`#.` lines)
- Removes redundant comment lines within each entry
- Reports which files were cleaned

**When to use:**

- After downloading from Weblate (if duplicates accumulated)
- Before uploading to Weblate to keep files clean
- As maintenance on skipped languages (which shouldn't be touched by AI translation)
- Works independently of translation workflow

**Important:** This command only processes `.po` files and doesn't interact with Weblate or run AI translation.

#### 6. Check Translation File Status

[](#6-check-translation-file-status)

Check whether `.po` source files and compiled formats (`.mo`, `.json`, `.l10n.php`) are in sync:

```
# Check status of all translation files
vendor/bin/publishpress-translate --sync-files
```

**What this does:**

- **Lists** all `.po` source files found
- **Checks** if corresponding `.mo`, `.json`, and `.l10n.php` files exist
- **Reports** whether compiled files are up-to-date or outdated compared to `.po` files
- **Recommends** running compile step if any files are missing or outdated

**When to use:**

- Before deploying to ensure all translation formats are current
- In CI/CD pipelines as a verification step
- After updating `.po` files to see what needs recompilation

**Compiling Translation Files:**

Compile `.mo`, `.json`, and `.l10n.php` files from `.po` sources using:

- **`.mo`** (compiled binary) - `wp i18n make-mo` (WP-CLI) or `composer translate:compile`
- **`.json`** (JSON format) - `composer translate:compile` or custom build script
- **`.l10n.php`** (PHP format) - `composer translate:compile` or custom build script

The library verifies compilation status but delegates actual compilation to your build/deployment tools.

#### 7. Translation audit (`--audit`)

[](#7-translation-audit---audit)

Run static checks (and optionally an OpenAI "worthiness" review) on `.po` files under `languages/`. This does **not** call Weblate or run the normal translate/upload cycle.

**Basic usage:**

```
vendor/bin/publishpress-translate --audit
# or
composer translate:audit
```

**What it checks** (all run by default; see `--audit-only` to limit):

IdFocus`text`Git-changed `.po` entries: optional AI judgment whether the translation still fits the source (uses `OPENAI_API_KEY`; spending capped by `--audit-max-cost`)`empty`Untranslated (`msgstr` empty) strings`fuzzy`Fuzzy-flagged entries`pot`Strings present in `.pot` but missing or mismatched in `.po``version``Project-Id-Version` header vs plugin version (advisory; headers are not rewritten by the tool)`source-i18n`Statically extractable i18n calls in PHP and JS/JSX source vs POT entries for each text domain**Modes (`--audit-mode`):**

- `interactive` (default) - on the **text** check, prompts whether to keep or revert each change the judge flags as not worth keeping (TTY only). Other checks are read-only.
- `allow-edit` - same **text** check, but unworthy changes are **reverted automatically** (no prompts). Other checks stay read-only.
- `report` - lists findings only; nothing is reverted. **CI / non-TTY:** with the default `interactive`, the tool switches to `report` and prints a notice.

```
composer translate:audit:report
vendor/bin/publishpress-translate --audit --audit-mode=report
```

**Scope:** Only locales in the translator **target language** list are scanned (same defaults and `--languages` handling as AI translation). Codes filtered out by `SKIP_LANGUAGES` / built-in skipped locales are **not** audited, even if you list them in `--languages`. To audit a narrower set of allowed locales, use e.g. `--languages=de_DE,fr_FR`.

For the `source-i18n` check, source scanning also excludes paths from `AUDIT_SOURCE_EXCLUDE_PATHS` (comma-separated fragments). If unset, defaults are: `dev-workspace-cache,vendor,lib/vendor,node_modules`.

**Run a subset of checks:**

```
vendor/bin/publishpress-translate --audit --audit-only=empty,fuzzy,pot,version
vendor/bin/publishpress-translate --audit --audit-only=text --languages=de_DE
vendor/bin/publishpress-translate --audit --audit-only=source-i18n
```

`--audit-only` accepts a comma-separated list: `text`, `empty`, `fuzzy`, `pot`, `version`, `source-i18n`.

**Cost control (text check only):**

```
vendor/bin/publishpress-translate --audit --audit-max-cost=2.5
```

**Optional context for the `text` check:** set `PLUGIN_AI_CONTEXT` to a short blurb about the plugin under audit if you want the AI judge to weigh domain-specific wording. See **Additional configuration** for behavior and limits.

**Report files:** By default, findings are summarized on the terminal only. To also write full reports to disk:

```
vendor/bin/publishpress-translate --audit --audit-report-format=txt,html --audit-report-dir=./build
```

Formats: `txt` (plain UTF-8, good for CI logs), `ansi` (color codes), `html` (single-file overview). Aliases `plain` and `text` map to `txt`. If `--audit-report-dir` is omitted, files are written to the **plugin root**. Report files use the basename `translation-audit-report` with extensions `.txt`, `.ansi.txt`, or `.html` depending on format.

**Exit code:** The process exits with a non-zero status if any finding is treated as failing (for example severity `error`, user quit at a prompt, or a failed revert). Warnings alone may still exit `0` depending on finding metadata—use `--audit-report-format=txt` in CI if you need a full artifact to review.

**`--audit-strict-po`:** Reserved for stricter PO parsing when a gettext v5 stack is available; typical Composer stacks (e.g. alongside WP-CLI) still use gettext v4, so this flag may only log that strict mode is unavailable.

### Default Languages

[](#default-languages)

The tool translates into these languages by default:

- Arabic (ar)
- Bulgarian (bg\_BG)
- Catalan (ca)
- Czech (cs\_CZ)
- Danish (da\_DK)
- German (de\_DE)
- Greek (el)
- Estonian (et\_EE)
- Persian (fa\_IR)
- Finnish (fi)
- Filipino (fil)
- Hebrew (he\_IL)
- Croatian (hr)
- Hungarian (hu\_HU)
- Indonesian (id\_ID)
- Japanese (ja)
- Korean (ko\_KR)
- Lithuanian (lt\_LT)
- Norwegian Bokmål (nb\_NO)
- Dutch (nl\_NL)
- Polish (pl\_PL)
- Portuguese (Portugal) (pt\_PT)
- Romanian (ro\_RO)
- Russian (ru\_RU)
- Slovak (sk\_SK)
- Slovenian (sl\_SI)
- Swedish (sv\_SE)
- Thai (th)
- Turkish (tr\_TR)
- Ukrainian (uk)
- Vietnamese (vi)
- Yoruba (yor)
- Chinese (China) (zh\_CN)
- Chinese (Taiwan) (zh\_TW)

### Skipped Languages

[](#skipped-languages)

The following languages should not be translated by Potomatic, they are handled by human translators:

- Italian (it\_IT)
- Spanish (es\_ES)
- French (fr\_FR)

These languages will be skipped during translation and upload processes, even if PO files exist for them.

**How Skipped Languages Work:**

1. **Translation (`composer translate`)** - Skipped languages are not passed to Potomatic AI translation
2. **Upload (`composer translate:upload`)** - Skipped languages are NOT uploaded to Weblate
3. **Download (`composer translate:download`)** - Skipped languages ARE downloaded from Weblate (translations can be pulled but not replaced by AI)
4. **Cleaning/Syncing** - Skipped languages ARE operated on by `--clean-po` and `--sync-files` (useful for maintenance without risk of overwriting with AI)
5. **Audit (`--audit`)** - Uses the same target-language list as translation (skipped locales are excluded by default, and `--languages` is filtered the same way), so skipped-language `.po` files are not scanned. This differs from `--clean-po` / `--sync-files`, which iterate every `.po` in `languages/`.

### Preventing Plugin Name Translation

[](#preventing-plugin-name-translation)

By default, all strings in your plugin are translated, including the plugin name. To keep your plugin name untranslated, add it to your `composer.json` file:

```
{
    "extra": {
        "plugin_name": "your plugin name"
    }
}
```

The translation tool will then automatically keep the plugin name untranslated in all PO files, both when:

- Running AI translations with Potomatic
- Downloading translations from Weblate

### Translation Overrides and Exclusions

[](#translation-overrides-and-exclusions)

You can control which words or phrases should be kept untranslated (excluded) or have specific translations enforced across all languages or per-language using environment variables.

#### Global Overrides (All Languages)

[](#global-overrides-all-languages)

Set `TRANSLATION_OVERRIDES` to specify words that should be kept untranslated in all languages:

```
export TRANSLATION_OVERRIDES="Dashboard,Shortlinks,Upgrade to Pro"
```

Or in your `.env` file:

```
TRANSLATION_OVERRIDES="Dashboard,Shortlinks,Upgrade to Pro"

```

#### Per-Language Overrides

[](#per-language-overrides)

Use `TRANSLATION_OVERRIDES_{language}` to override specific words for individual languages:

```
export TRANSLATION_OVERRIDES_yor="Shortlinks"

export TRANSLATION_OVERRIDES_de_DE="Dashboard,Shortlinks"
```

Or in your `.env` file:

```
TRANSLATION_OVERRIDES_yor="Shortlinks,Upgrade to Pro"
TRANSLATION_OVERRIDES_de_DE="Dashboard"

```

#### Custom Translations (Overrides)

[](#custom-translations-overrides)

You can also force specific translations using the `source=target` format:

```
# Force "Pro" to be translated as "Premium" in all languages
export TRANSLATION_OVERRIDES="Pro=Premium"

# Language-specific custom translation
export TRANSLATION_OVERRIDES_fr_FR="Upgrade to Pro=Passer à Premium"
```

#### How Overrides Work

[](#how-overrides-work)

**Priority:** Language-specific overrides take precedence over global overrides.

**Example:**

```
TRANSLATION_OVERRIDES="Dashboard,Shortlinks"
TRANSLATION_OVERRIDES_yor="Upgrade to Pro"
```

- **Yoruba (yor):** "Dashboard", "Shortlinks", and "Upgrade to Pro" kept untranslated
- **All other languages:** Only "Dashboard" and "Shortlinks" kept untranslated

**Automatic Dictionary Integration:**

The library includes a built-in dictionary (`config/dictionaries.json`) with common brand names and technical terms that are automatically kept untranslated:

- PublishPress, TaxoPress, MetaSlider, WordPress, WooCommerce
- Technical terms: taxonomy, taxonomies, post type, custom field, shortcode, widget, admin, dashboard

These are applied automatically without needing to set them in `TRANSLATION_OVERRIDES`.

How It Works
------------

[](#how-it-works)

### Translation Cycle (`composer translate`)

[](#translation-cycle-composer-translate)

**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 `.pot` files
- Generates AI translations for new/missing strings only
- Merges with existing translations (preserves manual edits)
- Creates/updates `.po` and `.mo` files 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

### Download Only (`composer translate:download`)

[](#download-only-composer-translatedownload)

1. Connects to Weblate using your API token
2. Finds your plugin's project and components
3. Downloads latest `.po` files for all languages
4. Converts to `.mo` files for WordPress
5. 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

### Weblate Integration

[](#weblate-integration)

- **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 `.pot` file becomes a component
- **Optional** - Works without Weblate if token not set

One-Time Setup
--------------

[](#one-time-setup)

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-token
```

Troubleshooting
---------------

[](#troubleshooting)

### "Potomatic not found" Error

[](#potomatic-not-found-error)

This shouldn't happen if you installed via Composer. If it does, please report it as a bug.

### "OPENAI\_API\_KEY not set" warning / exit

[](#openai_api_key-not-set-warning--exit)

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.

### "Weblate not configured" Error

[](#weblate-not-configured-error)

This appears when running `--download` without `WEBLATE_API_TOKEN` set. Weblate integration is optional for generation but required for download.

### "No .pot files found" Error

[](#no-pot-files-found-error)

Ensure your plugin has a `languages/` directory with `.pot` translation template files. Generate these using tools like:

- [WP-CLI i18n make-pot](https://developer.wordpress.org/cli/commands/i18n/make-pot/)
- [Poedit](https://poedit.net/)
- [Loco Translate](https://wordpress.org/plugins/loco-translate/)

### Weblate Upload Fails

[](#weblate-upload-fails)

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)

Development
-----------

[](#development)

### Clone the Repository

[](#clone-the-repository)

```
git clone https://github.com/publishpress/translations.git
cd translations
composer install
```

### Testing Locally

[](#testing-locally)

To test the library before publishing:

1. In your plugin's `composer.json`, add a repository:

```
{
    "repositories": [
        {
            "type": "path",
            "url": "../publishpress-translations"
        }
    ],
    "require": {
        "publishpress/translations": "@dev"
    }
}
```

2. Run `composer install`

License
-------

[](#license)

GPL-3.0-or-later

Credits
-------

[](#credits)

Built with [Potomatic](https://github.com/GravityKit/potomatic) by GravityKit.

###  Health Score

44

—

FairBetter than 90% of packages

Maintenance95

Actively maintained with recent releases

Popularity21

Limited adoption so far

Community16

Small or concentrated contributor base

Maturity39

Early-stage or recently created project

 Bus Factor1

Top contributor holds 64.3% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~16 days

Recently: every ~4 days

Total

11

Last Release

45d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/407131?v=4)[Anderson Grüdtner Martins](/maintainers/andergmartins)[@andergmartins](https://github.com/andergmartins)

---

Top Contributors

[![Deji98](https://avatars.githubusercontent.com/u/105164114?v=4)](https://github.com/Deji98 "Deji98 (90 commits)")[![andergmartins](https://avatars.githubusercontent.com/u/407131?v=4)](https://github.com/andergmartins "andergmartins (42 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (8 commits)")

###  Code Quality

TestsPHPUnit

Static AnalysisPHPStan

Code StylePHP\_CodeSniffer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/publishpress-translations/health.svg)

```
[![Health](https://phpackages.com/badges/publishpress-translations/health.svg)](https://phpackages.com/packages/publishpress-translations)
```

###  Alternatives

[aws/aws-sdk-php

AWS SDK for PHP - Use Amazon Web Services in your PHP project

6.3k543.5M2.6k](/packages/aws-aws-sdk-php)[neuron-core/neuron-ai

The PHP Agentic Framework.

2.0k656.1k38](/packages/neuron-core-neuron-ai)[tencentcloud/tencentcloud-sdk-php

TencentCloudApi php sdk

3741.3M47](/packages/tencentcloud-tencentcloud-sdk-php)[tempest/framework

The PHP framework that gets out of your way.

2.2k34.4k15](/packages/tempest-framework)[tio/laravel

Add this package to localize your Laravel application (PHP, JSON or GetText).

170341.2k](/packages/tio-laravel)[eslazarev/wildberries-sdk

Wildberries OpenAPI clients (generated).

273.0k](/packages/eslazarev-wildberries-sdk)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
