wp-plugin-i18n-release

Prépare un plugin WordPress hébergé sur plugins.svn.wordpress.org pour l'internationalisation complète et publie la version sur le SVN. Couvre : réécriture des chaînes codées en dur de l'espagnol vers l'anglais (PHP et JS), génération du .pot avec wp-cli, création de la traduction initiale .po/.mo (ex : espagnol neutre), mise à jour synchronisée de la version, commit sur le trunk et création du tag.

Qu'est-ce que wp-plugin-i18n-release ?

Ce skill automatise le processus complet d'internationalisation (i18n) et de publication d'un plugin WordPress sur le SVN officiel de plugins.svn.wordpress.org. Il est conçu pour les développeurs dont les plugins sont approuvés sur WP.org mais dont le code contient des chaînes traduisibles en espagnol, empêchant la traduction vers d'autres locales comme le français, l'allemand ou le portugais via GlotPress. Le workflow commence par la vérification de l'environnement (TortoiseSVN, PHP, wp-cli), le checkout du SVN, l'identification des chaînes avec `Select-String`, puis leur réécriture en anglais selon une table de correspondance fournie. Ensuite, il régénère le fichier `.pot` avec `wp i18n make-pot`, crée une traduction initiale `.po` / `.mo` (ex : espagnol neutre) en utilisant `mb_chr` pour contourner les problèmes d'encodage PHP sur Windows, et prépare les fichiers pour publication. Le skill met à jour la version du plugin dans quatre fichiers (header PHP, constante, `readme.txt`, `CHANGELOG.md`), construit une version propre en excluant les fichiers de développement via un `.distignore`, et effectue le commit sur le trunk SVN ainsi que la création d'un tag. Il inclut des solutions pour les problèmes courants sous Windows (chemins UNC, encodage des accents, SVN hors PATH).

Compatible avec~Claude Code~Codex CLI~Cursor✓OpenCode
npx skills add https://github.com/leoarayas/agent-skills/tree/main/wp-plugin-i18n-release

Installed? Explore more Développement et programmation skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

Demander à votre IA préférée

Ouvre une nouvelle conversation avec cette compétence d'agent déjà préchargée.

Documentation

Plugin WordPress : i18n complet + Release sur le SVN de .org

Quand l'utiliser

  • Plugin fraîchement approuvé sur WP.org qui doit être prêt pour translate.wordpress.org.
  • Les chaînes traduisibles (__(), _e(), wp.i18n.__(), etc.) sont codées en dur en espagnol et bloquent les autres locales (fr, de, pt, ja, etc.) dans GlotPress.
  • Il faut ajouter une traduction initiale ou un .pot pour la première fois.
  • Toute release qui met à jour la version et publie sur le SVN de plugins.svn.wordpress.org.

Prérequis

ComposantComment vérifierS'il manque
TortoiseSVN (svn.exe)Test-Path "C:\Program Files\TortoiseSVN\bin\svn.exe"Installer depuis https://tortoisesvn.net/downloads.html (cocher "command line tools")
PHP 8.x dans le PATHphp --version depuis un dossier non-UNCHerd legacy suffit ; ou PHP standalone
wp-cli.pharTélécharger depuis https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.pharInvoke-WebRequest -Uri ... -OutFile wp-cli.phar
Accès SVN au pluginEmail d'approbation de [email protected] avec l'URL SVN, le nom d'utilisateur et le mot de passeDemander à l'équipe si manquant

Workflow complet

  1. Vérifier l'environnement et le plugin
  2. Checkout du SVN du plugin
  3. Localiser les chaînes traduisibles dans le code (PHP + JS)
  4. Réécrire les chaînes en anglais en conservant la sémantique technique
  5. Régénérer le .pot avec wp i18n make-pot
  6. Générer .po + .mo de la traduction initiale (ex : espagnol neutre)
  7. Mettre à jour la version synchronisée (header Version, constante, readme stable tag, CHANGELOG)
  8. Régénérer un build propre en excluant les fichiers de développement (.distignore)
  9. Commit sur le trunk + créer un tag dans SVN
  10. (Optionnel) Synchroniser le dossier local en préservant les fichiers Git

1. Vérifier l'environnement et le plugin

# SVN sur Windows (souvent pas dans PATH ; utiliser le chemin complet ou ajouter)
$env:Path = "$env:ProgramFiles\TortoiseSVN\bin;$env:Path"
svn --version

# PHP
php --version

Avant de toucher au code, lire le plugin :

  • Plugin header (Name, Version, Text Domain, Domain Path)
  • readme.txt (Stable tag, Changelog)
  • CHANGELOG.md (s'il existe)
  • Liste des fichiers PHP/JS dans includes/ et assets/

2. Checkout du SVN

$svnUser = '<wp-org-user>'       # nom d'utilisateur WP.org (sensible à la casse)
$svnPass = 'svn_XXXXX...'     # depuis "Account & Security" dans profiles.wordpress.org
$slug    = 'mon-plugin'        # le slug du plugin
$checkout = "C:\Temp\opencode\$slug-svn"

svn checkout --non-interactive --trust-server-cert `
  --username $svnUser --password $svnPass `
  "https://plugins.svn.wordpress.org/$slug" $checkout

SVN contient déjà trunk/, tags/, assets/. Si vous venez de publier la première release, tags/ sera vide et trunk/ aussi (tout juste créé avec le trunk initial).

3. Localiser les chaînes traduisibles

Identifiez TOUS les appels aux fonctions i18n. Utilisez grep avec ces motifs :

# PHP
Select-String -Path 'includes/*.php' -Pattern '__\(|_e\(|_x\(|esc_html__\(|esc_attr__\(|esc_html_e\(|esc_attr_e\(|_n\(|_nx\('

# JS (wp.i18n ou chaînes codées en dur sans fonction)
Select-String -Path 'assets/js/*.js' -Pattern 'wp\.i18n|__\('
Select-String -Path 'assets/js/*.js' -Pattern '"[^"]{6,80}"'   # détecte les chaînes codées en dur

Anti-motif courant : chaînes en espagnol dans du HTML concaténé en JS (ex : html += '<option>Toutes</option>';). Les réécrire en anglais est valable ; utiliser wp.i18n.__() est mieux si vous voulez qu'elles soient traduisibles au moment de l'exécution.

4. Réécrire les chaînes en anglais

Règles strictes :

  1. Traduisez UNIQUEMENT le premier argument des fonctions i18n. Ne touchez PAS au text-domain (deuxième argument).
  2. Ne touchez à rien en dehors d'un appel i18n.
  3. NE modifiez PAS le format PHP (espaces, guillemets, parenthèses).
  4. Les termes techniques comme ExampleStore, WooCommerce, API, Correlation ID, Premium, JSON, HTTP, URL, CLP restent en anglais (ce sont déjà des noms propres / acronymes).
  5. PRÉSERVEZ les placeholders de sprintf/printf (%s, %d, %1$s, etc.) exactement identiques.
  6. Si une chaîne est déjà en anglais, ne la touchez PAS.

Table de traduction recommandée (ajustez au contexte) :

EspagnolAnglais
"Activo""Enabled"
"Título""Title"
"Configurar""Configure"
"Guardar""Save"
"Eliminar""Delete"
"Comuna""Commune"
"Región""Region"
"Selecciona una región""Select a region"
"Sin reglas guardadas""No saved rules"
"Configura la URL de API y el token""Configure API URL and token"
"Diagnóstico ejecutado correctamente""Diagnostic executed successfully"
"No se pudo {verbe}""Could not {verbe}"
"Debes ingresar X""You must enter X"
"Cotización API recibida""API quote received"
"Tarifa por defecto (CLP)""Default rate (CLP)"

Pour les gros fichiers, déléguez à un agent avec des instructions précises et la table de traductions.

5. Régénérer le .pot avec wp-cli

# Depuis le dossier du plugin (miroir local)
$wpCli = 'C:\Temp\opencode\wp-cli.phar'
php $wpCli i18n make-pot . "languages/mon-plugin.pot" --domain="mon-plugin"

Le .pot doit être dans /languages/ avec le nom <text-domain>.pot.

6. Créer la traduction .po + .mo

Décision clé : quel locale ? Pour que le plugin soit traduit automatiquement pour tous les hispanophones sans variantes régionales, utilisez <text-domain>-es.po (racine es). WordPress fait un fallback en cascade : es_CL → es → anglais.

Stratégie recommandée :

  • es.po/.mo (racine) → sert es_CL, es_ES, es_MX, es_AR, es_PE, etc.
  • (Optionnel plus tard) es_CL.po/.mo spécifique pour le Chili avec des expressions locales.

Générer le .po : utilisez un script PHP qui lit le .pot et applique un tableau de traductions EN→ES. Utilisez mb_chr(0x00f3) pour les caractères accentués (PHP sur Windows a des problèmes de codepage avec les littéraux UTF-8).

// build-es.php
declare(encoding='UTF-8');
$pot = file_get_contents('languages/mon-plugin.pot');
$po_es = 'languages/mon-plugin-es.po';

// Précharger `mb_chr` pour les caractères accentués
function A() { return mb_chr(0x00e1); } // á
function E() { return mb_chr(0x00e9); } // é
function O() { return mb_chr(0x00f3); } // ó
// etc.

$t = [
    "Configure API URL and token" => "Configura la URL de API y el token",
    // ...
];

$header = "msgid \"\"\nmsgstr \"\"\n"
        . "\"Project-Id-Version: Mon Plugin 1.0.0\\n\"\n"
        . "\"Language-Team: Español (neutro) <>\"\n"
        . "\"Language: es\\n\"\n"
        . "\"Plural-Forms: nplurals=2; plural=(n != 1);\\n\"\n";

// Parser le .pot, remplir msgstr avec $t, écrire le .po
// (logique complète : voir wp-plugin-i18n-release/build-es.php)

Compilation du .mo :

php $wpCli i18n make-mo languages/

Ceci crée automatiquement languages/<text-domain>-es.mo.

7. Mettre à jour la version synchronisée

Mettez à jour quatre fichiers :

// 1. my-plugin.php (header)
 * Version: 1.1.0

// 2. my-plugin.php (constante)
define('PLUGIN_VERSION', '1.1.0');

// 3. readme.txt
Stable tag: 1.1.0
/* + nouvelle entrée dans == Changelog == */

// 4. CHANGELOG.md
## [1.1.0] - 2026-09-14
### Changed
- ...

8. Régénérer un build propre (exclure les fichiers de dev)

Le .distignore du plugin définit ce qu'il faut exclure. S'il n'existe pas, utilisez cette liste standard :

$exclude = @('.git','.github','.gitignore','.gitattributes','.distignore',
             '.idea','.DS_Store','.release-build','bin','node_modules',
             'tests','vendor/bin','phpcs.xml*','phpunit.xml*',
             '.phpunit.result.cache','*.lock','*.log','*.zip',
             'README.md','RELEASING.md','Makefile','.pr-body-*.md')

# Nettoyer la destination, tout copier, supprimer les exclus
$src  = 'chemin/miroir/plugin'
$dist = 'chemin/build/plugin'
Copy-Item -Path "$src\*" -Destination $dist -Recurse -Force
foreach ($pat in $exclude) {
  Get-ChildItem -Path $dist -Recurse -Force -Filter $pat -ErrorAction SilentlyContinue | Remove-Item -Recurse -Force
}

9. Commit sur le trunk + créer un tag

$env:Path = "$env:ProgramFiles\TortoiseSVN\bin;$env:Path"

# Remplacer le trunk par le build propre
$trunk = "C:\Temp\opencode\$slug-svn\trunk"
Get-ChildItem -Path $trunk -Force | Where-Object { $_.Name -ne '.svn' } | Remove-Item -Recurse -Force
Copy-Item -Path "$dist\*" -Destination $trunk -Recurse -Force

# svn add + commit
Set-Location $trunk
svn add --force --depth infinity .

svn commit --non-interactive --trust-server-cert `
  --username $svnUser --password $svnPass `
  -m "Release 1.1.0 : chaînes source en anglais, réécriture i18n complète, traduction initiale en espagnol (es)"

# Créer un tag (copie SVN distante)
svn copy --non-interactive --trust-server-cert `
  --username $svnUser --password $svnPass `
  -m "Tagging 1.1.0" `
  "https://plugins.svn.wordpress.org/$slug/trunk" `
  "https://plugins.svn.wordpress.org/$slug/tags/1.1.0"

Après le tag distant, forcer une mise à jour locale (les nouveaux tags ne se matérialisent pas complètement dans la copie de travail) :

svn cleanup
svn update --depth infinity --force --non-interactive --trust-server-cert `
  --username $svnUser --password $svnPass "$trunk/../"

10. (Optionnel) Synchroniser le dossier local

Préserver les fichiers qui NE sont PAS dans l'export SVN (.git/, .gitignore, tests/, bin/, etc.) :

$local    = 'C:\Users\...\wp-content\plugins\mon-plugin'
$exportDir = 'C:\Users\...\export-1.1.0'

# Exporter le tag fraîchement créé
svn export "https://plugins.svn.wordpress.org/$slug/tags/1.1.0" $exportDir

# Supprimer UNIQUEMENT les fichiers de la release du dossier local, garder le reste
$releaseNames = (Get-ChildItem $exportDir -Force).Name
foreach ($name in $releaseNames) {
  $localPath = Join-Path $local $name
  if (Test-Path $localPath) { Remove-Item $localPath -Recurse -Force }
}

# Copier l'export sur le dossier local
Copy-Item -Path "$exportDir\*" -Destination $local -Recurse -Force

11. Vérification finale

# Versions en local
Write-Host "header : " (Get-Content "$local\mon-plugin.php" | Select-String -Pattern 'Version:' | Select-Object -First 1).ToString().Trim()
Write-Host "readme : " (Get-Content "$local\readme.txt" | Select-String -Pattern 'Stable tag:' | Select-Object -First 1).ToString().Trim()

# Vérifier le SVN distant
svn ls --recursive "https://plugins.svn.wordpress.org/$slug/tags/1.1.0/"

Conventions critiques de WordPress.org

ConceptRègle
Text DomainDoit être identique au slug du plugin (ex : mon-plugin). Ne changez jamais le slug sans re-soumettre le plugin.
Domain Path/languages/ pour que WP.org trouve le .pot
Plugin Name headerNe pas inclure de marques déposées de tiers au début (la revue WP.org rejette)
readme.txtWP.org parse ce fichier (pas README.md). Le Stable tag doit correspondre à la version.
SVN layout/trunk/ (développement), /tags/X.Y.Z/ (releases), /assets/ (bannières, icône, captures d'écran)
SVN comme système de publication"Seulement pousser des versions prêtes à l'emploi". Pas de commits de développement fréquents sur le trunk.
Fallback des traductionsWP cherche en cascade : text-domain-locale.mo → text-domain.mo → text-domain-en_US.mo (noyau). La racine de locale es dessert TOUTES les variantes es_XX.

Gotchas et erreurs courantes

PowerShell et chemins UNC

PHP et de nombreux binaires échouent si le CWD est un chemin UNC (\\serveur\partage). Avant d'exécuter des commandes :

Set-Location C:\Users\<utilisateur>   # ou tout autre dossier local
php $wpCli ...                # maintenant ça fonctionne

Encodage des caractères accentués en PHP (Windows)

PHP sur Windows a des problèmes avec les littéraux UTF-8 dans les scripts. Solution : utilisez mb_chr(0x00f3) pour chaque caractère accentué :

"Obtener pa" . mb_chr(0x00ed) . "s"  // "Obtener país"

PowerShell peut aussi afficher ? au lieu de caractères accentués avec Get-Content. Vérifiez les octets du fichier, pas le rendu :

$bytes = [System.IO.File]::ReadAllBytes('fichier.po')
# Chercher 0xC3 0xB3 (UTF-8 de 'ó')

La copie de travail SVN semble vide après un nouveau tag

SVN déduplique les fichiers entre le trunk et le tag (même "blob"). Après svn copy distant, les fichiers apparaissent sur le serveur mais la copie de travail locale a des placeholders. Solution : svn cleanup + svn update --depth infinity --force.

svn.exe n'est pas dans le PATH

TortoiseSVN s'installe dans C:\Program Files\TortoiseSVN\bin\ mais n'ajoute pas svn.exe au PATH par défaut. Solution temporaire :

$env:Path = "$env:ProgramFiles\TortoiseSVN\bin;$env:Path"

Ou ajouter de manière permanente au PATH de l'utilisateur.

Le plugin utilise des chaînes en espagnol dans le header

Les chaînes du header du plugin (Plugin Name, Description, etc.) NE sont PAS traduisibles. Mais si wp i18n les inclut dans le .pot, laissez-les avec msgstr "" (vide). WP.org et GlotPress savent qu'elles ne sont pas traduites.

Ne pas inclure de .po/.mo pour les locales gérées par GlotPress

Une fois que GlotPress a des traductions pour votre plugin (via la communauté), WP.org fournit automatiquement les .mo. Vos .po/.mo initiaux sont uniquement le seed initial. Ne luttez pas contre GlotPress.


Fichiers modifiés par la release (checklist)

  • my-plugin.php — header Version + PLUGIN_VERSION
  • readme.txt — Stable tag + entrée dans Changelog
  • CHANGELOG.md — nouvelle entrée
  • languages/<text-domain>.pot — régénéré
  • languages/<text-domain>-es.po — nouvelle traduction initiale
  • languages/<text-domain>-es.mo — compilé

Note : L'outil utilise PowerShell et des scripts PHP pour fonctionner sous Windows, mais les concepts (réécriture i18n, builds propres, SVN) sont universels.

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

Skills associés