emersonthis
emersonthis

Reputation: 33348

CakePHP how to change __() language in the same request

I'm on CakePHP 2.6.x

My app is localized in French and English. English is the default.

My translation files currently look like this:

/app/Locale/eng/LC_MESSAGES/default.po
/app/Locale/fra/LC_MESSAGES/default.po

In my views, I normally can show localized text for the current language like this:

echo __("Foo");

However, in a few situations I need to override the current language and return a translation for a specific language. My understanding is __d() is meant for exactly this. However, the following does NOT work for me:

echo __d("fra", "Foo");

[Correction: __d is NOT meant for this.]

This seems to always return the translation of the current language. Basically acting just link __().

After a lot of trial-and-error I renamed the French .PO file...

/app/Locale/fra/LC_MESSAGES/fra.po

...and then __d("fra", "Foo"); DOES work as expected. But then __() DOESN'T work anymore. After I change the file name, all instances of __() return text in the default language.

What am I doing wrong? How do I get BOTH __d() and _() to work at the same time? Or another way of asking the same question: How can I change the language used by __() within the same request?

Update

My first instinct was to try something like what Lars suggests below. But for some reason it doesn't work. I'm doing the following in an email view:

    Configure::write("Config.language", "fra");
    $this->log(Configure::read("Config.language")); //'fra'
    $this->log( __("yes") ); //'yes'

Notice that the Config language is correctly set. But __() ignores it and echos the current language anyway. (Btw I checked and yes/oui is in the PO file)

Upvotes: 2

Views: 4564

Answers (2)

emersonthis
emersonthis

Reputation: 33348

Following @ndm's suggestion, I wrote a little utility for "toggling" the language mid-request.

Here's how I use it:

App::uses('L10nTool', 'Lib');
$L10n = new L10nTool();
$L10n->startToggleLg("fra");
...
//Bonjour, mon ami
...
$L10n->stopToggleLg();//Back to initial language

Later I might add another method, similar Lars's answer, for doing one quick string in a single method. But right now I'm doing some email logic in the "toggled" language, so it's easier for me to do it this way.

Here's the code:

<?php
App::uses('AppHelper', 'View/Helper');
App::uses('CakeSession', 'Model/Datasource');

class L10nTool {

    public $start_lg;
    public $use_session = FALSE;

    public function startToggleLg($lg) {

        if (CakeSession::check("Config.language")) { 
            $this->start_lg = CakeSession::read("Config.language");
            $this->use_session = TRUE;
        } else {
            $this->start_lg = Configure::read("Config.language");
        }

        if ( $this->use_session ) {
            CakeSession::write("Config.language", $lg);
        } else {
            Configure::write("Config.language", $lg);
        }

    }

    public function stopToggleLg($lg = NULL) {

        $lg = ($lg) ? $lg : $this->start_lg;

        if ( $this->use_session ) {
            CakeSession::write("Config.language", $lg);
        } else {
            Configure::write("Config.language", $lg);
        }        

    }

}

Upvotes: 3

Lars Ebert-Harlaar
Lars Ebert-Harlaar

Reputation: 3537

Your best bet would be to change the set language prior the call and change it back later:

$before = Configure::read('Config.language');
Configure::write('Config.language', 'fra');
echo __('Your String');
Configure::write('Config.language', $before);

You could even put that into a function:

function __lang($string, $language) {
    $before = Configure::read('Config.language');
    Configure::write('Config.language', $language);
    echo __($string);
    Configure::write('Config.language', $before);
}

Edit

As mdm explained in the comments, that is basically what the I18N::translate function does.

If this (and my function) does not work, I would guess that there is something wrong with your translation files. Have you tried switching to the target language globally? Does that print the correct string?

To circumvent all configuration and session values, you could simply rely on the I18N::translate function:

function __lang($string, $language) {
    echo I18N::translate($string, null, null, I18n::LC_MESSAGES, null, $language);
}

Upvotes: 3

Related Questions