Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Internationalisation for WordPress Developers

Internationalisation for WordPress Developers

In this presentation I cover the concepts and terminology of internationalisation, the three core steps needed to internationalise your WordPress plugin or theme, some best practices, and advanced considerations to make the lives of your translators easier.

Video: https://wordpress.tv/2016/05/30/john-blackbourn-internationalisation-for-wordpress-developers/

This session has been presented at:

* Global WordPress Translation Day, April 2016
* WordCamp Europe Contributor Day, June 2016
* WordCamp Brighton Contributor Day, July 2016
* WordSesh, August 2016

23e12888dcd87d07434b7621bc164958?s=128

John Blackbourn

June 26, 2016
Tweet

Transcript

  1. Internationalisation for WordPress Developers

  2. Best Practices for Internationalising Themes and Plugins

  3. Terminology Translation Localisation Internationalisation t9n l10n i18n

  4. Terminology Translation Localisation Internationalisation t9n l10n i18n 18

  5. Internationalisation for WordPress Developers

  6. i18n for w7s d8s

  7. Say no to Concatenation echo $post_type . ' updated'; echo

    'You have ' . $number . ' posts';
  8. $text = 'Hello, World!'; $text = __( 'Hello, World!', 'my-plugin'

    ); Step 1: __() and _e()
  9. __() and _e() echo 'Hello, World!'; _e( 'Hello, World!', 'my-plugin'

    ); echo __( 'Hello, World!', 'my-plugin' ); Step 1:
  10. echo 'Hello, World!'; _e( 'Hello, World!', 'my-plugin' ); echo __(

    'Hello, World!', 'my-plugin' ); Step 1: __() and _e()
  11. Loading MO Files Step 2: add_action( 'init', function() { load_plugin_textdomain(

    'my-plugin', false, dirname( __FILE__ ) . '/languages' ); } );
  12. Loading MO Files Step 2: add_action( 'after_setup_theme', function() { load_theme_textdomain(

    'my-theme', get_template_directory() . '/languages' ); } );
  13. wp-content/plugins/my-plugin/languages

  14. Localised Headers Step 3: /* Plugin Name: My Plugin Author:

    John Blackbourn Description: My excellent plugin Version: 1.0 Text Domain: my-plugin Domain Path: /languages */
  15. Localised Headers Step 3: /* Theme Name: My Theme Author:

    John Blackbourn Description: My excellent theme Version: 1.0 Text Domain: my-plugin Domain Path: /languages */
  16. Step 1: __() and _e() Step 2: Loading MO Files

    Step 3: Localised Headers
  17. Context _e( 'Comment', 'my-plugin' ); // A comment _e( 'Comment',

    'my-plugin' ); // To comment
  18. Context _ex( 'Comment', 'noun', 'my-plugin' ); _ex( 'Comment', 'verb', 'my-plugin'

    ); via _x() and _ex() Kommentar / Kommentieren
  19. Context /* translators: column name header */ $col = __(

    'Comments', 'my-plugin' ); via translator comments
  20. Context _x() and _ex() Used to disambiguate text for translation

    Translator Comments Used to provide further context for translators
  21. Formatted Strings $text = __( 'Hello, World!', 'my-plugin' ); $text

    = __( "Hello, {$name}!", 'my-plugin' ); No!
  22. Formatted Strings $text = __( 'Hello, ', 'my-plugin' ); $text

    .= $name; $text .= __( '!', 'my-plugin' ); No!
  23. Formatted Strings $text = sprintf( /* translators: 1: user name

    */ __( 'Hello, %s!', 'my-plugin' ), $name ); via sprintf()
  24. Numbers $text = __( "You have {$count} posts", 'my-plugin' );

    No!
  25. Numbers $text = sprintf( /* translators: 1: number of posts

    */ _n( '%s Post', '%s Posts', $count, 'my-plugin' ), $count ); via sprintf() and _n()
  26. Numbers if ( 1 === $deleted ) { $message =

    __( 'Theme deleted.' ); } else { $message = _n( '%s theme deleted.', '%s themes deleted.', $deleted ); } via sprintf() and _n()
  27. Numbers $label = _n_noop( 'Image (%s)', 'Images(%s)' ); echo sprintf(

    translate_nooped_plural( $label, $count ), $count ); via _n_noop()
  28. Punctuation $text = __( 'Next Post', 'my-plugin' ); $text .=

    '»'; No!
  29. Punctuation $text = __( 'Next Post »', 'my-plugin' ); Better

  30. Security _e( 'Hello, World!', 'my-plugin' );

  31. Security _e( 'Hello, World!', 'my-plugin' ); // <script>alert("Hello!")</script>

  32. Security esc_html_e( 'Hello, World!', 'my-plugin' ); // &lt;script&gt;alert("Hello!")&lt;/script&gt;

  33. Security esc_attr__() esc_html__() esc_attr_e() esc_html_e() esc_attr_x() esc_html_x() esc_html( __n( ...

    ) )
  34. HTML in Strings $text = sprintf( /* translators: 1: user

    name */ __( 'Hello, %s!', 'my-plugin' ), $name );
  35. HTML in Strings $text = sprintf( /* translators: 1: user

    name */ __( 'Hello, <b>%s</b>!', 'my-plugin' ), $name ); Not great
  36. HTML in Strings $text = sprintf( /* translators: 1: user

    name */ __( 'Hello, %s!', 'my-plugin' ), '<b>' . $name . '</b>' ); Better
  37. i18n Tools translate.wordpress.org

  38. i18n Tools develop.svn.wordpress.org trunk -> tools -> i18n Poedit

  39. i18n Tools I18n for WordPress Developers More Information: developer.wordpress.org/plugins and

  40. Test Your Knowledge! WordPress Developers: Test your i18n knowledge!

  41. Internationalisation for WordPress Developers Questions!