通用API文档

国际化指南

💡 云策文档标注

概述

本文档介绍了 WordPress 国际化(i18n)的核心函数和最佳实践,适用于 PHP 和 JavaScript 代码。它涵盖了字符串翻译、变量处理、复数形式、上下文区分、描述注释和字符串编写规范。

关键要点

  • 使用 __() 和 _e() 函数进行基本字符串翻译,__() 返回翻译,_e() 输出翻译。
  • 在字符串中使用变量时,应使用 printf 或 sprintf 函数,并添加占位符(如 %s),避免直接嵌入变量。
  • 处理复数形式时,使用 _n() 函数,它根据数量返回正确的翻译形式。
  • 对于需要上下文区分的术语,使用 _x() 或 _ex() 函数,添加上下文参数以避免歧义。
  • 为翻译字符串添加注释,以 /* translators: */ 开头,帮助译者理解上下文。
  • 避免在可翻译字符串中使用回车符(r),使用换行符(n)代替。
  • 不要国际化空字符串,如有需要,添加上下文。
  • 使用转义函数(如 esc_attr_e() 和 esc_html_e())结合国际化函数,防止恶意代码。
  • 遵循字符串编写最佳实践:使用完整句子、避免多余空格、假设翻译后长度加倍、避免不必要的 HTML 标记、使用占位符而非字符串拼接。

代码示例

// 基本字符串翻译
__( 'Blog Options', 'my-theme' );
_e( 'WordPress is the best!', 'my-theme' );

// 使用变量和占位符
printf(
    /* translators: %s: Name of a city */
    __( 'Your city is %s.', 'my-theme' ),
    $city
);

// 复数处理
printf(
    _n(
        '%s comment',
        '%s comments',
        get_comments_number(),
        'my-theme'
    ),
    number_format_i18n( get_comments_number() )
);

// 上下文区分
_x( 'Post', 'noun', 'my-theme' );
_x( 'post', 'verb', 'my-theme' );

// 转义字符串
esc_attr_e( 'Skip to content', 'my-theme' );
esc_html_e( 'Select Menu:', 'my-theme' );

注意事项

  • 不要直接嵌入变量到翻译字符串中,如 _e( "Your city is $city.", 'my-theme' );,这会导致翻译提取失败。
  • 避免使用字符串拼接进行翻译,应使用占位符和格式字符串。
  • 在占位符中使用单引号,避免双引号导致 PHP 变量解析错误。
  • 确保翻译注释以小写 "translators:" 开头,并紧邻 gettext 调用。
  • JavaScript 中也可使用类似函数,如 __() 和 sprintf。

📄 原文内容

In this article, you will learn when and how to use all available i18n functions and the best practices for writing your strings.

The recommendations in this article applies both for your PHP and your javascript code. You can see all the available functions for each language in the I18n functions page. The functions available for javascript will also be highlighted.

Basic strings

The most commonly used function is <a href="https://developer.wordpress.org/reference/functions/__/">__()</a>. It returns the translation of its argument:

__( 'Blog Options', 'my-theme' );

Another simple one is <a href="https://developer.wordpress.org/reference/functions/_e/">_e()</a>, which outputs the translation of its argument. Instead of writing:

echo __( 'WordPress is the best!', 'my-theme' );

you can use the shorter:

_e( 'WordPress is the best!', 'my-theme' );

__()is also available for javascript

Variables

If you are using variables in strings, similar to the example below, you need to use placeholders.

echo 'Your city is $city.'

Use the printf family of functions. Especially helpful are <a href="http://php.net/printf">printf</a> and <a href="http://php.net/sprintf">sprintf</a>. For example:

printf(
    /* translators: %s: Name of a city */
    __( 'Your city is %s.', 'my-theme' ),
    $city
);

Notice that the string for translation is the template "Your city is %s.", which is the same in both the source and at run-time.

If you have more than one placeholder in a string, it is recommended that you use argument swapping. In this case, single quotes (') are mandatory : double quotes (") tell php to interpret the $s as the s variable, which is not what we want.

printf(
    /* translators: 1: Name of a city 2: ZIP code */
    __( 'Your city is %1$s, and your zip code is %2$s.', 'my-theme' ),
    $city,
    $zipcode
);

Here the zip code is displayed after the city name. In some languages, displaying the zip code and city in opposite order is more appropriate. Using %s prefix, as in the above example, allows for this. A translation can be written:

printf(
    /* translators: 1:ZIP code 2:Name of a city */
    __( 'Your zip code is %2$s, and your city is %1$s.', 'my-theme' ),
    $city,
    $zipcode
);

sprintf is also available for javascript translations:

const zipCodeMessage = sprintf(
    /* translators: 1:ZIP code 2:Name of a city */
    __( 'Your zip code is %2$s, and your city is %1$s.', 'my-theme'),
    city,
    zipcode
);

The following example tells you what not to do

This is incorrect.
// This is incorrect do not use.
_e( "Your city is $city.", 'my-theme' );

The strings for translation are extracted from the source without executing the PHP associated with it. For example: The variable $city may be Vancouver, so your string will read "Your city is Vancouver" when the template is run but gettext won’t know what is inside the PHP variable in advance.

As the value of the variable is unknown when your string is translated, it would require the translator to know every case for the variable $country. This is not ideal, and it is best to remove dynamic content and allow translators to focus on static content.

Plurals

Basic Pluralization

If you have a string that changes when the number of items changes. In English you have "One comment" and "Two comments". In other languages, you can have multiple plural forms. To handle this in WordPress, you can use the <a href="https://developer.wordpress.org/reference/functions/_n/">_n()</a> function.

printf(
    _n(
        '%s comment',
        '%s comments',
        get_comments_number(),
        'my-theme'
    ),
    number_format_i18n( get_comments_number() )
);

_n() accepts 4 arguments:

  • singular – the singular form of the string (note that it can be used for numbers other than one in some languages, so '%s item' should be used instead of 'One item')
  • plural – the plural form of the string
  • count – the number of objects, which will determine whether the singular or the plural form should be returned (there are languages, which have far more than 2 forms)
  • text domain – the theme’s text domain

The return value of the functions is the correct translated form, corresponding to the given count.

`_n() is also available for javascript

Pluralization done later

You first set the plural strings with <a href="https://developer.wordpress.org/reference/functions/_n_noop/">_n_noop()</a> or <a href="https://developer.wordpress.org/reference/functions/_nx_noop/">_nx_noop()</a>.

$comments_plural = _n_noop(
    '%s comment.',
    '%s comments.'
);

At a later point in the code, you can use <a href="https://developer.wordpress.org/reference/functions/translate_nooped_plural/">translate_nooped_plural()</a> to load the strings.

printf(
    translate_nooped_plural(
        $comments_plural,
        get_comments_number(),
        'my-theme'
    ),
    number_format_i18n( get_comments_number() )
);

Disambiguation by context

Sometimes a term is used in more than one context and must be translated separately in other languages, even though the same word is used for each context in English. For example, the word Post can be used both as a verb "Click here to post your comment" and as a noun "Edit this Post". In such cases the <a href="https://developer.wordpress.org/reference/functions/_x/">_x()</a> or <a href="https://developer.wordpress.org/reference/functions/_ex/">_ex</a>() function should be used. It is similar to __() and _e(), but it has an additional argument — the context:

_x( 'Post', 'noun', 'my-theme' );
_x( 'post', 'verb', 'my-theme' );

Using this method in both cases, we get the string Comment for the original version. However, translators will see two Comment strings for translation, each in a different context.

Taking an example from the German version of WordPress as an illustration: Post is Beiträge. The corresponding verb form in German is beitragen.

Note that similar to __(), _x() has an echo version: _ex(). The previous example could be written as:

_ex( 'Post', 'noun', 'my-theme' );
_ex( 'post', 'verb', 'my-theme' );

Use the one you feel enhances legibility and ease of coding.

_x() and _nx()are also available for javascript

Descriptions

You can add a clarifying comment in the source code, so translators know how to translate a string like __( 'g:i:s a' ) . It must start with the word translators:, in all lowercase, and be the last PHP comment before the gettext call. Here is an example:

/* translators: draft saved date format, see http://php.net/date */
$saved_date_format = __( 'g:i:s a' );

Multi-line example:

/*
 * translators: Replace with a city related to your locale.
 * Test that it matches the expected location and has upcoming
 * events before including it. If no cities related to your
 * locale have events, then use a city related to your locale
 * that would be recognizable to most users.
 */
?>
<input placeholder="<?php esc_attr_e( 'Cincinnati' ); ?>" id="location" type="text" name="location" />

Newline characters

Gettext doesn’t like r (ASCII code: 13) in translatable strings, so avoid it and use n instead.

Empty strings

The empty string is reserved for internal Gettext usage, and you must not try to internationalize the empty string. It also doesn’t make any sense because translators won’t have context.

If you have a valid use-case to internationalize an empty string, add context to both help translators and be in peace with the Gettext system.

Escaping strings

It is good to escape all of your strings, preventing translators from running malicious code. There are a few escape functions that are integrated with internationalization functions.

<a title="<?php esc_attr_e( 'Skip to content', 'my-theme' ); ?>" class="screen-reader-text skip-link" href="#content" >
  <?php _e( 'Skip to content', 'my-theme' ); ?>
</a>
<label for="nav-menu">
  <?php esc_html_e( 'Select Menu:', 'my-theme' ); ?>
</label>

Best Practices for writing strings

Here are the best practices for writing strings

  • Use decent English style – minimize slang and abbreviations.
  • Use entire sentences – in most languages, word order is different than English.
  • Split at paragraphs – merge related sentences, but do not include a whole page of text in one string.
  • Do not leave leading or trailing whitespace in a translatable phrase.
  • Assume strings can double in length when translated.
  • Avoid unusual markup and unusual control characters – do not include tags that surround your text.
  • Do not put unnecessary HTML markup into the translated string.
  • Do not leave URLs for translation, unless they could have a version in another language.
  • Add the variables as placeholders to the string as in some languages the placeholders change position.
printf(
    __( 'Search results for: %s', 'my-theme' ),
    get_search_query()
);
  • Use format strings instead of string concatenation – translate phrases and not words –
printf(
    __( 'Your city is %1$s, and your zip code is %2$s.', 'my-theme' ),
    $city,
    $zipcode
);

is always better than

__( 'Your city is ', 'my-theme' ) . $city . __( ', and your zip code is ', 'my-theme' ) . $zipcode;
  • Try to use the same words and symbols to prevent translating multiple similar strings (e.g. don’t do the following)
__( 'Posts:', 'my-theme' ); and __( 'Posts', 'my-theme' );