---
description: https://github.com/dfwood/i18n-example
---

# Cách sử dụng  i18n làm multiple language javascript (ok)

**Ví dụ 1:**

C:\xampp\htdocs\datvietcoconut\wp-content\themes\twentyseventeen\functions.php

```php
function twentyseventeen_scripts_ct() {
    wp_enqueue_script ( 'my-plugin-script' , get_template_directory_uri() .'/js/my-script.js'  , array (  'wp-i18n'  ) , '0.0.1',true ) ;
    wp_set_script_translations ('my-plugin-script' ,  'my-plugin',get_template_directory() . '/languages') ;
}
add_action( 'wp_enqueue_scripts', 'twentyseventeen_scripts_ct' );
```

C:\xampp\htdocs\datvietcoconut\wp-content\themes\twentyseventeen\js\my-script.js

```
const { __, _x, _n, sprintf } = wp.i18n;
const outputContainer = document.getElementById('i18n-js-examples');
const strings = [
  __('Hello World', 'my-plugin'),
  __('Glitter Box', 'my-plugin')
];
outputContainer.innerHTML = strings.join('<br/>');
```

C:\xampp\htdocs\datvietcoconut\wp-content\themes\twentyseventeen\languages\my-plugin-vi-my-plugin-script.json

```json5
{ 
   "domain" :  "my-plugin" , 
   "locale_data" :  { 
      "my-plugin" :  { 
         "" :  { 
            "domain" :  "my-plugin" , 
            "plural_forms" :  "nplurals=2; plural=(n != 1);" , 
            "lang" :  "vi" 
         } , 
         "Hello World": ["Xin chào thế giới 😁"],
         "Glitter Box": ["Chiếc hộp kỳ diệu 😁"], 
      } 
   } 
}
```

C:\xampp\htdocs\datvietcoconut\wp-content\themes\twentyseventeen\header.php

```html
<div id="i18n-js-examples"></div>
```

<figure><img src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2F1WaSx81d4r2E3owce4F8%2FScreenshot_1.png?alt=media&#x26;token=63ea2728-6b31-40c0-b2d3-876e031a1e40" alt=""><figcaption></figcaption></figure>

**Chú ý với cách đặt ngôn ngữ khác ví dụ: en-AU**

C:\xampp\htdocs\datvietcoconut\wp-content\themes\twentyseventeen\languages\my-plugin-en\_AU-my-plugin-script.json

```json
{ 
   "domain" :  "my-plugin" , 
   "locale_data" :  { 
      "my-plugin" :  { 
         "" :  { 
            "domain" :  "my-plugin" , 
            "plural_forms" :  "nplurals=2; plural=(n != 1);" , 
            "lang" :  "en-AU" 
         } , 
         "Hello World": ["Xin chào thế giới 😁"],
         "Glitter Box": ["Chiếc hộp kỳ diệu 😁"], 
      } 
   } 
}
```

<figure><img src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FT332UMncaa0mUq9oaeZF%2FScreenshot_2.png?alt=media&#x26;token=1f7195c7-28a0-4f6a-99de-351f42e6f466" alt=""><figcaption></figcaption></figure>

<figure><img src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FOl428GSrYjyqcIonfy2m%2FScreenshot_3.png?alt=media&#x26;token=f7387740-fc29-4444-82a6-3879d3725d50" alt=""><figcaption></figcaption></figure>

**Plugin gốc**

{% file src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FMosRDTDMRuc840Ncgw9W%2Fi18n-example-master.zip?alt=media&token=87066814-3626-437f-8757-3433e80dae77" %}

**Plugin chỉnh sửa tiếng việt để test**

{% file src="https://2370029328-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2F-LWPtKFbhw0XehxVuoiZ%2Fuploads%2FACtN5emWnq5QrMDYG1xi%2Fi18n-example.zip?alt=media&token=a982fe58-fdd5-46ca-90b0-2ffe16bf236a" %}

## WordPress 5.0+ JavaScript localization translation

[October 27, 2020](https://themes.show/2020/10/27/wordpress-5-0-javascript-localization-translation/) [John](https://themes.show/author/john/) [Tutorial](https://themes.show/category/tutorial/)

**Article directory** \[hide]

* WordPress JavaScript internationalization
  * JavaScript localization functions
  * Load JavaScript translation
  * JavaScript translation file
    * JavaScript translation file name
    * Generate JavaScript translation files
* Tools to increase efficiency
  * Webpack configuration
  * Babel integration
  * Available hooks and filters
* WordPress PHP Internationalization
* Further reading

Advocate mentioned that WordPress supports JavaScript localization translation in “WordPress 5.0+ supports JavaScript i18n localization translation”. Today, Advocate will share with you the article “The Internationalization of WordPress 5.0” from @Pascal Birchler. It comprehensively introduces the entire implementation of JavaScript localization translation. I hope it will be helpful to all developers.

### WordPress JavaScript internationalization

WordPress 5.0 comes with a new editor called Gutenberg. This new editor is mainly written in JavaScript, which means that many international translations happen on the client instead of the server. Although the core of WordPress used to use `wp_localize_script()` functions to translate the [fields](https://themes.show/tag/fields/) of the UI interface, in the face of complex JavaScript plugins like Gutenberg, a more powerful solution is needed.

#### JavaScript localization functions

WordPress 5.0 adds support JavaScript I18N, which is bringing PHP as a function similar to what we are familiar with JavaScript developers, this is a new start `wp-i18n`of JavaScript package that provides new functions  `__()`, , `_x()`, `_n()`,   `_nx()`even `sprintf()`. These functions are basically the same as the original PHP functions and can be used in the same way.

To use this package, you need `wp-i18n`to add the script as a dependency when registering JavaScript:

```
wp_register_script ( 
	'my-plugin-script' , 
	plugins_url (  'js/my-script.js' ,  __FILE__  ) , 
	array (  'wp-i18n'  ) , 
	'0.0.1' 
) ;
```

Then, the localized functions `wp.i18n`are available under global variables in JavaScript. You can use them like this:

```
const  { __ , _x , _n ,  sprintf  }  = wp . i18n ;
__ (  'Hello World' ,  'my-plugin'  ) ;
_x (  'Glitter Box' ,  'block name' ,  'my-plugin'  ) ;
// Get the number of comments anywhere in your js script. 
const commentCount = wp . Data . Select (  'my/data-store'  ) . GetCommentCount ( ) ;
/* translators: %s: number of comments */ 
sprintf ( _n (  'There is %s comment' ,  'There are %s comments' , commentCount ,  'my-plugin'  ) , commentCount ) ;
```

This is all you need to make JavaScript components fully localizable.

If you are familiar with the PHP translation function in the core of WordPress, you will find that similar `esc_html()`or missing `esc_html__()`. These are not needed in JavaScript, because browsers can already escape unsafe characters.

**Note** : Although the use of HTML in translatable strings is discouraged, sometimes it is necessary, such as adding a link ( `Check out this link to <a href="%s">my website</a>.`). Now, it’s not easy to do this, at least without using  `innerHTML` /  `dangerouslySetInnerHTML`. Currently, this issue is being discussed on GitHub.

```
wp_register_script ( 
	'my-plugin-script' , 
	plugins_url (  'js/my-script.js' ,  __FILE__  ) , 
	array (  'wp-i18n'  ) , 
	'0.0.1' 
) ;
wp_register_script ( 
	'my-awesome-block' , 
	plugins_url (  'js/my-block.js' ,  __FILE__  ) , 
	array (  'wp-i18n'  ) , 
	'0.0.1' 
) ;
wp_set_script_translations (  'my-plugin-script' ,  'my-plugin'  ) ; 
wp_set_script_translations (  'my-awesome-block' ,  'my-plugin'  ) ;
```

The reason for this is for **performance** . The translation will only be loaded when your script is actually _queued_ . If this is the case, WordPress will load the translation file into memory and provide it via inline JavaScript `wp.i18n`. This means that WordPress  needs   **a translation file for each script handle**   , and each file only contains strings related to the script.

Imagine writing a WordPress plugin that includes JavaScript, which contains many different packages, which can also be used independently of each other. If you only need those translations for a single package, you don’t want to load all the translations.

#### JavaScript translation file

We have already introduced how to load JavaScript translation files, but what is so special about them? Well, this time we will not deal with PO or MO files, but use **JSON** files. Since JSON can be easily read in JavaScript, it is a convenient format to store translations.

In addition, the   `wp-i18n` package uses a library that is basically compatible with the Jed JavaScript gettext library, which requires Jed-style JSON conversion data. As mentioned in the previous section, WordPress.org will automatically provide these translation files. But if you want to load your own translation, you need to create such a JSON file yourself.

A very simple Jed style JSON translation file looks like this:

```
{ 
   "domain" :  "messages" , 
   "locale_data" :  { 
      "messages" :  { 
         "" :  { 
            "domain" :  "messages" , 
            "plural_forms" :  "nplurals=2; plural=(n != 1);" , 
            "lang" :  "de_DE" 
         } , 
         "Source" :  [ 
            "Quelle" 
         ] , 
         "Enter the information for this recommendation." :  [ 
            "Gib die Informationen zu dieser Empfehlung ein." 
         ] , 
         "%s comment" :  [ 
            "%s Kommentar" , 
            "%s Kommentare" 
         ] , 
         "block name \u 0004Recommendation" :  [ 
            "Empfehlung" 
         ] 
      } 
   } 
}
```

If you are already familiar with PO translation files, this format contains similar information, such as information about locale ( `de_DE`) and its plural forms. All strings are in the `messages`object, the original is the key, and the translation is the value. If a string has an additional context, it will be  separated by the **\u0004** separator.

**Note:** An important detail here is the text field, which is currently only available   `messages` , not the field you actually use in your code. Here is a WordPress Trac ticket, which may support the use of actual text [fields](https://themes.show/tag/fields/) in the future.

**JavaScript translation file name**

PO and MO translation files in WordPress usually have formats `$textdomain-$locale.po`, for example `my-plugin-de_DE.po`. But for JSON files, the situation is a bit different.

You may remember that we need to pass the script handle name to `wp_set_script_translations()`. This handle also needs to add the json file name `$textdomain-$locale-$handle.json`.

Therefore, for our `my-plugin-script` script handle, the translation file needs to be named `my-plugin-de_DE-my-plugin-script.json`.

For technical reasons, WordPress also looks for files in the form `$textdomain-$locale-$md5.json`, which `$md5` contains the MD5 hash of the JavaScript file name, including the extension. In the previous example, `my-plugin-script` point to `js/my-script.js`. `my-script.js` The MD5 hash value is `537607a1a008da40abcd98432295d39e`. So our translation file can also be named `my-plugin-de_DE-537607a1a008da40abcd98432295d39e.json`.

**Generate JavaScript translation files**

Since WordPress requires a translation file for each script handle, each file only contains strings related to the script, which means processing a large number of JSON files. Fortunately, **there** is **no need to write these by hand** .

The recommended way to generate JSON translation files is to use WP-CLI. The latest version of WP-CLI 2.1.0 provides special commands for this purpose   `wp i18n make-json` .

This `wp i18n make-json`command can extract all JavaScript strings from regular PO translation files and put them into a separate JSON file.

**Note:**  WP-CLI 2.1.0 was released on December 18. Make sure you are `wp cli update`using the latest version by running  . You can use to  `wp cli version`check the current version.

Let’s assume your plugin folder in the file `my-plugin` have three source files: `my-plugin.php`, `js/my-script.js` and `js/my-block.js`. You use WP-CLI to extract the string and generate a translation catalog (POT) as shown below:

```
wp i18n make -pot my-plugin my-plugin/languages/my-plugin. pot
```

Use the poedit software to translate the generated .pot files and generate the required PO and MO files. Suppose we first add a German translation `my-plugin/languages/my-plugin-de_DE.po`. After that, you only need to run it `wp i18n make-json my-plugin/languages` to generate JavaScript translation files. The results are as follows:

* A new  `my-plugin/languages/my-plugin-de_DE-537607a1a008da40abcd98432295d39e.json`file contains translations `my-script.js`.
* A new   `my-plugin/languages/my-plugin-de_DE-dad939d0db25804f91959baeec56ea8a.json` file contains translations   `my-block.js`.
* In `my-plugin/languages/my-plugin-de_DE.po`now contains only the need to be translated on the server side.

If you don’t want to modify the PO file, please `--no-purge` pass parameters to the WP-CLI command as described in the documentation.

**Note:** These WP-CLI commands have some known problems in some special situations. When we understand how people use them, we are always working to improve the tools.

### ools to increase efficiency

These new processes introduced by WordPress 5.0 and [Gutenberg](https://themes.show/tag/gutenberg/) can feel a bit complicated at first. To make life easier, I want to share some tips and tricks for project configuration.

#### ebpack configuration

If you need to reference global variables in the project anywhere `wp.i18n`, you will not be satisfied with the [code](https://themes.show/tag/code/) editor displaying type hints and the like. To change this situation, I recommend installing `@wordpress/i18n`  packages as  dependencies of using  `npm` /  `yarn`. Then you can use it throughout the project `import { __ } from '@wordpress/i18n;` .

Usually, this will cause Webpack to bundle the library with your code. Since WordPress has already `wp.i18n` exposed the library globally, there is no need for [code](https://themes.show/tag/code/) duplication. To prevent this, add the following to the Webpack configuration:

```
externals :  { 
    '@wordpress/i18n' :  {  this :  [  'wp' ,  'i18n'  ]  } 
}
```

In this way you can benefit from the functions of the IDE and the existing `wp.i18n`global functions. Just make sure  `wp_register_script()`to add it `wp-i18n`as a dependency when calling  .

#### Babel integration

In the previous section, I mentioned using `wp i18n make-pot`a pot to create the necessary translation directory, from which you can create the actual localization. Depending on your developer workflow, you may want to call the build tool using Babel `@wordpress/babel-plugin-makepot`to create the POT file. Next, share the integration with Babel to extract the I18N method.

`npm install --save-dev @wordpress/babel-plugin-makepot` Next , please run the directory and add the following [code](https://themes.show/tag/code/) to your Babel configuration:

```
[ 
    '@wordpress/babel-plugin-makepot' , 
    { 
        output :  'languages/my-plugin-js.pot' , 
    } , 
]
```

Advocating tips: If you are not familiar with how to integrate Babel and configure Webpack, I suggest you read this article: https://www.bluehost.com/[blog](https://themes.show/tag/blog/)/developers-corner/javascript-translations-in-[gutenberg](https://themes.show/tag/gutenberg/)-9931 /

**Note:**   You still want to create POT files for other PHP files, not just JavaScript files. You can still use WP-CLI to do this. Just skip the JavaScript string extraction and merge the generated POT file as shown below:

```
wp i18n make - pot my - plugin my - plugin / languages / my - plugin. pot  - skip - js - merge = my - plugin / languages / my - plugin - js. pot
```

In this case, it `languages/my-plugin-js.pot`is only temporary, so you can delete it again later.

#### Available hooks and filters

WordPress provides `load_textdomain` and  `gettext` such filters allow rewriting the translation file path or personal translation.

In WordPress 5.0.2, the following filters are added for changing   `wp_set_script_translations()` the results, so you can do the same for JavaScript translation:

* `pre_load_script_translations`: Pre-filter the script conversion of a given file, script handle and text field. In this way, you can short-circuit the script conversion logic to return your own translation.
* `load_script_translation_file`: Filter the file path used to load the script conversion of the given script handle and text field.
* `load_script_translations`: Filter script conversion for a given file, script handle and text field. This way, you can overwrite the translation after loading the translation from the translation file.

In addition, pull request # 12517 [Gutenberg](https://themes.show/tag/gutenberg/) project also  `@wordpress/i18n` pack increase in the `i18n.gettext`, , `i18n.gettext_with_context`, `i18n.ngettext`and `i18n.ngettext_with_context`filters. To overwrite individual translations, you can use them like this:

```
wp. hooks . addFilter ( 
    'i18n.gettext' , 
    'myplugin/filter-gettext' , 
    function ( translation , text , domain )  { 
        if  (  'Source'  === text &&  'foo-domain'  === domain )  { 
            return'New  translation' ; 
        }
 
        return translation ; 
    } 
) ;
```



### WordPress PHP Internationalization

In this article, we mentioned a lot of JavaScript translations, and you might be wondering if we also changed things in PHP. The answer is: no.

However, now is a good time to do some kind of I18N cleaning for your plugin or theme. Here is some useful information:

* Make sure to set it in the main plugin file/theme style sheet `Text Domain`, and use the same text field throughout the project.
* If your WordPress plugin or theme is hosted on WordPress.org and requires WordPress 4.6 or higher ( `Tested up to`indicated by the title in the readme file), you don’t need to call it `load_plugin_textdomain()`.
* You can run `wp i18n make-pot --debug`to see which translatable strings should be improved.

### Further reading

* Dev Note on the new JavaScript internationalization support
* Internationalization best practices in the plugin developer manual
* Internationalization in the [Gutenberg](https://themes.show/tag/gutenberg/) Manual

**Original: Internationalization in WordPress 5.0, published on December 20, 2018, translated by Advocate@WordPress大学. Reprinting and misappropriation of the translation is prohibited without permission!**

> Advocate summary: The translation field in javascript needs to be extracted and generated by the methods mentioned in the article to generate the pot file, and then use the poedit software to import the pot to translate the .po file, and then use the WP-CLI command or po2json to convert the content of the po to generate a json file ,This is done.
