Introducing 

Prezi AI.

Your new presentation assistant.

Refine, enhance, and tailor your content, source relevant images, and edit visuals quicker than ever before.

Loading…
Transcript

WP and PHP functions for i18n

__() _n() _e()

_x() _nx() _ex()

_n()

_nx()

sprintf() printf()

load_textdomain()

load_plugin_textdomain

load_theme_textdomain

wp_localize_script()

_n_noop, _nx_noop and translate_nooped_plural()

esc_attr__(), esc_attr_e(), esc_attr_x(), esc_html__(), esc_html_e(), esc_html_x()

String containing HTML

Who am I ?

Charles St-Pierre

  • Graphic designer since 2001
  • Specializing in Web since 2004
  • WordPress developer since 2.8.3

  • Co-founder of , workers coop
  • Full time daddy (since today), part time freelance

Kaki needs freelance WP integrators

and developers now: info@kakidcm.ca

I18n Por Favor

Why is it important?

What is i18n?

Definition:

Internationalization is the process of designing a software application so that it can potentially be adapted to various languages and regions without engineering changes.

The WHAT, WHY and HOW of internationalization

Comprehensible text

makes your UI work

In short:

  • Wrapping up all texts in your UI with functions so it can be easily translated (or LOCALIZED);
  • Thinking about how language works;
  • Communicating with the translators to make sure they understand what they are translating;

WordPress specifically

  • Based on GETTEXT library;
  • Core, plugins and themes can be internationalized;

Most importantly

  • It is simple (most of the time)

You are interacting with the user through language

It makes your work available to a broader audience

You contribute

to peace on Earth

i18n

=

Don’t be shy, contribute back

echo 'Click <a href="http://facebook.com/">this link</a> for

<b class="superbold">serious procastination</b>.';

/** Keep the < and > to communicate to your translator that these

* variables are HTML tags

*/

printf( __('Click <%1$s>this link<%2$s> for <%3$s>serious

procastination<%4$s>.', 'ytd'),

'a href="http://facebook.com/"',

'/a',

'b class="superbold"',

'/b');

Don’t hesitate to internationalize public plugins

and send back the code to the author.

You insure that the site your working on will be able to update its plugins in the future.

and don’t forget you are contributing to...

Peace on Earth.

¡Gracias!

CharlesStPierre.com

Now to more complex cases...

H O

Simple stuff

60% of your i18n needs can be covered by these technics.

to implement internationalization?

Multiple numeric variables:

introducing nominal groups

// $int_doc and $int_cat can vary in number.

echo 'We found '. $int_doc .' documents in '. $int_cat .' categories.';

// Solution: split nominal groups.

$NG_doc = sprintf( _n('one document', '%d documents' , $int_doc, 'ytd'),

$int_doc);

$NG_cat = sprintf( _n('one category', '%d categories' , $int_cat, 'ytd'),

$int_cat);

printf( __('We found %1$s in %2$s.', 'ytd'), $NG_doc, $NG_cat );

// Talk to your translators with special comments

/* translators: First variable is the "number of documents" nominal group, the second is the "number of categories" nominal group. */

printf( __('We found %1$s in %2$s.', 'ytd'), $NG_doc, $NG_cat );

No-op plural translation

Not yet knowing

how much stuff there is...

/** We need to print out a sentence depending on the gender of the user

* and number of posts by this user

*/

$user = get_userdata(); // Gender and post count attribute has been added

/** _n_noop stores every possible plurals in an array */

switch ( $user->gender) {

case 'female':

$_n_noop_array = _n_noop('%s is a woman and she has 1 post',

'%s is a woman and she has %d posts','ytd');

break;

case 'male':

$_n_noop_array = _n_noop('%s is a man and he has 1 post',

'%s is a man and he has %d posts', 'ytd');

break;

default: // ’cause some time, you don’t know

$_n_noop_array = _n_noop('%s is a user and has 1 post',

'%s is a user and has %d posts', 'ytd');

break;

}

/** translate_nooped_plural now get the right plural string

* from the $_n_noop_array depending on a given numeric variable

*/

$format_str = translate_nooped_plural( $_n_noop_array,

$user->post_count, 'ytd');

/** $format_str now contains the right format string for printf

* and can be populated with the variables

*/

printf( $format_str, $user->nicename, $user->post_count );

Nice date ranges

August 16 & 17, 2014

not : August 16th 2014 at 9:00am to August 17th 2014 at 5:00pm

$start_time = 1408172400;

$end_time = 1408287600;

echo date_i18n( 'F j Y \a\t g:ia', $start_time )

.' to '

.date_i18n( 'F j Y \a\t g:ia', $end );

/** Solution: compare $start and $end. Check for 2 things:

* Same what? Same day, month, year or same nothing

* Full period: full day, full month, full year

*/

if ( date( 'Ymd', $start_time) === date( 'Ymd', $end) ){

$same = 'day';

}

/** Full day (00:00 to 23:59), full month (1 to last day of month),

* full year (Jan 1 to Dec 31) */

if ( date( 'd', $start_time) == '1'

&& date('t',$end) == date('d',$end) { // 't' number of day in month

$full = 'month';

}

/** Based on $same and $full, set $start_pattern and $end_pattern

* Always use context functions.

*/

echo date_i18n( $start_pattern, $start_time)

.date_i18n( $end_pattern, $end_time);

Same day: August 16, 2014, 9:00am to 5:00pm

Same day, full day: August 16, 2014

Same month, full day: August 16 to 18, 2014

Same month, full month: August 2014

String concatenation with variable

echo 'Hello ' . $your_name . '. How are you today?';

// bad, bad developer

echo __('Hello ','ytd').$your_name.__('. How are you today?','ytd');

/** Translators get these phrases to translate:

* 'Hello '

* and

* '. How are you today?'

*

* And localized strings should NEVER contain trailing spaces

*/

/** Use printf (and sprintf) strength to manage variables

* in their format string.

*/

printf( __('Hello %1$s. How are you today?', 'ytd'), $your_name );

Simple stuff

$variable = 'the string';

$variable = __( 'the string', 'ytd');

<p>the string</p>

<p><?php _e( 'the string', 'ytd') ?></p>

$mounting = 'Screwed';

$predicament = 'Screwed';

_x( 'Screwed', 'attached to another object by an inclined plane,

wrapped helically around an axis', 'ytd' );

_x( 'Screwed', 'being in a predicament', 'ytd' );

if ( $nb_of_fallen_teeth == 1 ){

$string = 'tooth';

}else{

$string = 'teeth';

}

$string = _n( 'tooth', 'teeth', $nb_of_teeth, 'ytd' );

I18n toolbox for developers

Nice page in the CODEX just for you:

http://codex.wordpress.org/I18n_for_WordPress_Developers

Tools in WP repository to generate POT file

Download the WordPress i18n tools directory from SVN

CodeStyling Localize:

WordPress plugin for localization useful for internationalization too.

Enumerations

This Post is linked to 3 categories, 1 tag, [N taxonomies…] and 6 subjects.

We don’t know how many taxonomies, or how many terms in any taxonomies.

$post_tax_nominal_groups = array();

foreach ( get_taxonomies() as $tax ) {

$taxonomy = $tax->name;

// taxonomy object contains translated labels

$taxonomy_single_label = $tax->labels->singular_name;

$taxonomy_plural_label = $tax->labels->name;

$terms = wp_get_post_terms($post_id, $taxonomy, array('fields' => 'ids'));

/** Here, we can’t really use the plural GETTEXT function because WordPress

* taxonomy labels declaration only uses one value for plural form.

*/

if (count($terms)){

$post_tax_nominal_groups[] = sprintf( _n( 'one %1$s', // first variable

'%2$d %3$s', // second and third

count($terms),'ytd'),

$taxonomy_single_label, // first

count($terms), // second

$taxonomy_plural_label );// third

}

}

// how many [N taxonomies...]

$nb_of_nominal_group = count( $post_tax_nominal_groups );

// take out the last one and store it in a string

$last_nominal_group = array_pop( $post_tax_nominal_groups );

// concatenate the others with commas

$comma_sep_nominal_groups = implode( ', ', $post_tax_nominal_groups );

printf( _n( 'This post is linked to %2$s.', // use only the last one

'This post is linked to %1$s and %2$%.', // use both string with AND

$nb_of_nominal_group,

'ytd' ),

$comma_sep_nominal_groups,

$last_nominal_group );

This Post is linked to 3 categories, 1 tag, [N taxonomies…] and 6 subjects.

Simple stuff

'ytd' // for your-text-domain

First, choose your textdomain

  • short
  • unique
  • easy to type (you’ll be typing it often)

Then, load your localization.

  • WordPress define locale in wp-config.php
  • WPML define locale at hook PLUGINS_LOADED, priority 2
  • Polylang define locale at PLUGINS_LOADED, priority 1

Always load textdomain inside a hook, after these two.

Numeric variable: plural forms

// $bug_count being an integer

echo 'You have ' . $bug_count . ' bugs in your code.';

/** English, Greek, Spanish have a plural if "n" is not ONE

* nplurals=2; plural=(n != 1);

*

* French, Filipino, Turquish have a plural if "n" greater than ONE

* nplurals=2; plural=(n > 1);

*

* Arabic have 6 plural forms

* nplurals=6; plural=(n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3

* && n%100<=10 ? 3 : n%100>=11 ? 4 : 5);

*

* Developers need to be flexible.

*/

printf( _n( 'You have a little bug in your code.', // singular

'You have %d bugs in your code.', // plural

$bug_count, 'ytd' ),

$bug_count);

/* GETTEXT takes care of the rest */

Simple stuff

<script type="text/javascript"> // java_script.js contains

if ( status == 'error' ){

alert( 'Good God, there’s an error!');

}else if ( status == 'warning' ){

alert( 'Be careful with that!' );

}else{

alert( 'All good, carry on.' );

}

</script>

$java_texts = array(

'message' => __('All good, carry on.','ytd'),

'error' => __('Good God, there’s an error!','ytd'),

'warning' => __('Be careful with that!','ytd')

);

wp_enqueue_script('java_script');

wp_localize_script('java_script', 'java_obj', $java_texts);

<script type="text/javascript"> // java_script.js contains

alert( java_obj[status] );

</script>

Simple stuff

add_action('plugins_loaded','load_my_plugin_localization',10);

function load_my_plugin_localization(){

load_plugin_textdomain('ytd', false,

'./path/relative/to/WP_PLUGIN_DIR/with/trailing/slash/' );

//Name your .PO/.MO files your_text_domain-xx_XX.

}

add_action('after_theme_setup','load_my_theme_localization',10);

function load_my_theme_localization(){

load_theme_textdomain('ytd',

'/absolute/path/theme/language/WITHOUT/trailing/slash');

//Name your .PO/.MO files xx_XX only.

}

Learn more about creating dynamic, engaging presentations with Prezi