Top Banner
Internationalization for Plugin and Theme Developers Sergey Biryukov WordCamp Milano 2016
30

I18n for Plugin and Theme Developers, WordCamp Milano 2016

Jan 13, 2017

Download

Internet

Sergey Biryukov
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Internationalization forPlugin and Theme Developers

Sergey Biryukov

WordCamp Milano 2016

Page 2: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Sergey Biryukov● WordPress Core Contributor at Yoast

yoast.com● Co-founder of Russian WP community

ru.wordpress.org● Polyglots, Support, and Meta teams

sergeybiryukov.com@SergeyBiryukov

Page 3: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Plugins and Themes for the Whole World

● Internationalization (i18n) — providing the ability to translate● Localization (L10n) — translating to a particular language

Page 4: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Plugins and Themes for the Whole World

● Over 100 languages● More robust code● Feedback● It’s easy

Page 5: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Localized Theme Directories

Page 6: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Localized Plugin Directories

Page 7: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Introduction to gettext

● Text domain– 'my-plugin'

● Preparing the strings– <?php echo 'Title'; ?>→<?php _e( 'Title', 'my-plugin' ); ?>

● Language files– .pot, .po, .mo

Page 8: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Text Domain

● Should match the plugin/theme slug (folder name):– wp-content/plugins/my-plugin→'my-plugin'

– wp-content/themes/my-theme→'my-theme'

● Should be added to plugin/theme headers:– Plugin Name: My Plugin

– Version: 1.0

– Text Domain: my-plugin

Page 9: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Text Domain

● Loading the text domain– load_plugin_textdomain( 'my-plugin', false,

dirname( plugin_basename( __FILE__ ) ) . '/languages' );

– load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );

Page 10: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Text Domain

● Loading the text domain– load_plugin_textdomain( 'my-plugin', false,

dirname( plugin_basename( __FILE__ ) ) . '/languages' );

– load_theme_textdomain( 'my-theme', get_template_directory() . '/languages' );

● wp-content/languages (WordPress 4.6+)

Page 11: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Preparing the Strings

● Regular strings:– __( 'Hello world!', 'my-plugin' );

– _e( 'Hello world!', 'my-plugin' );

● Strings with context:– _x( 'Hello world!', 'post title', 'my-plugin' );

– _ex( 'Hello world!', 'post title', 'my-plugin' );

Page 12: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Preparing the Strings

● Plural forms:– _n( '%d item', '%d items', $count, 'my-plugin' );

– _nx( '%d item', '%d items', $count, 'comments', 'my-plugin' );

● If the number is not available yet:– _n_noop( '%d item', '%d items', 'my-plugin' );

– _nx_noop('%d item', '%d items', 'comments', 'my-plugin' );

Page 13: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Preparing the Strings

● Escaping HTML tags:– esc_html__( 'Hello <em>world</em>!', 'my-plugin' );

– esc_html_e( 'Hello <em>world</em>!', 'my-plugin' );

– esc_html_x( 'Hello <em>world</em>!', 'post title', 'my-plugin' );

● Escaping HTML attributes:– esc_attr__( 'Hello "world"!', 'my-plugin' );

– esc_attr_e( 'Hello "world"!', 'my-plugin' );

– esc_attr_x( 'Hello "world"!', 'post title', 'my-plugin' );

Page 14: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Preparing the Strings

● Escaping HTML tags and attributes:– <option value="<?php esc_attr_e( 'value', 'my-plugin' ); ?>">

<?php esc_html_e( 'Option label', 'my-plugin' ); ?></option>

● Same, in a longer notation:– <option value="<?php echo esc_attr( __( 'value', 'my-plugin' ) ); ?>">

<?php echo esc_html( __( 'Option label', 'my-plugin' ) ); ?></option>

Page 15: I18n for Plugin and Theme Developers, WordCamp Milano 2016

_e() ≠ echo()

● Don’t use PHP variables, only simple strings:– _e( $string ); — don’t do that.

● Provide the ability to translate whole phrases, not separate words:– echo __( 'Hello' ) . ' ' . __( 'world!' ); — don’t do that either.

● Don’t forget the text domain:– _e( 'Hello world!', 'my-plugin' );

● Remove unnecessary HTML markup from the strings:– _e( '<p>Hello world!</p>', 'my-plugin' );

Page 16: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Context and Comments

● Context — same string, different translations:– _x( 'redirect', 'noun', 'my-plugin' );

– _x( 'redirect', 'verb', 'my-plugin' );

● Comments — to explain placeholders in a string:– /* translators: %s: file name */

__( '%s was deleted.', 'my-plugin' );

Page 17: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Plural Forms

● ???– _e( "You have $count items.", 'my-plugin' );

– _e( 'You have ' . $count . ' items.', 'my-plugin' );

– printf( __( 'You have %d items.', 'my-plugin' ), $count );

– printf( _n( 'You have %d item.', 'You have %d items.', $count ), $count );

Page 18: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Plural Forms

● Incorrect:– _e( "You have $count items.", 'my-plugin' );

– _e( 'You have ' . $count . ' items.', 'my-plugin' );

– printf( __( 'You have %d items.', 'my-plugin' ), $count );

● Almost correct:– printf( _n( 'You have %d item.', 'You have %d items.', $count ),

$count );

Page 19: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Plural Forms

● Correct:– printf( _n( 'You have %d item.', 'You have %d items.', $count ),

number_format_i18n( $count ) );

● number_format_i18n() — for displaying numbers● date_i18n() — for displaying dates

Page 20: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Plural Forms

● If the number is not available:– $items_plural = _n_noop( 'You have %s item.', 'You have %s items',

'my-plugin' );

● ...● After it’s available:

– printf( translate_nooped_plural( $items_plural, $count ), number_format_i18n( $count ) );

● translate_nooped_plural() — for deferred translations of plural strings

Page 21: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Plural Forms

● The first form is not necessarily used for 1 item:– printf( _n( 'Theme deleted.', '%d themes deleted.', $count ),

number_format_i18n( $count ) );

● Better:– if ( 1 === $count ) {

_e( 'Theme deleted.' );– } else {

printf( _n( '%d theme deleted.', '%d themes deleted.', $count ), number_format_i18n( $count ) );

– }

Page 22: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Language Files

● .pot (Portable Object Template)– Translation template, contains English strings only.

● .po (Portable Object)– Language file in a human-readable format.

● .mo (Machine Object)– Compiled language file in a machine-readable format.

Page 23: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Language Files

makepot.php→.pot→Poedit→.po/.mo→email

Page 24: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Plugin Changelog

● Version 1.5.6– Added Russian translation.

– That’s it!

● Version 1.5.6.1– Fixed a typo in Russian translation.

Page 25: I18n for Plugin and Theme Developers, WordCamp Milano 2016

Language Files

makepot.php→.pot→Poedit→.po/.mo→email

translate.wordpress.org

Page 26: I18n for Plugin and Theme Developers, WordCamp Milano 2016

translate.wordpress.org

Page 27: I18n for Plugin and Theme Developers, WordCamp Milano 2016

translate.wordpress.org

● GTE (General Translation Editor) — locale editors– Can check and approve all translations.

● PTE (Project Translation Editor) — project editors– Can approve translations for a particular project.

● Translators– Can suggest translations.

Page 28: I18n for Plugin and Theme Developers, WordCamp Milano 2016

If Someone Has Sent You Their Translation

● Ask them to create a WordPress.org account– They can be added as a Project Translation Editor.

– They would be able to import the .po file themselves.

– ...and continue translating in the future.

● Ask locale editors to import the files– No guarantee that the plugin will continue to be actively translated.

Page 29: I18n for Plugin and Theme Developers, WordCamp Milano 2016

If Someone Has Sent You Their Translation

● Once the translator has a WordPress.org account:– Go to the Polyglots team blog:

https://make.wordpress.org/polyglots/

– Find the Polyglots Handbook link:https://make.wordpress.org/polyglots/handbook/

– On “Theme & Plugin Directories” page, find a post template for requesting new translation editors.

– Submit your request to the Polyglots blog and wait for a reply.

Page 30: I18n for Plugin and Theme Developers, WordCamp Milano 2016

@SergeyBiryukov

Thanks! Questions?