Internationalization (i18n) – Blocks

Updated:

Categories:

This guide provides comprehensive instructions for implementing internationalization in WordPress blocks.

Table of Contents

  1. Overview
  2. PHP Internationalization
  3. JavaScript Internationalization
  4. Multiple Block Registration
  5. Translation File Generation
  6. Translation Workflow
  7. Testing Translations
  8. Best Practices

Overview

Internationalization (i18n) is the process of preparing your code to support multiple languages. WordPress provides robust i18n functions for both PHP and JavaScript that allow translators to create localized versions of your blocks.

Key Principles

  • Text Domain: Use a consistent text domain throughout your block
  • Context: Provide meaningful context for translators
  • Escaping: Always use proper escaping functions for security
  • Consistency: Maintain consistent naming conventions

PHP Internationalization

Basic Functions

Use WordPress i18n functions with proper escaping:

Context Examples

Provide clear context to help translators understand where and how the text is used:

  • 'Block card - component label'
  • 'Block card - screen reader text'
  • 'Block card - select dropdown label'
  • 'Block card - button label'
  • 'Block card - rich text placeholder'
  • 'Block card - error message'
  • 'Block card - help text'

Example Implementation


JavaScript Internationalization

Setup

Import the i18n functions from WordPress:

Usage in Components

Rich Text Placeholders


Multiple Block Registration

When registering multiple related blocks (e.g., parent and child blocks), ensure each has proper translation support:

Important Notes

  • Use the same text domain for related blocks
  • Ensure script handles match those registered in block.json or wp_register_script()
  • The translation path should point to your languages directory
  • For parent + child blocks sharing one textdomain: wp i18n make-json generates one JSON per .js source file. Rename each to its respective handle (e.g., prompt-this-fr_CA-zp-prompt-this-editor-script.json and prompt-this-fr_CA-zp-prompt-this-item-editor-script.json)

Translation File Generation

Package.json Scripts

Add these scripts to your package.json:

Script Parameters Explained

  • --slug: The block/plugin slug
  • --domain: Your text domain
  • --exclude: Directories to exclude from scanning
  • --no-purge: Keeps existing JSON files when generating new ones

Translation Workflow

Initial Setup

  1. Install Dependencies npm install
  2. Generate POT File npm run make-pot
    • Creates languages/ directory
    • Generates your-block-name.pot file with all translatable strings
  3. Create Translation with Poedit
    • Open Poedit
    • File → New from POT/PO file
    • Select your .pot file
    • Choose target language (e.g., French (Canada))
    • Translate strings
    • Save (creates .po and .mo files)

Updating Existing Translations

  1. Update POT Filenpm run make-pot
  2. Update PO Filesnpm run update-po Or in Poedit: Catalog → Update from POT file
  3. Recompile .mo File
    • Poedit: Save → automatically generates .mo
    • msgfmt fr_CA.po -o your-domain-fr_CA.mo (if gettext is installed)
    • Fallback: WordPress POMO library (PO::import_from_file() → MO::export_to_file())
  4. Generate JSON Filesnpm run make-json
  5. Rename JSON Files
    • Generated file: your-block-name-fr_CA-{hash}.json
    • Rename to: your-block-name-fr_CA-your-script-handle.json
    • Example: cards-fr_CA-zp4-cards-editor-script.json

File Structure


Block.json Metadata vs JavaScript Translations

WordPress uses two separate translation mechanisms for blocks. Understanding the difference is critical:

JavaScript Strings (edit.js)

Strings in edit.js using _x(), __(), or _n() are handled by the JSON translation file:

  • Extracted by wp i18n make-pot scanning the compiled build/ output
  • Converted to JSON by wp i18n make-json
  • Loaded via wp_set_script_translations( $handle, $domain, $path )
  • File: {domain}-{locale}-{script-handle}.json

Block.json Metadata (title, description, keywords)

These fields in block.json are not handled by the JSON file. WordPress automatically wraps them in _x() calls during register_block_type() and injects them as an inline script:

This requires the .mo file to be loaded before register_block_type() runs. The .mo file must follow the naming convention {text-domain}-{locale}.mo (e.g., summary-fr_CA.mo).

Common Pitfall: .mo File Not Found

If block.json metadata fields appear untranslated in the editor, check:

  1. The .mo file is named {text-domain}-{locale}.mo (not just {locale}.mo like fr_CA.mo)
  2. The textdomain (.mo file) is loaded before register_block_type() runs on the init hook
  3. The textdomain field in block.json matches the loaded textdomain

Testing Translations

WordPress Admin Testing

  1. Switch Language
    • Go to Settings → General
    • Change Site Language to your test language
    • Save changes
  2. Test Block Editor
    • Create/edit a page
    • Add your block
    • Verify all UI elements are translated
    • Check tooltips, placeholders, and error messages
  3. Test Frontend
    • Visit the page on frontend
    • Verify PHP translations are working
    • Check accessibility labels

Development Testing


Best Practices

String Guidelines

  • Be descriptive: Use clear, concise strings that provide context
  • Avoid concatenation: Don’t split sentences across multiple translation calls
  • Use placeholders: For dynamic content, use sprintf() with placeholders
  • Consider length: Account for text expansion in different languages

Context Best Practices

Performance Considerations

  • Load translations only when needed
  • Use wp_set_script_translations() after script registration
  • Consider lazy loading for large translation files

Accessibility

  • Translate aria-label and aria-describedby attributes
  • Provide translated screen reader text
  • Ensure translated text maintains semantic meaning

Version Control

  • Include .pot files in version control
  • Include .po files for supported languages
  • Consider excluding .mo files (can be generated from .po)
  • Include properly named .json files

Common Pitfalls

  • Inconsistent text domains: Use the same domain across all files
  • Missing script translations: Remember wp_set_script_translations()
  • Incorrect JSON naming: Ensure JSON files match script handles
  • Hard-coded strings: Always use translation functions
  • Missing context: Provide meaningful context for translators

Troubleshooting

Translations Not Loading

  1. Check script handle matches in wp_set_script_translations()
  2. Verify JSON file naming convention
  3. Ensure text domain consistency
  4. Confirm languages/ directory path is correct

Missing Strings in POT

  1. Verify text domain in translation functions
  2. Check file extensions in make-pot exclude list
  3. Ensure functions are properly formatted

Frontend vs. Editor Issues

  • PHP translations: Check .mo file loading
  • JavaScript translations: Verify JSON file naming and script registration

This guide should be updated as WordPress i18n best practices evolve. Always refer to the WordPress Developer Handbook for the latest information.