Localization of Vue based WordPress plugin

Here’s how localization (aka Internationalization or i18n ) of a WordPress plugin with Vue front-end can be done. Language resources need to be used both in plugin WordPress backend and Vue based front end. Plugin should be translatable with WordPress standard tools. and translations (.po, .mo files) should be served by WordPress.

Before you start

You should have gettext installed in your system. Y

Defining translatable resources

We can not use strings for showing information to end user in multi-language plugin. We will use gettext functions instead. These functions provide a mechanism for automatic generation of central language resources (.po files) and means to present translated strings from that resource. Here is an example how function __() is used for this purpose in WordPress plugin backend code :

<?php
echo '<strong>' . __('Mango Form Processor works only when Contact Form 7 is installed and activated.') . '</strong>';

All the language resources that are used in Vue component need to be defined in plugin php code and should be passed to Javascript front end with the help of WordPress function wp_localize_script. Goal here is to generate localized resources that can be accessed in Javascript as global variable. For more details, see here.

The function is called in callback for the action admin_enqueue_scripts

<?php
function loadAdminJs() {
    add_action('admin_enqueue_scripts', 'initAdminPage');
}

function initAdminPage() {
    registerVueScripts(); //encqueues JS Vue frontend scripts
    wp_localize_script(
        'mangofp_vuejs',
        'MANGOFP_RESOURCES', //name of the global variable that is geenrated for Javascript
        [
            'adminUrl' => get_rest_url( null, '/mangofp', 'rest'), //uri for backend api that Vue frontend will use
            'strings' => MangoFp\Localization::getStrings() //actual language resources that will be used in Vue
        ]
    );
}

registerVueScripts enqueues all our plugin Javascript resouces to the front end. For details, look here. Data passed to Javascripts with wp_language_script does not have to be only l18n resources. We are also passing url to our plugin API that Javascript front end will use. Actual localization resources are fetched with MangoFp\Localization::getStrings() and are defined like this:

<?php
class Localization {
    static public function getStrings() {
        $MANGOFP = 'mangofp'; //domain for the plugin language resources
        return [
            'Send' => esc_html__('Send', $MANGOFP),
            'State' => esc_html__('State', $MANGOFP),
            'All' => esc_html__('All', $MANGOFP),
            'Confirm' => esc_html__('Confirm', $MANGOFP),
            'Confirm and send' => esc_html__('Confirm and send', $MANGOFP)
           //...
        ];
    }
}

esc_html__ here is a gettext function that “guards” our plugin’s front end from invalid UTF8 characters and unwanted HTML code.

Generate POT file

There are several ways for generating pot-files. Our solution is based on Grunt. If you don’t have already (but for Vue front end you probably have) NPM installed, then do it. In your plugin directory add package.json file

{
    "name": "Your plugin name",
    "version": "0.0.1",
    "description": "Your plugin description",
    "scripts": {
        "gettext": "grunt gettext"
    },
    "dependencies": {},
    "devDependencies": {
        "grunt": "^0.4.5",
        "grunt-pot": "^0.2.1"
    }
}

If you already have package.json file, just add devDependencies to it. Now execute on command line in your plugin directory:

npm install

in your plugin directory create Gruntfile.js

module.exports = function(grunt) {
    grunt.initConfig({
        pot: {
            options: {
                text_domain: 'mangofp', //Your text domain. Produces mangofp.pot
                dest: 'languages/', //directory to place the pot file
                keywords: ['gettext', '__', 'esc_html__', 'esc_html_e'], //gettext functions to look for language resources
            },
            files: {
                src: ['**/*.php'], //Parse all php files
                expand: true,
            }
        },
    });
    grunt.loadNpmTasks('grunt-pot');
    grunt.registerTask('gettext', [
        'pot',
    ]);
};

Now you are ready to create the pot file. You can do it from command line like this:

npm run gettext

Localize language resources

For the actual translation we are using WordPress plugin Loco Translate. We recommend using local WordPress installation for plugin development and then it is also convenient to install Loco Translate there, too. Now you can translate the resources from primary language to some additional language in your local development environment.

Localization of plugin with Loco Translate
Localization of plugin’s language resources from English to Estonian

Make sure that you transfer generated po files to your versioning system and/or staging environments.

Use translations in Vue components

Now localized language resources are accessible in end-user browser.

Investigating localized language resources in browser Javascript console.

Language resources could be referenced from this global object, but from Vue component its more convenient through a Vue plugin.

Here is the source code of this plugin. Function $locStr accesses a string. If the string is not found, it returns the text in the original language (key for the language resouce)

/*globals MANGOFP_RESOURCES:false */
const locStr = {
    install(Vue) {
        Vue.prototype.$locStr = function(key) {
            if (
                !MANGOFP_RESOURCES ||
                !MANGOFP_RESOURCES.strings ||
                !MANGOFP_RESOURCES.strings[key]
            ) {
                return key;
            }
            return MANGOFP_RESOURCES.strings[key];
        };
    },
};

export default locStr;

Plugin is stored in plugins/locStr.js and the plugin needs to be used by your Vue object. This is usually done in main.js through use of command: Vue.use(locStr).

Here is an example of the complete main.js file that uses locStr ja vuetify plugins:

import Vue from 'vue';
import App from './App.vue';
import store from './store';
import vuetify from './plugins/vuetify';
import locStr from './plugins/locStr';

Vue.config.productionTip = false;

Vue.use(locStr); //add this to your main.js file

new Vue({
    store,
    vuetify,
    render: h => h(App),
}).$mount('#app');

Language string in Vue code templates can now be used like this:

<v-sheet v-if="selectedItem">
    {{ $locStr('Change') }}
    <v-select
        :items="labels"
        v-model="selectedLabel"
        :label="$locStr('Label')"
    >
    </v-select>
    ...
</v-sheet>

And in Javascript objects like this:

<script>
export default {
    data() {
        return {
            expanded: [],
            headers: [
                { text: this.$locStr('Date'), value: 'dateTime' },
                { text: this.$locStr('Status'), value: 'changeSubType' },
                { text: this.$locStr('To'), value: 'contentTo' },
            ],
        };
    },
    ...
}
</script>

Happy localizing!

Comments are closed.