5

I am struggling to load translation in JavaScript for my simple plugin. Translation works for PHP, but not in JS. What seems to be the problem, how can I debug this?

  1. I have loaded text domain in my plugin method and this works ok. My text domain is instantsearch, locale for my language is hr

    load_plugin_textdomain('instantsearch', FALSE, basename( dirname( __FILE__ ) ) . '/languages/'); // returns true
    var_dump(__('No results', 'instantsearch')); // This shows correct translation for my language
    
  2. I have generated .json file with WP CLI

    wp i18n make-json languages/
    
  3. This gives me new file /myplugin/languages/instantsearch-hr-hash.json. My JS file is assets/instant-search.js and somewhere I have read that I need to manually rename that hash. I just copied that file two times and renamed them to the following just to try it out, so something out of those 3 should be working :)

    instantsearch-hr-47626afcca1bc179bc9eedb6abdc01ff.json
    instantsearch-hr-instant-search.json
    instantsearch-hr-instantsearch.json
    
  4. I have registered the script for translation

    wp_register_script('instant-search', plugins_url('assets/instant-search.js', __FILE__), array('jquery', 'wp-i18n'), false, true);
    wp_enqueue_script('instant-search');
    wp_set_script_translations('instant-search', 'instantsearch', plugins_url('languages', __FILE__));
    
  5. In the script at the very top I have tried this, but it doesn't give me translation like in PHP, it just shows english default string

    console.log(wp.i18n.__('No results', 'instantsearch'));
    
  6. Here is example of json

    {"translation-revision-date":"2019-12-31 13:41+0100","generator":"WP-CLI\/2.4.0","source":"assets\/instant-search.js","domain":"messages","locale_data":{"messages":{"":{"domain":"messages","lang":"hr","plural-forms":"nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : 2);"},"No results":["Nema prona\u0111enih rezultata"]}}}
    
  7. I know I can use wp_localize_script() to move string from PHP to JS but from WP 5.* we should be able to do it

6
  • you use wp_register_script instead of wp_enqueue_script then translation are not loaded. then in wp_set_script_translations you have to set the path look in the documentation Commented Dec 31, 2019 at 15:06
  • I use both, first I register and then a little bit later enqueue. I have updated my code. I tried setting wp_set_script_translation with a path (which correctly points to languages directory in plugin) but unfortunately still no success Commented Dec 31, 2019 at 15:46
  • I tried you json content with a file instantsearch-hr-instant-search.json and it works. then I think you are near of having a good result but I don't know how to help you. Commented Dec 31, 2019 at 16:43
  • 2
    I'm having the same issue. Did you ever solve this? Commented May 1, 2020 at 20:57
  • The same and it looks like the @JosiahSprague's answer doesn't work for me. I tried a lot variations. In the page, I can see an inline script and empty i18n JSON '{ "locale_data": { "messages": { "": {} } } }'. It's right above my app.js. wp_set_script_translations() returns true. get_locale() is 'nl_NL' and is correct. Commented Aug 5, 2020 at 18:22

6 Answers 6

3

I was having the same problem and this is how I solved it:

First, the generated JSON file has some errors. You need to update where it says messages with your text domain. There are three places where that needs to be changed. I also had to change the lang attribute to be all lowercase with a dash. Here are the fields I changed:

{
  "domain": "my-text-domain",
  "locale_data": {
    "my-text-domain": { // Instead of "messages"
      "": {
        "domain": "my-text-domain",
        "lang": "es-es"
      },
      ...
    }
  }
}

Second, the file name with the md5 hash tends to have the wrong md5 hash, so it's best to rename the file to {domain}-{locale}-{script-name}.json, so mine became my-text-domain-es_ES-my-script-name.js.

Third, the wp_set_script_translations function needs to be called with the right path, and attached to the right hook. This is what I had to do, since I was localizing an admin-side script:

function enqueue_scripts() {
    wp_set_script_translations( 'script-name', 'my-text-domain', plugin_dir_path( dirname(__FILE__) ) . 'languages' );
}
add_action( 'admin_enqueue_scripts', 'enqueue_scripts' );

Try echoing out the value of plugin_dir_path( dirname(__FILE__) ) . 'languages' to make sure you're getting the path where your translation files are.

Once I sorted out all of these little details, my translations started working, so I hope this helps someone else!

2
  • 1
    It doesn't work for me. I read a lot of articles and posts. It should work, but... I can't figure out where I'm wrong. Perhaps, now you can add some additional ingo by the question. Commented Aug 5, 2020 at 18:38
  • It seems that replacing message with the text domain has no effect, instead having a wrong MD5 hash can cause the issue, as you mentioned later. I added some details about that case here: wordpress.stackexchange.com/a/415545/231798 Commented Apr 22, 2023 at 20:53
2

TL;DR: run npm run build before executing wp i18n commands!

The problem described in this post also happens if you generate the .pot and .po files before generating the production js files. This will cause the wp CLI to produce only one JSON file (instead of two) and the app will not be able to find the one with the desired hash.

Suppose that you have a file src/App.js that is transformed to build/app.js by your npm scripts.

If you haven't produced the build/app.js file yet and you generate the POT file using wp i18n make-pot you will end having something like this in your POT file:

#: src/App.js:11
msgid "My label"
msgstr ""

The same will be reported in the .po files and only one JSON file will be produced, e.g. my-plugin-it_IT-14b1e33d5bf5649597cdc0e4f684dadd.json

If you run npm run build and then wp i18n make-pot, you can see that both the source file and the production file will be listed:

#: src/App.js:11
#: build/app.js:462
msgid "My label"
msgstr ""

Starting from this POT file, wp i18n make-json will produce 2 JSON files:

  • my-plugin-it_IT-14b1e33d5bf5649597cdc0e4f684dadd.json (src/App.js)
  • my-plugin-it_IT-b8c773ce202d23e4e6718b08f32ecf3c.json (build/app.js)

To verify the expected hash you can use the following command:

echo -n "build/app.js" | md5sum

Moreover, in your JavaScript files you may have to use

const { __ } = wp.i18n;

instead of

import { __ } from '@wordpress/i18n';
1

I'll leave it here. Perhaps it will help someone. I had the same issue. I did all steps and all looked working, but in JS __('Hello world', 'textdomain'); didn't work.

There are a lot of recommendations about the JSON file for example to use 'nl' instead 'nl_NL', etc. For today (2020.08.06) you shouldn't change a json-file in any way except its name as custom_dir/{domain}-{locale}-{handle}.json.

The base steps:

  1. PHP code:
load_theme_textdomain( 'textdomain', get_template_directory() . '/languages' );
// ...
wp_enqueue_script( 'scripts', asset_url( 'js/app.js' ), [ 'jquery', 'wp-i18n' ], null, true );
wp_set_script_translations( 'scripts', 'textdomain', get_template_directory() .'/languages/js' );
  1. I use the Poedit application for creating & translating the nl_NL.po file.

  2. With WP-CLI I generate wp i18n make-json ./languages ./languages/js --no-purge --pretty-print a json-file and I reneme it to ./languages/js/textdomain-nl_NL-scripts.json.

The essential thing: The author's mistake is plugins_url('languages', __FILE__) in wp_set_script_translations();. My mistake was a simple get_template_directory_uri() instead of get_template_directory(). But the function requires "$path The full file path to the directory containing translation files".

All you need is placed here: https://developer.wordpress.org/block-editor/developers/internationalization/.

1
  • I cannot thank you enough. THANK YOU THANK YOU. This worked for me as I was working with theme translation and wp cli. Commented Jul 2, 2024 at 10:22
1

Inside the wp_set_script_translations function, you use plugins_url('languages', __FILE__) which is not the correct path.

You should use plugin_dir_path(__FILE__) . 'languages/'

1

Here are the steps I followed to make WordPress translations work in Javascript (WordPress 6.8.3):

  1. Make sure you've added load_plugin_textdomain or load_theme_textdomain with proper hook (init for plugins and after_setup_theme for themes).
  2. Use WP-CLI command to generate .json file with translations based on PO file - for example, wp i18n make-json languages/. Both $textdomain-$locale-md5.json and $textdomain-$locale-$handle.json work for me.
  3. Make sure you've added wp_set_script_translations and added wp-i18n as dependency to wp_register_script or wp_enqueue_script function with proper hook wp_enqueue_scripts. After this, the translated string should be returned in the browser console:
    console.log(wp.i18n.__('Translated text', 'text-domain'))

console.log of wp.i18n1

If strings in Javascript are still not being translated, please check your script bundler configuration.
In my case, adding wp.i18n in webpack's externals configuration and using const { __ } = wp.i18n; fixed the issue.

0

I too could not get @wordpress/i18n to translate strings, despite following the directions on https://developer.wordpress.org/block-editor/how-to-guides/internationalization/ under "Provide Your Own Translations".

The following worked for me:

  1. I was translating to Spanish and using just 'es' in my po file, which used the same in the generated json files. I changed that to es_ES.

  2. I had multiple components importing @wordpress/i18n and when I ran "wp i18n make-json languages", separate json files were created for each with a hash in the file name. There is one json file for build/index.js - that file contained all translations and is the only one I needed.

  3. I changed the json filename of the file referencing build/index.js (in #2 above) to: {Text Domain}-{locale}-{script-name}.json, so mine became localestr-es_ES-scriptname.json. In the above, localestr is my text domain set in my plugin and in my translation strings, ex: __('Back', 'localestr '). scriptname is the name used with wp_enqueue_script('scriptname')

Many people, in many places say wp_set_script_translations( 'myguten-script', 'myguten', plugin_dir_path( FILE ) . 'languages' ); Needs forward slashes before and/or after languages. I found a forward slash around 'languages' are not needed at all.

I was also able to leave "domain":"messages" in my json file. That works for me, and I did not need to change "messages" in 3 places to my Text Domain.

I hope this helps someone else. It's super frustrating to debug because there is so little documentation, debug options, and the documentation is missing a very important bit about the generated json files with wp-cli are not named correctly to automatically get set up with wp_set_script_translations.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.