* @author Kornel LesiƄski * @license http://www.gnu.org/licenses/lgpl.html GNU Lesser General Public License * @version SVN: $Id$ * @link http://phptal.org/ */ /** * PHPTAL_TranslationService gettext implementation. * * Because gettext is the most common translation library in use, this * implementation is shipped with the PHPTAL library. * * Please refer to the PHPTAL documentation for usage examples. * * @package PHPTAL * @author Laurent Bedubourg */ class PHPTAL_GetTextTranslator implements PHPTAL_TranslationService { private $_vars = array(); private $_currentDomain; private $_encoding = 'UTF-8'; private $_canonicalize = false; public function __construct() { if (!function_exists('gettext')) throw new PHPTAL_ConfigurationException("Gettext not installed"); $this->useDomain("messages"); // PHP bug #21965 } /** * set encoding that is used by template and is expected from gettext * the default is UTF-8 * * @param string $enc encoding name */ public function setEncoding($enc) { $this->_encoding = $enc; } /** * if true, all non-ASCII characters in keys will be converted to C form. This impacts performance. * by default keys will be passed to gettext unmodified. * * This function is only for backwards compatibility * * @param bool $bool enable old behavior */ public function setCanonicalize($bool) { $this->_canonicalize = $bool; } /** * It expects locale names as arguments. * Choses first one that works. * * setLanguage("en_US.utf8","en_US","en_GB","en") * * @return string - chosen language */ public function setLanguage(/*...*/) { $langs = func_get_args(); $langCode = $this->trySettingLanguages(LC_ALL, $langs); if ($langCode) return $langCode; if (defined("LC_MESSAGES")) { $langCode = $this->trySettingLanguages(LC_MESSAGES, $langs); if ($langCode) return $langCode; } throw new PHPTAL_ConfigurationException('Language(s) code(s) "'.implode(', ', $langs).'" not supported by your system'); } private function trySettingLanguages($category, array $langs) { foreach ($langs as $langCode) { putenv("LANG=$langCode"); putenv("LC_ALL=$langCode"); putenv("LANGUAGE=$langCode"); if (setlocale($category, $langCode)) { return $langCode; } } return null; } /** * Adds translation domain (usually it's the same as name of .po file [without extension]) * * Encoding must be set before calling addDomain! */ public function addDomain($domain, $path='./locale/') { bindtextdomain($domain, $path); if ($this->_encoding) { bind_textdomain_codeset($domain, $this->_encoding); } $this->useDomain($domain); } /** * Switches to one of the domains previously set via addDomain() * * @param string $domain name of translation domain to be used. * * @return string - old domain */ public function useDomain($domain) { $old = $this->_currentDomain; $this->_currentDomain = $domain; textdomain($domain); return $old; } /** * used by generated PHP code. Don't use directly. */ public function setVar($key, $value) { $this->_vars[$key] = $value; } /** * translate given key. * * @param bool $htmlencode if true, output will be HTML-escaped. */ public function translate($key, $htmlencode=true) { if ($this->_canonicalize) $key = self::_canonicalizeKey($key); $value = gettext($key); if ($htmlencode) { $value = htmlspecialchars($value, ENT_QUOTES, $this->_encoding); } while (preg_match('/\${(.*?)\}/sm', $value, $m)) { list($src, $var) = $m; if (!array_key_exists($var, $this->_vars)) { throw new PHPTAL_VariableNotFoundException('Interpolation error. Translation uses ${'.$var.'}, which is not defined in the template (via i18n:name)'); } $value = str_replace($src, $this->_vars[$var], $value); } return $value; } /** * For backwards compatibility only. */ private static function _canonicalizeKey($key_) { $result = ""; $key_ = trim($key_); $key_ = str_replace("\n", "", $key_); $key_ = str_replace("\r", "", $key_); for ($i = 0; $i 127) { $result .= 'C<'.$o.'>'; } else { $result .= $c; } } return $result; } }