Contents
Introduction
This tutorial covers everything needed to generate .pot files for WordPress projects using the WP-CLI i18n command. It explains prerequisites, installation, options, common problems, best practices, automation examples, and step-by-step commands for themes and plugins. Examples and copy-paste commands are provided in runnable form.
Prerequisites
- WordPress project (theme or plugin code with gettext functions such as __(), _e(), _n(), _x(), _ex(), _nx(), esc_html__(), esc_attr__(), etc.).
- WP-CLI installed and available on the command line. See WP-CLI.
- WP-CLI i18n package (wp-cli/i18n-command) installed as a WP-CLI package (installation instructions below).
- PO/MO tools for translators: Poedit, gettext utilities (msgfmt/msginit/xgettext), or any PO editor.
- Files must be encoded as UTF-8 (without BOM). Non-UTF-8 or BOM may break extraction.
Install or enable the WP-CLI i18n command
If the i18n command is not available, install it as a WP-CLI package:
wp package install wp-cli/i18n-command
Verify the command is available:
wp i18n --help
Basic usage: generate a .pot file
The canonical command is:
wp i18n make-pot ltsource-dirgt ltpot-filegt [--domain=lttext-domaingt] [--slug=ltsluggt] [options]
Common practical examples follow.
Generate a .pot for a plugin
wp i18n make-pot ./wp-content/plugins/my-plugin ./wp-content/plugins/my-plugin/languages/my-plugin.pot --domain=my-plugin --slug=my-plugin
Run this from your project root (or adjust paths accordingly). This command scans PHP and JavaScript files (by default) and writes a POT to languages/my-plugin.pot.
Generate a .pot for a theme
wp i18n make-pot ./wp-content/themes/my-theme ./wp-content/themes/my-theme/languages/my-theme.pot --domain=my-theme --slug=my-theme
Key options and what they do
- ltsource-dirgt — Directory to scan (file path or dot for current directory).
- ltpot-filegt — Output POT file path.
- –domain=lttext-domaingt — Text domain to use for creation and header (commonly your plugin/theme slug).
- –slug=ltsluggt — Sets the Project-Id-Version and Report-Msgid-Bugs-To headers useful for naming/versioning in the POT header.
- –exclude=ltpathsgt — Comma-separated paths to exclude (vendor,node_modules,tests,build,dist).
- –include=ltpathsgt — Comma-separated list of file globs to include (if you need to limit scanning).
- –skip-js — Do not scan JavaScript files.
- –skip-php — Do not scan PHP files (rare).
- –merge=ltfilegt — Merge existing POT file entries (useful to preserve translator comments).
- –merge-domain=ltdomaingt — Specify the text domain of the POT being merged.
- –keywords=ltkeywordgt — Add or override keywords (translation functions) and their argument positions—useful for custom wrapper functions.
- –project=ltproject-namegt — Set Project-Id-Version header manually.
- –buffer=ltbytesgt — Increase buffer when scanning huge projects.
- –debug, –porcelain, –allow-root — Misc developer/debug options.
Common, practical examples
Exclude node_modules and vendor
wp i18n make-pot . languages/project.pot --domain=project --exclude=node_modules,vendor,tests
Only scan a plugin directory (safe, fast)
wp i18n make-pot wp-content/plugins/my-plugin wp-content/plugins/my-plugin/languages/my-plugin.pot --domain=my-plugin
Specify extra custom translation keywords
If you have custom wrapper functions (for example my_translate( text, domain )), tell the extractor how to treat them:
wp i18n make-pot . languages/project.pot --keywords=__ --keywords=_e --keywords=my_translate:1,2
Keyword formats: functionName, functionName:arg-num, functionName:arg-num,context (see xgettext format). Add as many –keywords flags as needed.
Merge with an existing POT to retain manual changes or comments
wp i18n make-pot ./wp-content/plugins/my-plugin ./languages/my-plugin.pot --merge=./languages/my-plugin.pot --domain=my-plugin
Merging is useful when you want to preserve translator notes or header fields from an existing POT while refreshing strings.
Generating POT for a multi-component project (plugins theme)
# Generate one consolidated POT for the entire repository, excluding third-party dirs: wp i18n make-pot . languages/project.pot --domain=project --exclude=vendor,node_modules,tests
Example: Proper plugin file headers and loading text domain
Ensure your plugin or theme has a correct text domain and loads translations. This helps the extractor and translators.
Post-generation: working with POT, PO and MO
- Give the .pot file to translators or import into Poedit.
- Translators create language-specific .po files (e.g., my-plugin-fr_FR.po).
- Compile .po into .mo for distribution using msgfmt or Poedit’s export features.
Example using gettext utilities
# Initialize a new PO for French (creates my-plugin-fr_FR.po) msginit --input=languages/my-plugin.pot --locale=fr_FR --output-file=languages/my-plugin-fr_FR.po # Compile a PO into an MO that WP can load msgfmt -o languages/my-plugin-fr_FR.mo languages/my-plugin-fr_FR.po
Best practices
- Keep translations inside a languages/ folder at the root of your plugin or theme (common convention).
- Name POT file after your project, e.g., languages/my-plugin.pot or languages/my-theme.pot.
- Exclude third-party libraries (vendor/, node_modules/) to avoid noise in POT files.
- Use consistent text domain matching plugin slug and header Text Domain value.
- Avoid dynamic string concatenation in translation functions — use placeholders sprintf() instead. xgettext requires static string literals.
- File encoding: UTF-8 without BOM for accurate extraction.
- Document custom translation wrappers by adding --keywords flags to your generation script.
- Automate POT generation in your release pipeline to keep translators up to date.
Automation examples
npm / package.json script
{ scripts: { make-pot: wp i18n make-pot ./wp-content/plugins/my-plugin ./wp-content/plugins/my-plugin/languages/my-plugin.pot --domain=my-plugin --exclude=node_modules,vendor } }
Composer script
{ scripts: { make-pot: [ wp i18n make-pot ./wp-content/themes/my-theme ./wp-content/themes/my-theme/languages/my-theme.pot --domain=my-theme --exclude=node_modules,vendor ] } }
GitHub Actions step (example)
- name: Generate POT run: wp package install wp-cli/i18n-command wp i18n make-pot ./wp-content/plugins/my-plugin ./wp-content/plugins/my-plugin/languages/my-plugin.pot --domain=my-plugin --exclude=node_modules,vendor
Troubleshooting common issues
- No strings found — Verify your project uses WordPress gettext functions with a proper text domain, and that the extraction directory is correct. Check that strings are not concatenated at runtime (xgettext requires literal strings).
- Wrong text domain — Ensure the Text Domain header in your plugin/theme file matches the domain you pass to --domain or the one used in gettext functions.
- Non-UTF-8 or BOM in files — Convert files to UTF-8 without BOM. Many extractors fail on BOM.
- Custom wrappers not detected — Add --keywords entries describing function argument positions.
- Large projects memory or buffer issues — Use --buffer to increase memory buffer, exclude big directories, or scan subdirectories individually.
- Header fields — Use --project and --slug to set Project-Id-Version and other header values if needed.
Advanced tips
- Keep translators’ context — Use translators comments (/ translators: ... /) above the translation function to provide context. The extractor will include them in PO entries.
- Plural forms — Use proper plural functions (_n(), _nx(), etc.) so plural forms are extracted correctly.
- JavaScript translations — WP i18n command extracts strings from JavaScript (unless --skip-js). For modern JS using wp.i18n/tinyten, also consider wp i18n make-json to generate translation JSON for JS contexts.
- Continuous integration — Regenerate POT on each release or when strings change. Commit POT together with release branch or publish it to a translation platform.
Example workflow (concise)
- Ensure plugin/theme has proper Text Domain and load__textdomain() call.
- Install WP-CLI and the i18n package:
wp package install wp-cli/i18n-command
- Run extractor for your specific plugin/theme directory:
wp i18n make-pot ./wp-content/plugins/my-plugin ./wp-content/plugins/my-plugin/languages/my-plugin.pot --domain=my-plugin --exclude=node_modules,vendor
- Distribute the .pot to translators or import it in Poedit/translation platform.
- Receive .po files, compile to .mo and ship in languages/ or push to translate.wordpress.org as appropriate.
Summary
WP-CLI i18n is a reliable, scriptable way to generate .pot files for WordPress projects. Key points: install the wp-cli/i18n-command package, keep a consistent text-domain, exclude third-party directories, add custom keywords when needed, automate the command in builds/releases, and ensure files are UTF-8. Use the examples above to integrate POT generation in your workflow.
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |