# Test Internationalization Functions

Share on Social Plugin uses WordPress Internationalization (i18n) functions extensively and we need an easy method to test the string translations. In this blog, we explain the unit tests of i18n functions.

Setup Language Files for Tests

In WordPress Localization, we installed GetText software required for WordPress i18n and l10n, and also generated language files for the plugin.

To test plugin internationalization, we require separate set of language files. Procedure to generate test language files is described here.

Language files for tests are placed in tests/phpunit/langs directory. Create a new directory with next command.

$ cd share-on-social/tests/phpunit
$ mkdir langs

Next, copy the POT file generated by localization, to the test langs directory.

$ cd share-on-social
$ cp langs/share-on-social.pot tests/phpunit/langs

Next, generate PO file for the default language. The default language of Share on Social Plugin is en_US.

$ cd tests/phpunit/langs
$ msginit -i share-on-social.pot -o sos-domain-en_US.po -l en_US

The PO for en_US is shown in the next listing. For default language, both msgid (orginal string) and msgstr (translated string) will have same string.

share-on-social/tests/phpunit/langs/sos-domain-en_US.po

# Copyright (C) 2014 Share on Social
# This file is distributed under the same license as the Share on Social package.
msgid ""
msgstr ""
"Project-Id-Version: Share on Social 1.0.0n"
"Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/share-on-socialn"
"POT-Creation-Date: 2014-11-14 13:45:33+00:00n"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n"
"Content-Transfer-Encoding: 8bitn"
"PO-Revision-Date: 2014-11-14 19:16+0530n"
"Last-Translator: m <m@m>n"
"Language-Team: Englishn"
"Language: en_USn"
"Plural-Forms: nplurals=2; plural=(n != 1);n"

#: admin/class-activator.php:109
msgid "Content is Locked"
msgstr "Content is Locked"

#: admin/class-activator.php:110
msgid "Share to unlock the content"
msgstr "Share to unlock the content"

....

Copy the default PO file to Esperanto France language file.

$ cd tests/phpunit/langs
$ cp sos-domain-en_US.po sos-domain-eo_FR.po

Next, edit the sos-domain-eo_FR.po and prefix each and every msgstr string with Espéranto-France. The default and modified msgstr looks as follows.

# ORIGINAL

msgstr "Content is Locked"


# MODIFIED

msgstr "Espéranto-France Content is Locked"

Also, modify the header and change Language-Team to Esperanto and Language to es_FR. The modified sos-domain-eo_FR.po file is shown in the next listing.

share-on-social/tests/phpunit/langs/sos-domain-eo_FR.po

# Copyright (C) 2014 Share on Social
# This file is distributed under the same license as the Share on Social package.
msgid ""
msgstr ""
"Project-Id-Version: Share on Social 1.0.0n"
"Report-Msgid-Bugs-To: http://wordpress.org/support/plugin/share-on-socialn"
"POT-Creation-Date: 2014-11-14 13:45:33+00:00n"
"MIME-Version: 1.0n"
"Content-Type: text/plain; charset=UTF-8n"
"Content-Transfer-Encoding: 8bitn"
"PO-Revision-Date: 2014-11-14 19:17+0530n"
"Last-Translator: m <m@m>n"
"Language-Team: Esperanton"
"Language: eo_FRn"
"Plural-Forms: nplurals=2; plural=(n != 1);n"

#: admin/class-activator.php:109
msgid "Content is Locked"
msgstr "Espéranto-France Content is Locked"

#: admin/class-activator.php:110
msgid "Share to unlock the content"
msgstr "Espéranto-France Share to unlock the content"

....

Finally, generate MO file for Esperanto from PO using GetText’s msgfmt command.

$ cd tests/phpunit/langs
$ msgfmt -o sos-domain-eo_FR.mo  sos-domain-eo_FR.po

With that, language files for i18n unit tests are ready, and we can go ahead with the translation tests.

Test Internationalization Functions

In translation tests, we use Util::change_locale() method to change the locale and load the language files from tests/phpunit/langs directory.

share-on-social/tests/phpunit/util/class-util.php

    static function change_locale ( $lang ) {
        global $locale;
        $locale = $lang;
        load_plugin_textdomain( 'sos-domain', FALSE, 
                'share-on-social/tests/phpunit/langs' );
    }

Text domain is unloaded in teardown() method which reverts the test case back to the default language.

share-on-social/tests/phpunit/tests/test-help.php

class Test_Help extends WP_UnitTestCase {

    public function setup () {
        parent::setup();
        
        require_once 'admin/class-help.php';
        $this->sos_help = new Sos_Help();
    }

    public function teardown () {
        parent::teardown();
        unload_textdomain( 'sos-domain' );
    }

Let’s go through a method which uses internationalization function to understand how translations are tested. In Sos Locker admin screen, we display context help to create a new locker and these help text tabs are generated in Sos_Help class. Sos_Help::locker_id_tab() returns help text tab for locker id, and as we use i18n function __() for the help text, they get translated based on locale.

share-on-social/admin/class-help.php

    function locker_id_tab () {
        $label = __( 'Locker ID', 'sos-domain' );
        $help1 = __( 'Enter a uniquie ID for the locker. ', 'sos-domain' );
        $help1 .= __( 'Both name and number are allowed as the id. ', 
                'sos-domain' );
        $help2 = __( 
                'Use some descriptive name as locker id which is easy to remember', 
                'sos-domain' );
        $html = <<<EOD
<h3>$label</h3>
<p>$help1</p>
<p>$help2</p>
EOD;
        return $this->get_tab( 'locker_id_tab', $label, $html );
    }

The method is tested in test case Test_Help, where the method Test_Help::test_locker_id_tab() test the locker id help text for default language en_US.

share-on-social/tests/phpunit/tests/test-help.php

    public function test_locker_id_tab () {
        $tab = $this->sos_help->locker_id_tab();       
        $this->assertCount( 3, $tab );
        $this->assertSame( 'locker_id_tab', $tab[ 'id' ] );
        $this->assertSame( 'Locker ID', $tab[ 'title' ] );

        $expected = $this->expected_locker_id_tab();
        $this->assertSame( Util::trim_whitespaces( $expected ), 
                Util::trim_whitespaces( $tab[ 'content' ] ) );
    }

It fetch the help tab array from method under test Sos_Help::locker_id_tab(). As the text domain is not loaded, the $tab[’title’] returns default string ‘Locker ID’.

To test the help text, it calls a private method Test_Help::expected_locker_id_tab() which returns the expected help text for the tab. For default language, the $lang_str parameter is null, so the expected text will not have any prefix.

share-on-social/tests/phpunit/tests/test-help.php

    private function expected_locker_id_tab ( $lang_str = '' ) {
        $lang_str == '' ? $lang_str : $lang_str .= ' ';
        $html = <<<EOD
        <h3>{$lang_str}Locker ID</h3>
        <p>{$lang_str}Enter a uniquie ID for the locker. {$lang_str}Both name and number are allowed as the id. </p>
        <p>{$lang_str}Use some descriptive name as locker id which is easy to remember</p>
EOD;
        return $html;
    }

Actual translation is tested in next test, Test_Help::test_locker_id_tab_translate().

share-on-social/tests/phpunit/tests/test-help.php

    public function test_locker_id_tab_translate () {
        Util::change_locale( 'eo_FR' );
        $tab = $this->sos_help->locker_id_tab();        
        $this->assertCount( 3, $tab );
        $this->assertSame( 'locker_id_tab', $tab[ 'id' ] );
        $this->assertSame( 'Espéranto-France Locker ID', $tab[ 'title' ] );

        $expected = $this->expected_locker_id_tab( 'Espéranto-France' );
        $this->assertSame( Util::trim_whitespaces( $expected ), 
                Util::trim_whitespaces( $tab[ 'content' ] ) );
    }

In this test, we first change the locale to Esperanto France by calling utility method Util::change_locale( 'eo_FR' ). Earlier, while preparing the eo_FR language file, we prefixed all msgstr items with Espéranto-France. Now, i18n functions kicks in and returns the translated strings. For example, for string ‘Locker ID’, it returns ‘Espéranto-France Locker ID’.

As done before, we fetch the help tab array from method under test Sos_Help::locker_id_tab(). But this time, as text domain is set to Esperanto by Util::change_locale(), the $tab[’title’] is loaded with the string from eo_FR file, and it is ‘Espéranto-France Locker ID’ instead of default ‘Locker ID’.

Since eo_FR is loaded, tabs’ help text is also now prefixed with Espéranto-France. So, while calling the private method Test_Help::expected_locker_id_tab(), we pass string Espéranto-France as parameter so that expected text is also prefixed with string Espéranto-France. If everything is in order - translation files in proper directory, loading of text domain and proper use of i18n function - then test passes through.

In the next blog, we show how to test WordPress Ajax calls.