[TASK][!!!] Fix localization handling to support XLIFF
[Packages/TYPO3.CMS.git] / typo3 / sysext / extbase / Classes / Utility / Localization.php
1 <?php
2 /***************************************************************
3 * Copyright notice
4 *
5 * (c) 2009 Sebastian Kurf├╝rst <sebastian@typo3.org>
6 * All rights reserved
7 *
8 * This script is part of the TYPO3 project. The TYPO3 project is
9 * free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * The GNU General Public License can be found at
15 * http://www.gnu.org/copyleft/gpl.html.
16 *
17 * This script is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * This copyright notice MUST APPEAR in all copies of the script!
23 ***************************************************************/
24
25 /**
26 * Localization helper which should be used to fetch localized labels.
27 *
28 * @package Extbase
29 * @subpackage Utility
30 * @version $ID:$
31 * @api
32 */
33 class Tx_Extbase_Utility_Localization {
34
35 /**
36 * @var string
37 */
38 protected static $locallangPath = 'Resources/Private/Language/';
39
40 /**
41 * Local Language content
42 *
43 * @var string
44 **/
45 protected static $LOCAL_LANG = array();
46
47 /**
48 * Local Language content charset for individual labels (overriding)
49 *
50 * @var string
51 **/
52 protected static $LOCAL_LANG_charset = array();
53
54 /**
55 * Key of the language to use
56 *
57 * @var string
58 **/
59 protected static $languageKey = 'default';
60
61 /**
62 * Pointer to alternative fall-back language to use
63 *
64 * @var string
65 **/
66 protected static $alternativeLanguageKey = '';
67
68 /**
69 * Returns the localized label of the LOCAL_LANG key, $key.
70 *
71 * @param string $key The key from the LOCAL_LANG array for which to return the value.
72 * @param string $extensionName The name of the extension
73 * @param array $arguments the arguments of the extension, being passed over to vsprintf
74 * @return string The value from LOCAL_LANG or NULL if no translation was found.
75 * @author Christopher Hlubek <hlubek@networkteam.com>
76 * @author Bastian Waidelich <bastian@typo3.org>
77 * @author Sebastian Kurfuerst <sebastian@typo3.org>
78 * @api
79 * @todo: If vsprintf gets a malformed string, it returns FALSE! Should we throw an exception there?
80 */
81 static public function translate($key, $extensionName, $arguments = NULL) {
82 if (t3lib_div::isFirstPartOfStr($key, 'LLL:')) {
83 $value = self::translateFileReference($key);
84 } else {
85 self::initializeLocalization($extensionName);
86 // The "from" charset of csConv() is only set for strings from TypoScript via _LOCAL_LANG
87 if (isset(self::$LOCAL_LANG[$extensionName][self::$languageKey][$key])) {
88 $value = self::$LOCAL_LANG[$extensionName][self::$languageKey][$key][0]['target'];
89 if (isset(self::$LOCAL_LANG_charset[$extensionName][self::$languageKey][$key])) {
90 $value = self::convertCharset($value, self::$LOCAL_LANG_charset[$extensionName][self::$languageKey][$key]);
91 }
92 } elseif (self::$alternativeLanguageKey !== '' && isset(self::$LOCAL_LANG[$extensionName][self::$alternativeLanguageKey][$key])) {
93 $value = self::$LOCAL_LANG[$extensionName][self::$alternativeLanguageKey][$key][0]['target'];
94 if (isset(self::$LOCAL_LANG_charset[$extensionName][self::$alternativeLanguageKey][$key])) {
95 $value = self::convertCharset($value, self::$LOCAL_LANG_charset[$extensionName][self::$alternativeLanguageKey][$key]);
96 }
97 } elseif (isset(self::$LOCAL_LANG[$extensionName]['default'][$key])) {
98 $value = self::$LOCAL_LANG[$extensionName]['default'][$key][0]['target']; // No charset conversion because default is english and thereby ASCII
99 }
100 }
101 if (is_array($arguments)) {
102 return vsprintf($value, $arguments);
103 } else {
104 return $value;
105 }
106 }
107
108 /**
109 * Returns the localized label of the LOCAL_LANG key, $key.
110 *
111 * @param string $key The language key including the path to a custom locallang file ("LLL:path:key").
112 * @return string The value from LOCAL_LANG or NULL if no translation was found.
113 * @see language::sL()
114 * @see tslib_fe::sL()
115 * @author Bastian Waidelich <bastian@typo3.org>
116 */
117 protected function translateFileReference($key) {
118 if (TYPO3_MODE === 'FE') {
119 return $GLOBALS['TSFE']->sL($key);
120 } elseif (is_object($GLOBALS['LANG'])) {
121 $value = $GLOBALS['LANG']->sL($key);
122 return $value !== '' ? $value : NULL;
123 } else {
124 return $key;
125 }
126 }
127
128 /**
129 * Loads local-language values by looking for a "locallang.php" (or "locallang.xml") file in the plugin resources directory and if found includes it.
130 * Also locallang values set in the TypoScript property "_LOCAL_LANG" are merged onto the values found in the "locallang.php" file.
131 *
132 * @return void
133 * @author Christopher Hlubek <hlubek@networkteam.com>
134 * @author Bastian Waidelich <bastian@typo3.org>
135 */
136 static protected function initializeLocalization($extensionName) {
137 if (isset(self::$LOCAL_LANG[$extensionName])) {
138 return;
139 }
140 $locallangPathAndFilename = 'EXT:' . t3lib_div::camelCaseToLowerCaseUnderscored($extensionName) . '/' . self::$locallangPath . 'locallang.xml';
141
142 self::setLanguageKeys();
143
144 $renderCharset = (TYPO3_MODE === 'FE' ? $GLOBALS['TSFE']->renderCharset : $GLOBALS['LANG']->charSet);
145 self::$LOCAL_LANG[$extensionName] = t3lib_div::readLLfile($locallangPathAndFilename, self::$languageKey, $renderCharset);
146 if (self::$alternativeLanguageKey !== '') {
147 $alternativeLocalLang = t3lib_div::readLLfile($locallangPathAndFilename, self::$alternativeLanguageKey);
148 self::$LOCAL_LANG[$extensionName] = array_merge(self::$LOCAL_LANG[$extensionName], $alternativeLocalLang);
149 }
150 self::loadTypoScriptLabels($extensionName);
151 }
152
153 /**
154 * Sets the currently active language/language_alt keys.
155 * Default values are "default" for language key and "" for language_alt key.
156 *
157 * @return void
158 * @author Christopher Hlubek <hlubek@networkteam.com>
159 * @author Bastian Waidelich <bastian@typo3.org>
160 */
161 protected function setLanguageKeys() {
162 self::$languageKey = 'default';
163 self::$alternativeLanguageKey = '';
164 if (TYPO3_MODE === 'FE') {
165 if (isset($GLOBALS['TSFE']->config['config']['language'])) {
166 self::$languageKey = $GLOBALS['TSFE']->config['config']['language'];
167 if (isset($GLOBALS['TSFE']->config['config']['language_alt'])) {
168 self::$alternativeLanguageKey = $GLOBALS['TSFE']->config['config']['language_alt'];
169 }
170 }
171 } elseif (strlen($GLOBALS['BE_USER']->uc['lang']) > 0) {
172 self::$languageKey = $GLOBALS['BE_USER']->uc['lang'];
173 }
174 }
175
176 /**
177 * Overwrites labels that are set via typoscript.
178 * TS locallang labels have to be configured like:
179 * plugin.tx_myextension._LOCAL_LANG.languageKey.key = value
180 *
181 * @return void
182 * @author Christopher Hlubek <hlubek@networkteam.com>
183 * @author Bastian Waidelich <bastian@typo3.org>
184 */
185 protected function loadTypoScriptLabels($extensionName) {
186 $objectManager = t3lib_div::makeInstance('Tx_Extbase_Object_ObjectManager');
187 $configurationManager = $objectManager->get('Tx_Extbase_Configuration_ConfigurationManagerInterface');
188 $frameworkConfiguration = $configurationManager->getConfiguration(Tx_Extbase_Configuration_ConfigurationManagerInterface::CONFIGURATION_TYPE_FRAMEWORK);
189 if (!is_array($frameworkConfiguration['_LOCAL_LANG'])) {
190 return;
191 }
192 foreach ($frameworkConfiguration['_LOCAL_LANG'] as $languageKey => $labels) {
193 if (!is_array($labels)) {
194 continue;
195 }
196 foreach($labels as $labelKey => $labelValue) {
197 if (is_string($labelValue)) {
198 self::$LOCAL_LANG[$extensionName][$languageKey][$labelKey] = $labelValue;
199 // For labels coming from the TypoScript (database) the charset is assumed to be "forceCharset" and if that is not set, assumed to be that of the individual system languages
200 if (isset($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset']) && strlen($GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset']) > 0) {
201 self::$LOCAL_LANG_charset[$extensionName][$languageKey][$labelKey] = $GLOBALS['TYPO3_CONF_VARS']['BE']['forceCharset'];
202 } elseif (is_object($GLOBALS['LANG'])) {
203 self::$LOCAL_LANG_charset[$extensionName][$languageKey][$labelKey] = $GLOBALS['LANG']->csConvObj->charSetArray[$languageKey];
204 } else {
205 self::$LOCAL_LANG_charset[$extensionName][$languageKey][$labelKey] = $GLOBALS['TSFE']->csConvObj->charSetArray[$languageKey];
206 }
207 } elseif (is_array($labelValue)) {
208 $labelValue = self::flattenTypoScriptLabelArray($labelValue, $labelKey);
209 self::$LOCAL_LANG[$extensionName][$languageKey] = array_merge(self::$LOCAL_LANG[$extensionName][$languageKey], $labelValue);
210 }
211 }
212 }
213 }
214
215 /**
216 * Flatten TypoScript label array; converting a hierarchical array into a flat
217 * array with the keys separated by dots.
218 *
219 * Example Input: array('k1' => array('subkey1' => 'val1'))
220 * Example Output: array('k1.subkey1' => 'val1')
221 *
222 * @param array $labelValues Hierarchical array of labels
223 * @param string $parentKey the name of the parent key in the recursion; is only needed for recursion.
224 * @return array flattened array of labels.
225 */
226 protected function flattenTypoScriptLabelArray(array $labelValues, $parentKey = '') {
227 $result = array();
228 foreach ($labelValues as $key => $labelValue) {
229 if (!empty($parentKey)) {
230 $key = $parentKey . '.' . $key;
231 }
232
233 if (is_array($labelValue)) {
234 $labelValue = self::flattenTypoScriptLabelArray($labelValue, $key);
235 $result = array_merge($result, $labelValue);
236 } else {
237 $result[$key] = $labelValue;
238 }
239 }
240 return $result;
241 }
242
243 /**
244 * Converts a string from the specified character set to the current.
245 * The current charset is defined by the TYPO3 mode.
246 *
247 * @param string $value string to be converted
248 * @param string $charset The source charset
249 * @return string converted string
250 */
251 protected function convertCharset($value, $charset) {
252 if (TYPO3_MODE === 'FE') {
253 return $GLOBALS['TSFE']->csConv($value, $charset);
254 } else {
255 $convertedValue = $GLOBALS['LANG']->csConvObj->conv($value, $GLOBALS['LANG']->csConvObj->parse_charset($charset), $GLOBALS['LANG']->charSet, 1);
256 return $convertedValue !== NULL ? $convertedValue : $value;
257 }
258 }
259 }
260 ?>