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 .po
file 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
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
.