Overview

Packages

  • Core
    • Authentication
    • Backend
    • Cache
    • CEC
    • Chain
    • ContentType
    • Database
    • Datatype
    • Debug
    • Exception
    • Frontend
      • Search
      • URI
      • Util
    • GenericDB
      • Model
    • GUI
      • HTML
    • I18N
    • LayoutHandler
    • Log
    • Security
    • Session
    • Util
    • Validation
    • Versioning
    • XML
  • Module
    • ContentSitemapHtml
    • ContentSitemapXml
    • ContentUserForum
    • NavigationMain
    • NavigationTop
  • mpAutoloaderClassMap
  • None
  • Plugin
    • ContentAllocation
    • CronjobOverview
    • FormAssistant
    • FrontendLogic
    • FrontendUsers
    • Linkchecker
    • ModRewrite
    • Newsletter
    • Repository
      • FrontendNavigation
      • KeywordDensity
    • SearchSolr
    • SmartyWrapper
    • UrlShortener
    • UserForum
    • Workflow
  • PluginManager
  • Setup
    • Form
    • GUI
    • Helper
      • Environment
      • Filesystem
      • MySQL
      • PHP
    • UpgradeJob

Classes

  • cI18n

Functions

  • i18n
  • i18nEmulateGettext
  • i18nGetAvailableLanguages
  • i18nInit
  • i18nMatchBrowserAccept
  • i18nRegisterDomain
  • i18nStripAcceptLanguages
  • mi18n
  • trans
  • Overview
  • Package
  • Class
  • Tree
  • Deprecated
  • Todo
  1: <?php
  2: /**
  3:  * This file contains the the I18N class.
  4:  *
  5:  * @package    Core
  6:  * @subpackage I18N
  7:  * @version    SVN Revision $Rev:$
  8:  *
  9:  * @author     Murat Purc <murat@purc.de>
 10:  * @copyright  four for business AG <www.4fb.de>
 11:  * @license    http://www.contenido.org/license/LIZENZ.txt
 12:  * @link       http://www.4fb.de
 13:  * @link       http://www.contenido.org
 14:  */
 15: 
 16: defined('CON_FRAMEWORK') || die('Illegal call: Missing framework initialization - request aborted.');
 17: 
 18: /**
 19:  * Internationalization (i18n) class.
 20:  *
 21:  * @package    Core
 22:  * @subpackage I18N
 23:  */
 24: class cI18n {
 25: 
 26:     /**
 27:      * i18n related assoziative data cache.
 28:      * @var array
 29:      */
 30:     protected static $_i18nData = array(
 31:         'language' => null,
 32:         'domains' => array(),
 33:         'files' => array(),
 34:         'cache' => array()
 35:     );
 36: 
 37:     /**
 38:      * Initializes the i18n.
 39:      *
 40:      * @param  string  $localePath  Path to the locales
 41:      * @param  string  $langCode  Language code to set
 42:      * @param  string  $domain    Language domain
 43:      */
 44:     public static function init($localePath, $langCode, $domain = 'contenido') {
 45:         if (function_exists('bindtextdomain')) {
 46:             // Bind the domain 'contenido' to our locale path
 47:             bindtextdomain($domain, $localePath);
 48: 
 49:             // Set the default text domain to 'contenido'
 50:             textdomain($domain);
 51: 
 52:             // Half brute-force to set the locale.
 53:             if (!ini_get('safe_mode')) {
 54:                 putenv("LANG=$langCode");
 55:             }
 56: 
 57:             if (defined('LC_MESSAGES')) {
 58:                 setlocale(LC_MESSAGES, $langCode);
 59:             }
 60: 
 61:             setlocale(LC_CTYPE, $langCode);
 62:         }
 63: 
 64:         self::$_i18nData['domains'][$domain] = $localePath;
 65:         self::$_i18nData['language'] = $langCode;
 66:     }
 67: 
 68:     /**
 69:      * Returns translation of a specific text, wrapper for translate().
 70:      *
 71:      * @param  string  $string  The string to translate
 72:      * @param  string  $domain  The domain to look up
 73:      * @return string  Returns the translation
 74:      */
 75:     public static function __($string, $domain = 'contenido') {
 76:         return self::translate($string, $domain);
 77:     }
 78: 
 79:     /**
 80:      * Returns translation of a specific text
 81:      *
 82:      * @param  string  $string  The string to translate
 83:      * @param  string  $domain  The domain to look up
 84:      * @throws cException if this is the backend mode and the $belang is not set
 85:      * @return string  Returns the translation
 86:      */
 87:     public static function translate($string, $domain = 'contenido') {
 88:         global $cfg, $belang, $contenido;
 89: 
 90:         // Auto initialization
 91:         if (!self::$_i18nData['language']) {
 92:             if (!isset($belang)) {
 93:                 if ($contenido) {
 94:                     throw new cException('init $belang is not set');
 95:                 }
 96:                 // Needed - otherwise this won't work
 97:                 $belang = false;
 98:             }
 99: 
100:             self::init($cfg['path']['contenido_locale'], $belang, $domain);
101:         }
102: 
103:         // Is emulator to use?
104:         if (!$cfg['native_i18n']) {
105:             $ret = self::emulateGettext($string, $domain);
106:             // hopefully a proper replacement for
107:             // mb_convert_encoding($string, 'HTML-ENTITIES', 'utf-8');
108:             // see http://stackoverflow.com/q/11974008
109:             $ret = htmlspecialchars_decode(utf8_decode(conHtmlentities($ret, ENT_COMPAT, 'utf-8', false)));
110:             return $ret;
111:         }
112: 
113:         // Try to use native gettext implementation
114:         if (extension_loaded('gettext')) {
115:             if (function_exists('dgettext')) {
116:                 if ($domain != 'contenido') {
117:                     $translation = dgettext($domain, $string);
118:                     return $translation;
119:                 } else {
120:                     return gettext($string);
121:                 }
122:             }
123:         }
124: 
125:         // Emulator as fallback
126:         $ret = self::emulateGettext($string, $domain);
127:         if (isUtf8($ret)) {
128:             $ret = utf8_decode($ret);
129:         }
130:         return $ret;
131:     }
132: 
133:     /**
134:      * Returns the current language (if already defined)
135:      * @return  string|false
136:      */
137:     public static function getLanguage() {
138:         return (self::$_i18nData['language']) ? self::$_i18nData['language'] : false;
139:     }
140: 
141:     /**
142:      * Returns list of registered domains
143:      * @return  array
144:      */
145:     public static function getDomains() {
146:         return self::$_i18nData['domains'];
147:     }
148: 
149:     /**
150:      * Returns list of cached tranlation files
151:      * @return  array
152:      */
153:     public static function getFiles() {
154:         return self::$_i18nData['files'];
155:     }
156: 
157:     /**
158:      * Returns list of cached tranlations
159:      * @return  array
160:      */
161:     public static function getCache() {
162:         return self::$_i18nData['cache'];
163:     }
164: 
165:     /**
166:      * Resets cached translation data (language, domains, files, and cache)
167:      */
168:     public static function reset() {
169:         self::$_i18nData['language'] = null;
170:         self::$_i18nData['domains'] = array();
171:         self::$_i18nData['files'] = array();
172:         self::$_i18nData['cache'] = array();
173:     }
174: 
175:     /**
176:      * Emulates GNU gettext
177:      *
178:      * @param  string  $string  The string to translate
179:      * @param  string  $domain  The domain to look up
180:      * @return string  Returns the translation
181:      */
182:     public static function emulateGettext($string, $domain = 'contenido') {
183:         if ($string == '') {
184:             return '';
185:         }
186: 
187:         if (!isset(self::$_i18nData['cache'][$domain])) {
188:             self::$_i18nData['cache'][$domain] = array();
189:         }
190:         if (isset(self::$_i18nData['cache'][$domain][$string])) {
191:             return self::$_i18nData['cache'][$domain][$string];
192:         }
193: 
194:         $translationFile = self::$_i18nData['domains'][$domain] . self::$_i18nData['language'] . '/LC_MESSAGES/' . $domain . '.po';
195: 
196:         if (!cFileHandler::exists($translationFile)) {
197:             return $string;
198:         }
199: 
200:         if (!isset(self::$_i18nData['files'][$domain])) {
201:             self::$_i18nData['files'][$domain] = self::_loadTranslationFile($translationFile);
202:         }
203: 
204:         $stringStart = strpos(self::$_i18nData['files'][$domain], '"' . str_replace(array("\n", "\r", "\t"), array('\n', '\r', '\t'), $string) . '"');
205:         if ($stringStart === false) {
206:             return $string;
207:         }
208: 
209:         $matches = array();
210:         $quotedString = preg_quote(str_replace(array("\n", "\r", "\t"), array('\n', '\r', '\t'), $string), '/');
211:         $result = preg_match("/msgid.*\"(" . $quotedString . ")\"(?:\s*)?\nmsgstr(?:\s*)\"(.*)\"/", self::$_i18nData['files'][$domain], $matches);
212:         # Old: preg_match("/msgid.*\"".preg_quote($string,"/")."\".*\nmsgstr(\s*)\"(.*)\"/", self::$_i18nData['files'][$domain], $matches);
213: 
214:         if ($result && !empty($matches[2])) {
215:             // Translation found, cache it
216:             self::$_i18nData['cache'][$domain][$string] = stripslashes(str_replace(array('\n', '\r', '\t'), array("\n", "\r", "\t"), $matches[2]));
217:         } else {
218:             // Translation not found, cache original string
219:             self::$_i18nData['cache'][$domain][$string] = $string;
220:         }
221: 
222:         return self::$_i18nData['cache'][$domain][$string];
223:     }
224: 
225:     /**
226:      * Registers a new i18n domain.
227:      *
228:      * @param  string  $localePath  Path to the locales
229:      * @param  string  $domain  Domain to bind to
230:      * @return string  Returns the translation
231:      */
232:     public static function registerDomain($domain, $localePath) {
233:         if (function_exists('bindtextdomain')) {
234:             // Bind the domain 'contenido' to our locale path
235:             bindtextdomain($domain, $localePath);
236:         }
237:         self::$_i18nData['domains'][$domain] = $localePath;
238:     }
239: 
240:     /**
241:      * Loads gettext translation and file does some operations like stripping comments on the content.
242:      * @param   string  $translationFile
243:      * @return  string  The preparend translation file content
244:      */
245:     protected static function _loadTranslationFile($translationFile) {
246:         $content = cFileHandler::read($translationFile);
247: 
248:         // Normalize eol chars
249:         $content = str_replace("\n\r", "\n", $content);
250:         $content = str_replace("\r\n", "\n", $content);
251: 
252:         // Remove comment lines
253:         $content = preg_replace('/^#.+\n/m', '', $content);
254: 
255:         // Prepare for special po edit format
256:         /* Something like:
257:           #, php-format
258:           msgid ""
259:           "Hello %s,\n"
260:           "\n"
261:           "you've got a new reminder for the client '%s' at\n"
262:           "%s:\n"
263:           "\n"
264:           "%s"
265:           msgstr ""
266:           "Hallo %s,\n"
267:           "\n"
268:           "du hast eine Wiedervorlage erhalten für den Mandanten '%s' at\n"
269:           "%s:\n"
270:           "\n"
271:           "%s"
272: 
273:           has to be converted to:
274:           msgid "Hello %s,\n\nyou've got a new reminder for the client '%s' at\n%s:\n\n%s"
275:           msgstr "Hallo %s,\n\ndu hast eine Wiedervorlage erhalten für den Mandanten '%s' at\n%s:\n\n%s"
276:          */
277:         // assemble broken long message lines (remove double quotes with a line break in between, e. g. "\n")
278:         $content = preg_replace('/(""\\s+")/m', '"', $content);
279:         // replace line breaks followed by a whitespace character against a line break
280:         $content = preg_replace('/\\n"\\s+"/m', '\\n', $content);
281:         // remove multiple line breaks
282:         $content = preg_replace('/("\n+")/m', '', $content);
283:         // remove the backslash from double quotes (\"foobar\" -> "foobar")
284:         $content = preg_replace('/(\\\")/m', '"', $content);
285: 
286:         return $content;
287:     }
288: 
289: }
CMS CONTENIDO 4.9.0 API documentation generated by ApiGen 2.8.0