Your Location is: Home > Cakephp

Pseudolocalization in CakePHP/2

From: Stockholm View: 4911 Álvaro González 

Question

I'm adapting an existing application to support several languages and I'd like to implement pseudolocalization, i.e. make localized strings:

<?php echo h(__('Edit program settings')); ?>

... stand out:

[!!! εÐiţ Þr0ģЯãm səTτıИğ§ !!!]

... so I can quickly spot omissions and detect potential layout problems.

Unless I'm wrong the feature is not builtin and there aren't third-party plugins. What are my chances?

I feel a sensible path would be to extend I18n and overwrite I18n::translate(). However I'm not specially familiar with CakePHP internals and I'm not sure about how to make __() and family use my extended class.

On the other side, functions in lib\Cake\basics.php are wrapped in function_exists() calls so I guess I could write my own versions...

I'd welcome any suggestion.

Best answer

The ideal technique would be to be able to define a custom class:

class CustomI18n extends I18n {
    public static function translate($singular, $plural = null, $domain = null, $category = 6, $count = null, $language = null) {
    }
}

… and instruct CakePHP to use my custom class rather than the original. That would be coherent with e.g. the way view helpers work.

Unfortunately, I don't think it can't be done¹ because $this->Html inside a view is a dynamic property but __() contains a hard-coded class name: I18n::translate($singular).

¹ Yes, almost everything can be done. You know what I mean :)


Since it's just a helper tool that's not meant for Production, you can always resort to a quick and dirty hack not really specific to CakePHP:

  1. Rewrite into a file of your choice the functions from lib\Cake\basics.php you're interested in, typically the ones that start with underscore: __(), _n(), ...

    function __($singular, $args = null) {
        if (!$singular) {
            return;
        }
        $singular = pseudotranslation($singular); // <---------------------
    
        App::uses('I18n', 'I18n');
        $translated = I18n::translate($singular);
        if ($args === null) {
            return $translated;
        } elseif (!is_array($args)) {
            $args = array_slice(func_get_args(), 1);
        }
        return vsprintf($translated, $args);
    }
    

    Make sure you don't break vsprintf codes.

  2. Use auto_prepend_file to load the file before CakePHP startup begins. Ideally, set it on in your development box.

This has the advantage of being unobtrusive. You can enable or disable auto_prepend_file quite easily or you can take care of that in your prepended script.


Alternatively, CakePHP allows to override most classes so you could copy /lib/Cake/I18n/I18n.php as /app/Lib/I18n/I18n.php and tweak I18n::translate() to your liking. However I find this less convenient: you still have to maintain a custom copy of a system file if you upgrade CakePHP and there's no simple mechanism to disable pseudolocalisation on runtime since CakePHP will always use the file when it's present.