cakephpinternationalizationcakephp-2.4

Pseudolocalization in CakePHP/2


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.


Solution

  • 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.