WordPress plugin localization is extremely simple. This presentation will show you how to localize a WordPress plugin and show you some pretty advanced functions for helping your translators.
1. WordPress Plugin
Localization
By Ronald Huereca
Twitter: @ronalfy
Presented at WordCamp Raleigh
Slides and code available at: http://ithem.es/localize
May 22, 2011
1
2. About Ronald Huereca
Plugin developer at iThemes (the
creators of Builder and BackupBuddy)
Author of the book WordPress and
Ajax
Plugin author of Ajax Edit Comments
Karaoke singer, gamer, and Vodka
drinker (sometimes at the same time)
2
3. What is Localization (aka,
Internationalization)?
Allows your strings to be translated
into multiple languages
Provides a framework to format your
strings in a translatable way
3
4. What are the benefits of
Localization?
Your plugins or themes can be
translated by others
Your audience isn’t limited by one
locale or language
4
6. Example: Un-localized
strings :(
These strings are very sad :(
<div class='wrap'>
! <h2>My Plugin Settings</h2>
! <div class='updated'><p>Plugin Settings have
been saved.</p></div>
</div>
6
7. Example: Localized
strings :-)
These strings are very happy :-)
<div class='wrap'>
! <h2><?php _e( 'My Plugin Settings',
'DOMAIN' ); ?></h2>
! <div class='updated'><p><?php _e( 'Plugin
Settings have been saved.', 'DOMAIN' ); ?></p></
div>
</div>
7
8. How to enable localization
for a plugin?
Use the WordPress ‘init’ action
Function: load_plugin_textdomain (for
plugins)
Function: load_theme_textdomain (for
themes)
8
9. Enabling Localization for a
Plugin
Simple, simple, simple...
<?php
//Plugin header goes here
add_action( 'init', 'pb_msp_init' );
function pb_msp_init() {
! //Admin menu
! add_action( 'admin_menu', 'pb_msp_menu' );
! //Assuming you have a languages folder in your plugin -
Typically run within the 'init' action
! load_plugin_textdomain( 'unique_domain', false, dirname
( plugin_basename( __FILE__ ) ) . '/languages/' );
} //end pb_msp_init
//More functions
?>
9
16. Let’s use the _n() function
Provide a singular string
Provide a plural string
Provide a count integer (e.g., 2 )
16
17. _n( ‘singular’, ‘plural’,
$count, ‘domain’ )
Returns a singular or plural form of a string
<?php
! $total_count = 1;
! if ( $total_count > 1 || $total_count == 0 )
$count = 2;
! else $count = 1;
! printf( _n( 'You have voted %d time', 'You
have voted %d times', $count, 'unique_domain' ),
$total_count );
! //Output is: You have voted 1 time
?>
17
18. What about context?
Context provides... context
How many ways can you interpret blue
(i.e., feeling blue or literally being blue)
18
19. The _x function helps
provide context
It helps your translators figure out
what the string is for
It’ll also make you think, should I use a
different phrase or word?
19
20. _x( ‘string’, ‘context’,
‘domain’ )
Returns a string in a specific context
<?php
! echo _x( 'I am blue today.', 'noun',
'unique_domain' );
! //You are literally blue
! echo _x( 'I am blue today.', 'adjective',
'unique_domain' );
! //You are feeling blue (i.e., depressed) today
?>
20
24. Localizing JavaScript
Queue your script like normal
(wp_enqueue_script)
Provide localization (via
wp_localize_script)
Update your scripts to use it
24
28. Localization Functions
__( ‘string’, ‘domain’ ) - Returns a localized string
_e( ‘string’, ‘domain’ ) - Echos a localized string
_n( ‘singular’, ‘plural’, $count, ‘domain’ ) - Returns a singular or plural
form of a string
_x( ‘string’, ‘context’, ‘domain’ ) - Returns a string in a context (context
can be anything really, but it helps give the translators an idea of what
you’re going for)
esc_html_e or esc_html__ (works like __ and _e, but returns
encoded text)
esc_attr_e or esc_attr__ (works for encoding attribute values)
wp_localize_script - Helper function for localizing JavaScript strings
28
29. Even more...
_nx( ‘singular’, ‘plural’, $number, ‘context’, ‘domain’ ) - Combines the _n
and _x functions
_esc_attr_x( ‘string’, ‘context’, ‘domain’ ) - Like the esc_attr__
function, but with context
_esc_html_x( ‘string’, ‘context’, ‘domain’ ) - Like the esc_html__
function, but with context
_n_noop( ‘singular’, ‘plural’ ) - Provide _n strings for translation, but
will not be translated in the output (yet)
_nx_noop( ‘singular’, ‘plural’, ‘context’ ) - Provide _nx strings for
translation, but will not be translated in the output (yet)
translate_nooped_plural ( $noop_output, $number, ‘domain’ ) - Take
the results from _n_noop and _nx_noop and translate
29
30. And some helper functions
sprintf( ‘string format’, $arg1, $arg2, etc... ) - Returns a formatted string
printf( ‘string format’ $arg1, $arg2, etc...) - Prints a formatted string
30
31. How About a Video Demonstrating
Localization?
31
32. How About a Video Demonstrating
Localization?
31
33. H o w t o G e t Tr a n s l a t o r s ?
Release a useful plugin that is localization ready
Make sure translators can contact you
The translators will come to you
Package their “.mo” file with future releases
Keep track of your translators and notify them before any
major updates (some translators can act as beta testers)
32
34. H o w t o H e l p Tr a n s l a t o r s
Try to minimize da slang, ya know?
Limit jargon and acronomese FTW!
Translate sentences and paragraphs using sprintf or printf
to provide context
Avoid loooooong portions of translatable text - Split at
paragraphs or sentences
Avoid translating single words, and if you do, provide
context (_x function)
Avoid beginning or ending your string with whitespace
Try translating some of your own work - Even if it’s not
going in the final product, it’ll help you see what the
translators see
33
35. How to Generate POT Files
Use Poedit with the path and keywords (ewwwww, and way too
advanced - Would require another presentation)
With Poedit, just generate the “po” file and rename to “pot”. At least
that part is simple.
Use the WordPress Repo to do it (yay!!!)
34
37. <?php _e( ‘Conclusion’ ); ?>
Localization is super easy
Localization can increase your plugin audience
The WordPress Plugin Repo is ideal for generating
“pot” files. Poedit has issues.
36
38. <?php echo __( “Questions?” ); ?>
Slides and code available at: http://ithem.es/localize
37
40. sprintf( ‘string’, [arg1,arg2,
etc...] )
Returns a formatted string
<?php
//%s is for a string placeholder, %d is for an integer (there's a
lot more of these)
echo sprintf( 'My name is %s and I am %d years old', 'Ronald',
29 );
//Output is My name is Ronald and I am 29 years old
//Reuse the same string over again
echo sprintf( 'My name is %1$s and here I am again %1$s and I am
%d years old', 'Ronald', 29 );
//Output is My name is Ronald and here I am again Ronald and I am
29 years old
?>
39
41. printf( ‘string’, [arg1,arg2,
etc...] )
Prints a formatted string
<?php
//%s is for a string placeholder, %d is for an integer (there's a
lot more of these)
printf( 'My name is %s and I am %d years old', 'Ronald', 29 );
//Output is My name is Ronald and I am 29 years old
//Reuse the same string over again
printf( 'My name is %1$s and here I am again %1$s and I am %d
years old', 'Ronald', 29 );
//Output is My name is Ronald and here I am again Ronald and I am
29 years old
?>
40
42. __ and sprintf
sprintf allows you to keep strings in context without concatenation
<?php
! $total_count = 100; //retrieved from somewhere
! $my_localized_string = sprintf( __( 'You have
voted %d times', 'unique_domain' ),
$total_count );
! echo $my_localized_string;
! //Output is: You have voted 100 times
?>
41
45. esc_attr_e( ‘string’,
‘domain’ )
Translates, encodes, and echoes
<a href='http://pluginbuddy.com' title='<?php
esc_attr_e( 'PluginBuddy - The Creators of
BackupBuddy', 'unique_domain' ); ?
>'>PluginBuddy</a>
44
46. esc_attr__( ‘string’,
‘domain’ )
Translates, encodes, and returns
<a href='http://pluginbuddy.com' title='<?php printf
( esc_attr__( '%s - The Creators of %s',
'unique_domain' ), 'PluginBuddy',
'BackupBuddy' ); ?>'>PluginBuddy</a>
45
47. _e equivalent with printf
and __
Combine printf and __ for a _e equivalent with formatting
<?php
! printf( __( 'You have voted %d times',
'unique_domain' ), $total_count );
! //Output is: You have voted 100 times
?>
46