wordpress-internationalization
Skill19 starsChanged 11 days agoMITView on GitHub
Use when implementing WordPress i18n/l10n, adding translation functions, generating POT files, or preparing themes/plugins for translation. Keywords: i18n, l10n, internationalization, localization, translation, POT file, gettext, multilingual, WordPress translate
In this repository16 other files it gives its agents.
- CLAUDE.mdCLAUDE.md
- block-pattern-creationSkill
- canva-to-fse-autonomous-workflowSkill
- create-blog-articleSkill
- figma-to-fse-autonomous-workflowSkill
- fse-block-theme-developmentSkill
- fse-pattern-first-architectureSkill
- indesign-conversionSkill
- lintSkill
- scaffold-blockSkill
- testSkill
- visual-qa-verificationSkill
- wordpress-hook-integrationSkill
- wordpress-security-hardeningSkill
- wordpress-testing-workflowsSkill
- wp-cli-workflowsSkill
The file
We split this skill into the rules it gives an agent
4 rules. About 0 are common, 3 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 16
Use this skill when:
- Distinctive: line 221
When the figma-fse-converter agent generates block patterns, all visible strings MUST be wrapped in translation functions.
- Distinctive: line 225
Every PHP pattern file registers visible text.
- Very specific: line 279
All visible text in <h1>-<h6>, <p>, <a>, <span>, <button> gets esc_html__()
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
WordPress Internationalization (i18n/l10n)
Overview
WordPress internationalization (i18n) prepares code for translation, while localization (l10n) provides actual translations. Proper i18n requires using translation functions, setting up text domains, and generating POT files for translators.
Core Principle: Wrap ALL user-facing strings in translation functions, use consistent text domain, generate POT files with WP-CLI, never hardcode English text.
When to Use
Use this skill when:
- Preparing theme or plugin for translation
- Adding translation functions to code
- Generating POT files for translators
- Setting up language loading
- Handling pluralization
- Supporting RTL languages
Symptoms that trigger this skill:
- "translate"
- "i18n"
- "l10n"
- "multilingual"
- "POT file"
- "localization"
- "translation ready"
- "generate pattern" (FSE pattern generation should include i18n)
- "create pattern" (block patterns must wrap visible strings)
Quick Reference
Translation Functions
| Function | Use For | Example |
__() | Return translated string | $title = __( 'Title', 'textdomain' ); |
_e() | Echo translated string | _e( 'Welcome', 'textdomain' ); |
_x() | Translated with context | _x( 'Post', 'noun', 'textdomain' ); |
_n() | Pluralization | _n( '1 item', '%d items', $count, 'textdomain' ); |
esc_html__() | Translate + escape HTML | esc_html__( 'Title', 'textdomain' ); |
esc_html_e() | Echo translated + escaped | esc_html_e( 'Title', 'textdomain' ); |
esc_attr__() | Translate + escape attribute | esc_attr__( 'Title', 'textdomain' ); |
esc_attr_e() | Echo translated + escaped attr | esc_attr_e( 'Title', 'textdomain' ); |
Context-Aware Translation
// Without context - ambiguous
__( 'Post', 'textdomain' ); // Verb or noun?
// With context - clear meaning
_x( 'Post', 'verb: publish content', 'textdomain' );
_x( 'Post', 'noun: blog post', 'textdomain' );Implementation Patterns
Pattern 1: Theme i18n Setup
File: functions.php
<?php
/**
* Load theme text domain for translations
*/
function mytheme_load_textdomain() {
load_theme_textdomain( 'mytheme', get_template_directory() . '/languages' );
}
add_action( 'after_setup_theme', 'mytheme_load_textdomain' );File: style.css (theme header)
/*
Theme Name: My Theme
Text Domain: mytheme
Domain Path: /languages
*/Pattern 2: Plugin i18n Setup
File: my-plugin.php
<?php
/**
* Plugin Name: My Plugin
* Text Domain: myplugin
* Domain Path: /languages
*/
function myplugin_load_textdomain() {
load_plugin_textdomain( 'myplugin', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
}
add_action( 'plugins_loaded', 'myplugin_load_textdomain' );Pattern 3: Translation in Templates
<!-- WRONG: Hardcoded English -->
<h1>Welcome to Our Site</h1>
<p>We have 5 products available.</p>
<!-- CORRECT: Translatable -->
<h1><?php esc_html_e( 'Welcome to Our Site', 'mytheme' ); ?></h1>
<p><?php
printf(
esc_html_n(
'We have %d product available.',
'We have %d products available.',
$product_count,
'mytheme'
),
number_format_i18n( $product_count )
);
?></p>Pattern 4: Generating POT Files
# Generate POT file for theme
wp i18n make-pot wp-content/themes/mytheme wp-content/themes/mytheme/languages/mytheme.pot
# Generate POT file for plugin
wp i18n make-pot wp-content/plugins/myplugin wp-content/plugins/myplugin/languages/myplugin.pot
# Generate with specific domain
wp i18n make-pot . languages/mytheme.pot --domain=mythemePattern 5: JavaScript i18n
<?php
// Enqueue script with translations
function mytheme_enqueue_scripts() {
wp_enqueue_script(
'mytheme-script',
get_template_directory_uri() . '/assets/js/script.js',
array(),
'1.0.0',
true
);
// Set translations for JavaScript
wp_set_script_translations(
'mytheme-script',
'mytheme',
get_template_directory() . '/languages'
);
}
add_action( 'wp_enqueue_scripts', 'mytheme_enqueue_scripts' );
?>JavaScript file:
// Use wp.i18n for translations
import { __ } from '@wordpress/i18n';
const title = __( 'Welcome', 'mytheme' );
const message = sprintf(
_n( 'You have %d new message', 'You have %d new messages', count, 'mytheme' ),
count
);Pattern 6: Pluralization
<?php
// WRONG: Hardcoded plural logic
if ( $count === 1 ) {
echo $count . ' item';
} else {
echo $count . ' items';
}
// CORRECT: Using _n() for proper pluralization
printf(
_n(
'%d item',
'%d items',
$count,
'mytheme'
),
number_format_i18n( $count )
);
?>Pattern 7: Date and Number Localization
<?php
// Date localization
$date = date_i18n( get_option( 'date_format' ), $timestamp );
// Time localization
$time = date_i18n( get_option( 'time_format' ), $timestamp );
// Number localization
$formatted_number = number_format_i18n( 1234567.89 );
// Outputs: 1,234,567.89 (en_US) or 1.234.567,89 (de_DE)
?>i18n in FSE Pattern Generation
When the figma-fse-converter agent generates block patterns, all visible strings MUST be wrapped in translation functions. This is the most common i18n gap in the Figma-to-FSE pipeline.
Pattern PHP Files — Required Wrapping
Every PHP pattern file registers visible text. Wrap it at generation time, not as an afterthought.
<?php
/**
* Title: Hero Section
* Slug: mytheme/hero-section
* Categories: featured
*/
?>
<!-- WRONG: Raw strings in pattern -->
<!-- wp:heading {"level":1} -->
<h1 class="wp-block-heading">Welcome to Our Site</h1>
<!-- /wp:heading -->
<!-- CORRECT: Translated strings in pattern -->
<!-- wp:heading {"level":1} -->
<h1 class="wp-block-heading"><?php echo esc_html__( 'Welcome to Our Site', 'mytheme' ); ?></h1>
<!-- /wp:heading -->Button and Link Text
<!-- WRONG -->
<!-- wp:button -->
<div class="wp-block-button"><a class="wp-block-button__link">Get Started</a></div>
<!-- /wp:button -->
<!-- CORRECT -->
<!-- wp:button -->
<div class="wp-block-button"><a class="wp-block-button__link"><?php echo esc_html__( 'Get Started', 'mytheme' ); ?></a></div>
<!-- /wp:button -->Attribute Values (alt text, aria-labels)
<!-- CORRECT: Escaped for attribute context -->
<img src="<?php echo esc_url( get_theme_file_uri( 'assets/images/hero.webp' ) ); ?>"
alt="<?php echo esc_attr__( 'Hero background image', 'mytheme' ); ?>" />What NOT to Translate in Patterns
- Block comment markup (
<!-- wp:heading -->) — never translate - CSS class names — never translate
- theme.json token slugs (
var(--wp--preset--color--primary)) — never translate - HTML tag names and attributes — never translate
Integration with figma-fse-converter Agent
The figma-fse-converter agent should apply these rules during pattern generation:
- All visible text in
<h1>-<h6>,<p>,<a>,<span>,<button>getsesc_html__() - All
altattributes getesc_attr__() - Text domain matches the theme slug from
style.css - POT file generation runs after all patterns are created
Common Mistakes
1. Hardcoding English Text
WRONG:
echo '<h1>Welcome</h1>';CORRECT:
echo '<h1>' . esc_html__( 'Welcome', 'mytheme' ) . '</h1>';2. Translating Variables
WRONG:
// Dynamic variable - cannot be translated
$text = $some_variable;
echo __( $text, 'mytheme' );CORRECT:
// Static string with variable placeholder
echo sprintf(
__( 'Hello, %s!', 'mytheme' ),
esc_html( $user_name )
);3. Not Escaping Translated Strings
WRONG:
echo __( 'Title', 'mytheme' ); // No escapingCORRECT:
echo esc_html__( 'Title', 'mytheme' ); // Combined translate + escape4. Inconsistent Text Domain
WRONG:
__( 'Text 1', 'mytheme' );
__( 'Text 2', 'my-theme' ); // Different text domain
__( 'Text 3', 'mytheme-plugin' ); // Another different domainCORRECT:
__( 'Text 1', 'mytheme' );
__( 'Text 2', 'mytheme' );
__( 'Text 3', 'mytheme' );5. Not Using number_format_i18n()
WRONG:
echo number_format( 1234567, 2 ); // Hardcoded comma separatorCORRECT:
echo number_format_i18n( 1234567, 2 ); // Locale-specific formattingNo Exceptions
NEVER skip these i18n practices:
- ✅ Wrap ALL user-facing text - No hardcoded English
- ✅ Use consistent text domain - One domain per theme/plugin
- ✅ Escape translated strings - Use esc_html__(), esc_attr__()
- ✅ Use pluralization functions - _n() for countable items
- ✅ Generate POT files - For translators to use
- ✅ Use date_i18n() for dates - Locale-specific formatting
- ✅ Provide context when ambiguous - _x() with context
Translation Workflow
1. Developer writes code with translation functions
↓
2. Generate POT file with WP-CLI
↓
3. Translator creates PO file from POT (e.g., fr_FR.po)
↓
4. Compile PO to MO file (binary)
↓
5. Place MO file in /languages/ directory
↓
6. WordPress loads translations automaticallyIntegration with This Template
This skill works with:
- figma-to-fse-autonomous-workflow skill - i18n during Figma-to-FSE conversion
- figma-fse-converter agent - Pattern generation with translation wrappers
- fse-block-theme-development skill - i18n in block themes
- block-pattern-creation skill - Translatable patterns
- wp-cli-workflows skill - Generating POT files with WP-CLI
Resources
- WordPress I18n Handbook
- WP-CLI I18n Command
- Translating WordPress
- GlotPress - Translation management
Skill Version: 1.1.0 Last Updated: 2026-03-06 Testing Methodology: RED-GREEN-REFACTOR (TDD for documentation)
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

