SlideShare a Scribd company logo
Network: RU-Secure
Username: trsguest2017
Password: RUguest253$
Preparing a Plugin for
Translation
Brian Hogg
@brianhogg
brianhogg.com
echo esc_html( __( ‘Preparing
a Plugin for Translation’,
‘brian-hogg’ ) );
Courses 

https://brianhogg.com/courses
WordCamp Hamilton

https://hamilton.wordcamp.org/
Plugins

https://brianhogg.com/plugins
Slides
https://brianhogg.com/wcto2017/
Who Are You?
Why Translate?
Brian hogg   word camp preparing a plugin for translation
Brian hogg   word camp preparing a plugin for translation
Brian hogg   word camp preparing a plugin for translation
Brian hogg   word camp preparing a plugin for translation
Brian hogg   word camp preparing a plugin for translation
How to Start?
<?php
/***
Plugin Name: Event Calendar Newsletter
Version: 1.6.1
Author: Brian Hogg
Author URI: https://brianhogg.com/
License: GPL2 or later
*/
<?php
/***
Plugin Name: Event Calendar Newsletter
Version: 1.6.1
Author: Brian Hogg
Author URI: https://brianhogg.com/
License: GPL2 or later
Text Domain: event-calendar-newsletter
*/
Fetch a single event using the ID of
that event
__( ’Fetch a single event using the ID of
that event’, ‘event-calendar-newsletter’ );
_ _( $string, $textdomain )
__( ’Fetch a single event using the ID of
that event’, ‘event-calendar-newsletter’ );
_ _( $string, $textdomain )
__( ’Fetch a single event using the ID of
that event’, ‘event-calendar-newsletter’ );
_ _( $string, $textdomain )
__( ’Fetch a single event using the ID of
that event’, ‘event-calendar-newsletter’ );
_ _( $string, $textdomain )
Type this out!
// can’t do this
define( ‘ECN_TEXT_DOMAIN’, ‘event-
calendar-newsletter’ );
// ...
__( ’Fetch a single event using the ID
of that event’, ECN_TEXT_DOMAIN );
Wrong Way
__( ’Fetch a single event using the ID of
that event’, ‘event-calendar-newsletter’ );
Right Way
echo __( ’Fetch a single event
using the ID of that event’,
‘event-calendar-newsletter’ );
Outputting the String
_e( ’Fetch a single event using
the ID of that event’, ‘event-
calendar-newsletter’ );
Outputting the String
_e === echo + __
What if you have
something you don’t want
translated?
Exclude a single event from the
listing. Use "current" when using the
shortcode on an event page to exclude
the current event.
Using Placeholders
Exclude a single event from the
listing. Use "current" when using the
shortcode on an event page to exclude
the current event.
Using Placeholders
__( ‘Exclude a single event from the
listing. Use "current" when using the
shortcode on an event page to exclude
the current event.’, ‘my-shortcode’ )
Using Placeholders
sprintf( __( ‘Exclude a single event
from the listing. Use "%s" when using
the shortcode on an event page to
exclude the current event.’, ‘my-
shortcode’ ), ‘current’ );
Using Placeholders
echo sprintf( __( ‘Exclude a single
event from the listing. Use "%s" when
using the shortcode on an event page to
exclude the current event.’, ‘my-
shortcode’ ), ‘current’ );
Using Placeholders
Exclude a single event from the
listing. Use "current" when using the
shortcode on an event page to exclude
the current event.
Using Placeholders
What if you want to
output HTML?
Can't find the option you're looking
for? <a href="https://mysite.com/
support">Submit a support request</a>
and we'll do our best to help!
Outputting HTML
_e( "Can’t find the option you're looking
for? <a href="https://mysite.com/support
">Submit a support request</a> and we'll
do our best to help!", ‘my-shortcode’ );
Outputting HTML
_e( "Can’t find the option you're
looking for? %sSubmit a support request
%s and we'll do our best to help!",
‘my-shortcode’ );
Outputting HTML
echo sprintf( __( "Can’t find the option
you're looking for? %sSubmit a support
request%s and we'll do our best to help!",
‘my-shortcode’ ), '<a href="https://
mysite.com/support">', ‘</a>' );
Outputting HTML
Avoids link being
changed
Avoids broken HTML
Can’t find the option you're looking
for? %sSubmit a support request%s and
we'll do our best to help!
Sie können die gewünschte Option nicht
finden? %sSenden Sie eine Support-Anfrage
%s und wir werden unser Bestes tun, um zu
helfen!
Sie können die gewünschte Option nicht
finden? %sSenden Sie eine Support-Anfrage
%s <script>...</script>und wir werden
unser Bestes tun, um zu helfen!
Brian hogg   word camp preparing a plugin for translation
esc_html()
esc_attr()
Escape Functions
https://brianhogg.com/tips-sanitizing-validating-
wordpress-plugin-data/
esc_html( __( "blah blah blah
hahahaha", ‘my-shortcode’ ) );
Escape Functions
esc_html( __( "bla bla bla hihihihi”,
‘my-shortcode’ ) );
Escape Functions
esc_html( __( "bla bla bla <script>alert(‘test’);</
script> hihihihi”, ‘my-shortcode’ ) );
Escape Functions
esc_html( __( "bla bla bla <script>alert(‘test’);</
script> hihihihi”, ‘my-shortcode’ ) );
Escape Functions
bla bla bla &lt;script&gt;alert(‘test’);&lt;/
script&gt; hihihihi
Can Combine esc_html/
esc_attr and __/_e
Together
Brian hogg   word camp preparing a plugin for translation
esc_html__()
esc_html_e()
esc_attr__()
esc_attr_e()
Escape Functions
echo esc_html( __( "blah blah blah
hahaha", ‘my-shortcode’ ) );
Escape Functions
echo esc_html( __( "blah blah blah
hahaha”, ‘my-shortcode’ ) );
Escape Functions
esc_html_e( "blah blah blah hahaha",
‘my-shortcode’ );
echo sprintf( esc_html__( "here is %smy link%s",
‘my-shortcode’ ), ‘<a href=“…”>’, ‘</a>’ );
Careful With sprintf
vs
esc_html_e( sprintf( __( "here is %smy link%s",
‘<a href="…">’, ‘</a>’ ), ‘my-shortcode’ );
here is my link
Careful With sprintf
vs
here is &lt;a href=“…”&gt;my link&lt;/a&gt;
wp_kses()
wp_kses_post()
Need HTML?
Plurals
_n( $single_string, $plural_string,
$number, $domain );
Plurals
_n( ‘you did one thing’, ‘you did lots
of things’, 1, ‘my-plugin’ );
Plurals
you did one thing
_n( ‘you did one thing’, ‘you did lots
of things’, 5, ‘my-plugin’ );
Plurals
you did lots of things
sprintf( _n( ‘you did %s thing’, ‘you did %s
things’, $count, ‘my-plugin’ ), $count );
Plurals
What if strings are similar
or hard to recognize?
__( ‘Read’, ‘my-plugin’ );
Adding Context
__( ‘Read’, ‘my-plugin’ );
_x( $string, $context, $domain );
Adding Context
_x( ‘Event Calendar Newsletter’,
‘Settings title’, ‘my-plugin’ );
Adding Context
_x( ‘Event Calendar Newsletter’,
‘Plugin menu title’, ‘my-plugin’ );
Brian hogg   word camp preparing a plugin for translation
date_i18n()
Dates
date_i18n( get_option( 'date_format' ),
$timestamp )
Dates
JavaScript
wp_localize_script()
JavaScript
wp_register_script( ‘ecn_my_script’, plugins_url( ’js/
myscript.js’, __FILE__ ) );
wp_localize_script( ‘ecn_my_script’, ‘ecn_js’, array(
‘success’ => __( ‘You did the thing!’, ‘ecn’ ),
‘failure’ => __( ‘The thing didn’t work’, ‘ecn’ ),
) );
wp_enqueue_script( ‘ecn_my_script’ );
JavaScript
https://brianhogg.com/jswp
alert( ecn_js.success );
alert( ecn_js.failure );
Don’t trust the strings
in JavaScript
https://brianhogg.com/tips-sanitizing-validating-
wordpress-plugin-data/
Best Practices
Best Practices
• Decent English style
• Entire sentences
• Split at paragraphs
• Use format strings instead of string concatenation—
sprintf(__('Replace %1$s with %2$s'), $a, $b); is
always better than __('Replace ').$a.__(' with ').$b;
• Avoid unusual markup and unusual control characters
• Do not leave leading or trailing whitespace in a translatable
phrase
https://codex.wordpress.org/
I18n_for_WordPress_Developers#Best_Practices
Now What?
Now What?
• Generate the POT file (base language)
• Copy to a PO file (for each translation)
• Generate the MO file (compiled for
quick string access)
• Put them all in the languages/ folder
of your plugin
https://brianhogg.com/how-wordpress-org-plugin-
translations-are-handled/
...
#: core/templates/admin-page.php:2 edd/edd.php:46
msgid "The Events Calendar Shortcode"
msgstr ""
#: core/templates/admin-page.php:4
msgid ""
"The shortcode displays lists of your events. For
example the shortcode to "
"show next 8 events in the category "%s" in ASC order
with date showing:"
msgstr ""
my-plugin.pot
#: core/templates/admin-page.php:2 edd/edd.php:46
msgid "The Events Calendar Shortcode"
msgstr "The Events Calendar Shortcode"
#: core/templates/admin-page.php:4
msgid ""
"The shortcode displays lists of your events. For example the
shortcode to "
"show next 8 events in the category "%s" in ASC order with
date showing:"
msgstr ""
"O shortcode mostra listas de seus eventos. Por exemplo, o
shortcode para "
"mostrar os próximos 8 eventos na categoria "%s", em ordem
ASC exibindo a "
"data:"
my-plugin-pt_BR.po
??6?I|????dD?
?Z?/!
Q,_Y?^?7E:}??UA"?n?O)	 Ey	?	 	 ?	 ?	 ?	 <
a@
?
?
?
??
Xv
|?
FLE?L?;&
-b
?
??
_LZ?^fjm~H??'?V 5w*?&??????vg??]2a
?6?_?V9<?F??e?)?y)k?_o	?(?@?g
r????gL??V5S?X?I92?	???j?e?bS????T?!F+h^???83 .l ? /0()2!%3
my-plugin-pt_BR.mo
/languages
my-plugin.pot
my-plugin-fr_FR.po
my-plugin-fr_FR.mo
my-plugin-pt_BR.po
my-plugin-pt_BR.mo
...
Creating the Translations
Creating the POT
POEdit
https://www.youtube.com/watch?v=s6oRk6nfkI0
makepot.php

svn co http://develop.svn.wordpress.org/trunk/tools/
grunt-wp-i18n
https://github.com/cedaro/grunt-wp-i18n
function my_load_textdomain() {
load_plugin_textdomain( ‘my-plugin', false,
plugin_basename( dirname( __FILE__ ) ) . '/languages/' );
}
add_action( 'plugins_loaded', 'my_load_textdomain' );
Load the Translations
Test by Switching to the
Language
Testing
Testing
Maintaining Over Time
Ensure Any New Strings
Wrapped in a Translation
Function
Automatic POT
Generation for wp.org
(free) Plugins
Brian hogg   word camp preparing a plugin for translation
Translators Can Pull
Requests on github/
bitbucket
Brian hogg   word camp preparing a plugin for translation
DEMO
Takes Work
Brian hogg   word camp preparing a plugin for translation
Questions?
Des questions?
Questões?
¿Preguntas?
Brian Hogg
@brianhogg
brianhogg.com
https://brianhogg.com/wcto2017/

More Related Content

Brian hogg word camp preparing a plugin for translation