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