I usually use frameworks like Yii(2), Zend or Laravel to build pages but a customer forced us to use Wordpress this time.

I integrated Symfony/Twig as my template engine but now I have trouble with localization/translation. Because no matter what I do my strings won't be translated or even found by Wordpress.

Like in Laravel I created a Twig extension to translate the messages

class TranslateExtension extends \Twig_Extension {
    public function getFunctions(){
        return array(
            '__' => new \Twig_SimpleFunction('__', array($this, 'translate'))
        );
    }

    public function getName(){
        return 'TranslateExtension';
    }

    public function translate($string, $handle){
        return __($string, $handle);
    }
}

So I can do this in my template {{ __('Some strings here', 'plugin-handle') }} but these are not translated or even found by Loco translate creating a custom entry in the .pofile and compiling them into .mo files does not work either.

Can someone please explain me how this works? Nearly all answers/tutorials are about using POedit and insert the translations there but there are no "Add new translation" buttons and when I include the strings manually in my .po files and compile them WP still does not care about those.

If there is no way to use the WP method I'll include my custom functions to translate the strings without Wordpress

Edit
Maybe someone can find my mistake when I provide some more information This is how my po file looks like in /languages/cardio-de_DE.po

"Project-Id-Version: Cardio Plugin\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-11-30 16:19+0000\n"
"PO-Revision-Date: 2017-12-07 12:07+0100\n"
"Last-Translator: ******"
"Language-Team: German\n"
"Language: de_DE\n"
"Plural-Forms: nplurals=2; plural=n != 1;\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 2.0.5\n"
msgid "test"
msgstr "Fooo"

With Poedit I save the file and convert it to .mo format, then I upload it in the same directory like the po file
In my template I do {{ __("test", 'cardio') }} which is returns basically __("test", "cardio") from php but the output is just test and not Foo as expected

  • 1
    I don't know anything about "Loco translate" (for which you also won't get support here as 3rd party plugin questions are off topic). But I assume that the parser that searches for strings to translate in your templates probably just doesn't consider twig files. By trying to shoehorn Twig into WP you're getting yourself into a world of pain. Trust me, I've been there. ;) – kraftner Dec 7 '17 at 9:55
  • Well until now I ran fine with twig but I have to admit I don't really use Wordpress functions at all and included my custom query builders, template services, record services, form builders and so on.... Seems like I have to include my custom translation logic as well. Thanks for your answer – Robin Schambach Dec 7 '17 at 10:07
  • Okay I see I can't convince you to do it the WP way. I'll let you try this path yourself, I also didn't believe anyone. ;) So all you need for now is some way to automatically generate a *.pot file from your *.twig templates. Then you're approach should work. – kraftner Dec 7 '17 at 10:34
  • I know this does not belong here and I should create a new question but could you eventually explain why using twig is not a good way? I don't see any troubles at the moment except this one and after I find a way the page is finished – Robin Schambach Dec 7 '17 at 10:38
  • Sure, head over to chat.stackexchange.com/rooms/6/the-loop and ping me. – kraftner Dec 7 '17 at 12:55
up vote 3 down vote accepted

I have my own implementation of twig in WordPress as plugin and my translations are working. You can check my code.

Keep in mind couple of things when when you will test the code:

  • be sure that your WordPress have set locale which you want translate to
  • be sure that you your mo file is compiled from newest version of po file
  • be sure that your mo file exist and is loaded by load_plugin_textdomain function

You can debug which translation files WordPress are loading using script below.

function wpse_287988_debug_mofiles( $mofile, $domain ) {

    var_dump($mofile);

    return $mofile;
}

add_filter( 'load_textdomain_mofile', 'wpse_287988_debug_mofiles', 10, 2);

function wpse_287988_terminate() {
    die();
}

add_filter( 'wp_loaded', 'wpse_287988_terminate' );

Working twig implementation:

/**
 * Load composer autloader
 */
require_once dirname(__FILE__) . '/vendor/autoload.php';

// Main class

class WPSE_287988_Twig {

    /**
     * Templates path
     */
    private $templates_path;

    /**
     * Templates path
     */
    private $options;

    /**
     * Twig instance
     */
    private $twig;

    /**
     * Twig class constructor
     */
    public function __construct() {

        $this->templates_path = array();
        $this->options = array();

        $this->initialize_twig_options();
        $this->initialize_twig();
        $this->initialize_twig_functions();

        $this->define_hooks();
    }

    /**
     * Render method
     */
    public function render( $template, $variables = array() ) {

        return $this->twig->render( $template, $variables );
    }

    /**
     * Initialize twig options
     */
    private function initialize_twig_options() {

        /**
         * Resolve twig templates path
         */
        $plugins_dir = plugin_dir_path( __FILE__ );

        $this->templates_path[] = $plugins_dir;
        $this->templates_path[] = $plugins_dir . 'templates';

        foreach ($this->templates_path as $path) {

            if ( ! file_exists($path) ) {
                mkdir($path);
            }
        }

        /**
         * Resolve twig env options, disable cache
         */
        $this->options['cache'] = false;
    }

    /**
     * Initialize twig 
     */
    private function initialize_twig() {

        $loader       = new Twig_Loader_Filesystem( $this->templates_path );
        $this->twig   = new Twig_Environment($loader, $this->options );
    }

    /**
     * Initialize additional twig funcitons
     */
    public function initialize_twig_functions() {

        /**
         * Add gettext __ functions to twig functions.
         */
        $function = new Twig_Function('__', '__');

        $this->twig->addFunction($function);
    }

    /**
     * Load the plugin translations
     */
    public function load_plugins_textdomain() {

        $textdomain = 'wpse_287988';

        load_plugin_textdomain( $textdomain, false, basename( dirname( __FILE__ ) ) . '/languages' );
    }

    /**
     * Define hooks required by twig class
     */
    private function define_hooks()  {

        add_action( 'plugins_loaded', array( $this, 'load_plugins_textdomain' ) );
    }
}

// End of main class

// Initialize class

function wpse_287988_twig() {

    static $plugin;

    if ( isset( $plugin ) && $plugin instanceof WPSE_287988_Twig ) {
        return $plugin;
    }

    $plugin = new WPSE_287988_Twig();

    return $plugin;
}

wpse_287988_twig();

// End of class initialization

// Testing code

function wpse_287988_test_render() {

    $twig = wpse_287988_twig();
    echo $twig->render('template.html.twig');

    die();
}

add_action('init', 'wpse_287988_test_render');

// End of testing code

My template.html.twig file:

{% set text = "Foo" %}

{{ __(text, 'wpse_287988') }}

I keep my translations in languages directory in the main directory of my plugin. My translations files are named from textdomain and locale: wpse_287988-pl_PL.po and wpse_287988-pl_PL.mo.

  • Thanks for your comment but that does not work either – Robin Schambach Dec 7 '17 at 10:53
  • I added some code to my answer to show which file WordPress is loading for translation. Please make sure that this files exists in your file sytstem. – kierzniak Dec 7 '17 at 11:00
  • My files are in the output with the correct path – Robin Schambach Dec 7 '17 at 11:05
  • Do you use some WP ready Twig lib/plugin or custom implementation? I will try write my own and let you know. – kierzniak Dec 7 '17 at 11:10
  • Thank you very much. I don't use anything from Wordpress and build my custom implementation – Robin Schambach Dec 7 '17 at 11:13

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.