1

Currently I need to set and restore locale on my translate function because if using setlocale globally will affecting other part of our system (i.e. legacy code)

So we need to use..

function translate($text, $locale) {

    $original = getenv('LC_ALL');

    putenv('LC_ALL=' . $locale);
    setlocale(LC_ALL, $locale);

    $translated = _("text);

    putenv('LC_ALL=' . $original);
    setlocale(LC_ALL, $original);

    return $translated;
}

Are there any better way?

Ryan
  • 10,041
  • 27
  • 91
  • 156
  • 1
    Perhaps use a purely PHP based PO/MO file parser/gettext implementation which does not rely on the locale? – deceze Jun 15 '14 at 09:17
  • For example [php-gettext](https://launchpad.net/php-gettext/) via [Using PHP Gettext Extension vs PHP Arrays in Multilingual Websites?](http://stackoverflow.com/a/2319192/367456) – hakre Jun 18 '14 at 21:20

4 Answers4

1

Don't use LC_ALL, just use LC_MESSAGES. While setting LC_ALL will of course work, because it sets the language globally, it's perfectly enough to set only LC_MESSAGES - only this variable is used for translating:

setlocale(LC_ALL, "en_US");
setlocale(LC_MESSAGES, "cs_CZ");
_("something") # you will get czech translation now, even if globally you use EN

So if your legacy code can handle LC_MESSAGES set correctly, you are fine.

See http://us2.php.net//manual/en/function.setlocale.php for more information on each LC_* variable.

Tomas
  • 57,621
  • 49
  • 238
  • 373
1

You should pull the locale from the LANG environment variable as LC_ALL may not be set. This may not be Windows compatable, if you need it to be let me know and I'll update it.


//default locale to use when all else fails
define('DEFAULT_LANG',    'en_US.UTF-8');

/**
 * returns the current locale based on the LANG environment variable. 
 * Only calls getenv() once, after that uses a cached value.  remove the static 
 * keyword to disable this functionality.
 * 
 * @return string returns the current locale, or DEFAULT_LANG on error.
 */
function get_lang() {
  static $lang; //static variable, so the resulting call to getenv() only fire once
  if (!isset($lang) || $lang=="") { 
    $lang = getenv('LANG');
    if (trim($lang)=='')
      $lang = DEFAULT_LANG;    
  }
  return $lang;
}

/**
 * @param string $text string to translate
 * @param string $locale locale to translate to, i.e. de_DE
 * @param boolean $provideFallback - provide the original local as a fallback if locale is not     recognized
 * @return boolean|string returns $text translated to $locale, or FALSE on error. 
 */
function translate($text, $locale, $provideFallback = FALSE, $resetLocale = TRUE) {
  if ((empty($locale) || trim($locale)=='') && !$provideFallback) 
    return FALSE;
  if (empty($text))
    return $text;

  $original = get_lang();

  //provide a fallback locale in case $locale is not recognized.
  if ($provideFallback) {
    $l = strval($locale);
    if (empty($locale) || trim($locale)=='')
      $l = $original; //set locale to the original locale, since none was provided.
    $locale = array($l, $original, DEFAULT_LANG);
  }

  setlocale(LC_ALL, $locale);
  $translated = _($text);
  if ($resetLocale) {
    setlocale(LC_ALL, $original);
  }
  return $translated;
}


echo get_lang().PHP_EOL;
echo translate("test1", "de_DE.UTF-8") . PHP_EOL;
echo translate("test2", "de_DE.UTF-8") . PHP_EOL;
Trick
  • 636
  • 4
  • 7
0

Perhaps php-gettext is an option? It's a pure PHP implementation of the gettext functionality. Its gettext_reader class can read a gettext .mo file without relying on the locale functionality or any other global state. (php-gettext can also provide drop-in replacements of the standard PHP gettext API, but that seems rather ugly/dangerous.)

Disclaimer: never actually used this in production.

pdw
  • 8,359
  • 2
  • 29
  • 41
0

I think this is the proper way to do that. I had the same problem few year ago.

Here is my code, similar to yours :

// Translate
$_SESSION['locale'] = $locale;
\Application::GetInstance()->getLocaleManager()->refresh();
$output["data"][] = array(
    "text" => utf8_encode($menuItem->getLibelle()),
    "lang" => utf8_encode(ucfirst($localeName)),
    "translation" => utf8_encode(_($menuItem->getLibelle()))
);
// Restore lang
$_SESSION['locale'] = "fr";
\Application::GetInstance()->getLocaleManager()->refresh();

refresh() is doing :

  • \Locale::setDefault($locale)
  • setlocale(...)
  • putenv("LANG=".$locale); // Required on windows environment
  • putenv("LANGUAGE=".$locale); // Required on windows environment
Kevin Labécot
  • 2,005
  • 13
  • 25