adapted i18n from 4.9
Dieser Commit ist enthalten in:
Ursprung
335ed4a0d5
Commit
515ff38842
1 geänderte Dateien mit 376 neuen und 0 gelöschten Zeilen
376
conlite/classes/class.i18n.php
Normale Datei
376
conlite/classes/class.i18n.php
Normale Datei
|
@ -0,0 +1,376 @@
|
|||
<?php
|
||||
/**
|
||||
* This file contains the the I18N class.
|
||||
*
|
||||
* @package Core
|
||||
* @subpackage I18N
|
||||
* @author Murat Purc <murat@purc.de>
|
||||
* @copyright four for business AG <www.4fb.de>
|
||||
* @license http://www.contenido.org/license/LIZENZ.txt
|
||||
* @link http://www.4fb.de
|
||||
* @link http://www.contenido.org
|
||||
*/
|
||||
|
||||
defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
|
||||
|
||||
/**
|
||||
* Internationalization (i18n) class.
|
||||
*
|
||||
* @package Core
|
||||
* @subpackage I18N
|
||||
*/
|
||||
class cI18n {
|
||||
|
||||
const i18n_DEFAULT_DOMAIN = "conlite";
|
||||
|
||||
/**
|
||||
* i18n related assoziative data cache.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected static $_i18nData = array(
|
||||
'language' => NULL,
|
||||
'domains' => array(),
|
||||
'files' => array(),
|
||||
'cache' => array()
|
||||
);
|
||||
|
||||
/**
|
||||
* Initializes the i18n.
|
||||
*
|
||||
* @param string $localePath
|
||||
* Path to the locales
|
||||
* @param string $langCode
|
||||
* Language code to set
|
||||
* @param string $domain [optional]
|
||||
* Language domain
|
||||
*/
|
||||
public static function init($localePath, $langCode, $domain = self::i18n_DEFAULT_DOMAIN) {
|
||||
if (function_exists('bindtextdomain')) {
|
||||
// Bind the domain 'contenido' to our locale path
|
||||
bindtextdomain($domain, $localePath);
|
||||
|
||||
// Set the default text domain to 'contenido'
|
||||
textdomain($domain);
|
||||
|
||||
// Half brute-force to set the locale.
|
||||
if (!ini_get('safe_mode')) {
|
||||
putenv("LANG=$langCode");
|
||||
}
|
||||
|
||||
if (defined('LC_MESSAGES')) {
|
||||
setlocale(LC_MESSAGES, $langCode);
|
||||
}
|
||||
|
||||
if (false === empty($langCode)) {
|
||||
setlocale(LC_CTYPE, $langCode);
|
||||
}
|
||||
}
|
||||
|
||||
self::$_i18nData['domains'][$domain] = $localePath;
|
||||
self::$_i18nData['language'] = $langCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns translation of a specific text, wrapper for translate().
|
||||
*
|
||||
* @param string $string
|
||||
* The string to translate
|
||||
* @param string $domain [optional]
|
||||
* The domain to look up
|
||||
* @return string
|
||||
* Returns the translation
|
||||
*/
|
||||
public static function __($string, $domain = self::i18n_DEFAULT_DOMAIN) {
|
||||
return self::translate($string, $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns translation of a specific text
|
||||
*
|
||||
* @param string $string
|
||||
* The string to translate
|
||||
* @param string $domain [optional]
|
||||
* The domain to look up
|
||||
* @throws cException
|
||||
* if this is the backend mode and the $belang is not set
|
||||
* @return string
|
||||
* Returns the translation
|
||||
*/
|
||||
public static function translate($string, $domain = self::i18n_DEFAULT_DOMAIN) {
|
||||
global $cfg, $belang, $contenido;
|
||||
|
||||
// Auto initialization
|
||||
if (!self::$_i18nData['language']) {
|
||||
if (!isset($belang)) {
|
||||
if ($contenido) {
|
||||
throw new Exception('init $belang is not set');
|
||||
}
|
||||
// Needed - otherwise this won't work
|
||||
$belang = false;
|
||||
}
|
||||
|
||||
// CON-2165
|
||||
// initialise localisation of plugins correctly in frontend
|
||||
if ($domain === self::i18n_DEFAULT_DOMAIN) {
|
||||
self::init($cfg['path']['contenido_locale'], $belang, $domain);
|
||||
} else {
|
||||
if (empty($belang)) {
|
||||
$oApiLang = new cApiLanguage(cRegistry::getLanguageId());
|
||||
$language = $oApiLang->getProperty('language', 'code');
|
||||
$country = $oApiLang->getProperty('country', 'code');
|
||||
|
||||
$locale = $language . '_' . strtoupper($country);
|
||||
self::init($cfg['path']['contenido'] . $cfg['path']['plugins'] . $domain . '/locale/', $locale, $domain);
|
||||
} else {
|
||||
self::init($cfg['path']['contenido'] . $cfg['path']['plugins'] . $domain . '/locale/', $belang, $domain);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Is emulator to use?
|
||||
if (!$cfg['native_i18n']) {
|
||||
$ret = self::emulateGettext($string, $domain);
|
||||
// hopefully a proper replacement for
|
||||
// mb_convert_encoding($string, 'HTML-ENTITIES', 'utf-8');
|
||||
// see http://stackoverflow.com/q/11974008
|
||||
$ret = htmlspecialchars_decode(utf8_decode(conHtmlentities($ret, ENT_COMPAT, 'utf-8', false)));
|
||||
return $ret;
|
||||
}
|
||||
|
||||
// Try to use native gettext implementation
|
||||
if (extension_loaded('gettext')) {
|
||||
if (function_exists('dgettext')) {
|
||||
if ($domain != self::i18n_DEFAULT_DOMAIN) {
|
||||
$translation = dgettext($domain, $string);
|
||||
return $translation;
|
||||
} else {
|
||||
return gettext($string);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Emulator as fallback
|
||||
$ret = self::emulateGettext($string, $domain);
|
||||
if (self::_isUtf8($ret)) {
|
||||
$ret = utf8_decode($ret);
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current language (if already defined)
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public static function getLanguage() {
|
||||
return (self::$_i18nData['language']) ? self::$_i18nData['language'] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of registered domains
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getDomains() {
|
||||
return self::$_i18nData['domains'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of cached tranlation files
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getFiles() {
|
||||
return self::$_i18nData['files'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns list of cached tranlations
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public static function getCache() {
|
||||
return self::$_i18nData['cache'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets cached translation data (language, domains, files, and cache)
|
||||
*/
|
||||
public static function reset() {
|
||||
self::$_i18nData['language'] = NULL;
|
||||
self::$_i18nData['domains'] = array();
|
||||
self::$_i18nData['files'] = array();
|
||||
self::$_i18nData['cache'] = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Emulates GNU gettext
|
||||
*
|
||||
* @param string $string
|
||||
* The string to translate
|
||||
* @param string $domain [optional]
|
||||
* The domain to look up
|
||||
* @return string
|
||||
* Returns the translation
|
||||
*/
|
||||
public static function emulateGettext($string, $domain = self::i18n_DEFAULT_DOMAIN) {
|
||||
if ($string == '') {
|
||||
return '';
|
||||
}
|
||||
|
||||
if (!isset(self::$_i18nData['cache'][$domain])) {
|
||||
self::$_i18nData['cache'][$domain] = array();
|
||||
}
|
||||
if (isset(self::$_i18nData['cache'][$domain][$string])) {
|
||||
return self::$_i18nData['cache'][$domain][$string];
|
||||
}
|
||||
|
||||
$translationFile = self::$_i18nData['domains'][$domain] . self::$_i18nData['language'] . '/LC_MESSAGES/' . $domain . '.po';
|
||||
if (!cFileHandler::exists($translationFile)) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
if (!isset(self::$_i18nData['files'][$domain])) {
|
||||
self::$_i18nData['files'][$domain] = self::_loadTranslationFile($translationFile);
|
||||
}
|
||||
|
||||
$stringStart = strpos(self::$_i18nData['files'][$domain], '"' . str_replace(array(
|
||||
"\n",
|
||||
"\r",
|
||||
"\t"
|
||||
), array(
|
||||
'\n',
|
||||
'\r',
|
||||
'\t'
|
||||
), $string) . '"');
|
||||
if ($stringStart === false) {
|
||||
return $string;
|
||||
}
|
||||
|
||||
$matches = array();
|
||||
$quotedString = preg_quote(str_replace(array(
|
||||
"\n",
|
||||
"\r",
|
||||
"\t"
|
||||
), array(
|
||||
'\n',
|
||||
'\r',
|
||||
'\t'
|
||||
), $string), '/');
|
||||
$result = preg_match("/msgid.*\"(" . $quotedString . ")\"(?:\s*)?\nmsgstr(?:\s*)\"(.*)\"/", self::$_i18nData['files'][$domain], $matches);
|
||||
// Old:
|
||||
// preg_match("/msgid.*\"".preg_quote($string,"/")."\".*\nmsgstr(\s*)\"(.*)\"/",
|
||||
// self::$_i18nData['files'][$domain], $matches);
|
||||
|
||||
if ($result && !empty($matches[2])) {
|
||||
// Translation found, cache it
|
||||
self::$_i18nData['cache'][$domain][$string] = stripslashes(str_replace(array(
|
||||
'\n',
|
||||
'\r',
|
||||
'\t'
|
||||
), array(
|
||||
"\n",
|
||||
"\r",
|
||||
"\t"
|
||||
), $matches[2]));
|
||||
} else {
|
||||
// Translation not found, cache original string
|
||||
self::$_i18nData['cache'][$domain][$string] = $string;
|
||||
}
|
||||
|
||||
return self::$_i18nData['cache'][$domain][$string];
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a new i18n domain.
|
||||
*
|
||||
* @param string $localePath
|
||||
* Path to the locales
|
||||
* @param string $domain
|
||||
* Domain to bind to
|
||||
*/
|
||||
public static function registerDomain($domain, $localePath) {
|
||||
if (function_exists('bindtextdomain')) {
|
||||
// Bind the domain 'contenido' to our locale path
|
||||
bindtextdomain($domain, $localePath);
|
||||
}
|
||||
self::$_i18nData['domains'][$domain] = $localePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads gettext translation and file does some operations like stripping
|
||||
* comments on the content.
|
||||
*
|
||||
* @param string $translationFile
|
||||
* @return string
|
||||
* The preparend translation file content
|
||||
*/
|
||||
protected static function _loadTranslationFile($translationFile) {
|
||||
$content = cFileHandler::read($translationFile);
|
||||
|
||||
// Normalize eol chars
|
||||
$content = str_replace("\n\r", "\n", $content);
|
||||
$content = str_replace("\r\n", "\n", $content);
|
||||
|
||||
// Remove comment lines
|
||||
$content = preg_replace('/^#.+\n/m', '', $content);
|
||||
|
||||
// Prepare for special po edit format
|
||||
/*
|
||||
* Something like: #, php-format msgid "" "Hello %s,\n" "\n" "you've got
|
||||
* a new reminder for the client '%s' at\n" "%s:\n" "\n" "%s" msgstr ""
|
||||
* "Hallo %s,\n" "\n" "du hast eine Wiedervorlage erhalten für den
|
||||
* Mandanten '%s' at\n" "%s:\n" "\n" "%s" has to be converted to: msgid
|
||||
* "Hello %s,\n\nyou've got a new reminder for the client '%s'
|
||||
* at\n%s:\n\n%s" msgstr "Hallo %s,\n\ndu hast eine Wiedervorlage
|
||||
* erhalten für den Mandanten '%s' at\n%s:\n\n%s"
|
||||
*/
|
||||
// assemble broken long message lines (remove double quotes with a line
|
||||
// break in between, e.g. "\n")
|
||||
$content = preg_replace('/(""\\s+")/m', '"', $content);
|
||||
// replace line breaks followed by a whitespace character against a line
|
||||
// break
|
||||
$content = preg_replace('/\\n"\\s+"/m', '\\n', $content);
|
||||
// remove multiple line breaks
|
||||
$content = preg_replace('/("\n+")/m', '', $content);
|
||||
// remove the backslash from double quotes (\"foobar\" -> "foobar")
|
||||
$content = preg_replace('/(\\\")/m', '"', $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
private static function _isUtf8($input) {
|
||||
$len = strlen($input);
|
||||
|
||||
for ($i = 0; $i < $len; $i++) {
|
||||
$char = ord($input[$i]);
|
||||
$n = 0;
|
||||
|
||||
if ($char < 0x80) {
|
||||
// ASCII char
|
||||
continue;
|
||||
} else if (($char & 0xE0) === 0xC0 && $char > 0xC1) {
|
||||
// 2 byte long char
|
||||
$n = 1;
|
||||
} else if (($char & 0xF0) === 0xE0) {
|
||||
// 3 byte long char
|
||||
$n = 2;
|
||||
} else if (($char & 0xF8) === 0xF0 && $char < 0xF5) {
|
||||
// 4 byte long char
|
||||
$n = 3;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ($j = 0; $j < $n; $j++) {
|
||||
$i++;
|
||||
|
||||
if ($i == $len || (ord($input[$i]) & 0xC0) !== 0x80) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
Laden …
In neuem Issue referenzieren