How to provide a fallback or mapping for translation messages?

Sometimes you want to use exisiting translations for locales, which do not directly match. An example would be a website targeting Germany (de_de), Austria (de_at) and Switzerland (de_ch, fr_ch, it_ch). Although you may have exisiting translations for German (de), French (fr) and Italian (it), there are problems using it directly.

Assuming you've PHP message translation source files, a solution could be to override the default messages component class CPhpMessageSource with a custom class, which implements the fallback.

class P3PhpMessageSource extends CPhpMessageSource
    public $mappings = array();

    protected function getMessageFile($category, $language)
        // find default file
        $messageFile = parent::getMessageFile($category, $language);

        // look for fallbacks if no file is found
        if (!is_file($messageFile)) {
            if (isset($this->mappings[$language])) {
                // find file according to mapping
                $messageFile = parent::getMessageFile($category, $this->mappings[$language]);
            } else {
                // find file based on the string before _
                $messageFile = parent::getMessageFile($category, substr($language,0,strpos($language,'_')));
        return $messageFile;

Define your messages application component as follows:

'messages'      => array(
            'class' => 'P3PhpMessageSource',
            'mappings' => array(
                'de_de' => 'de',
                'de_at' => 'de',
                'de_ch' => 'de',
                'fr_ch' => 'fr',
                'it_ch' => 'it'