Commit | Line | Data |
---|---|---|
11ade432 | 1 | <?php |
a9229942 | 2 | |
11ade432 | 3 | namespace wcf\system\language; |
a9229942 | 4 | |
a935240b | 5 | use wcf\data\language\category\LanguageCategory; |
11ade432 | 6 | use wcf\data\language\Language; |
e6c6346d | 7 | use wcf\data\language\LanguageEditor; |
b401cd0d | 8 | use wcf\system\cache\builder\LanguageCacheBuilder; |
61022658 | 9 | use wcf\system\SingletonFactory; |
a9229942 | 10 | use wcf\system\template\TemplateScriptingCompiler; |
11ade432 | 11 | use wcf\system\WCF; |
11ade432 AE |
12 | |
13 | /** | |
14 | * Handles language related functions. | |
a9229942 TD |
15 | * |
16 | * @author Alexander Ebert | |
17 | * @copyright 2001-2019 WoltLab GmbH | |
18 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
19 | * @package WoltLabSuite\Core\System\Language | |
11ade432 | 20 | */ |
a9229942 TD |
21 | class LanguageFactory extends SingletonFactory |
22 | { | |
23 | /** | |
24 | * language cache | |
25 | * @var mixed[] | |
26 | */ | |
27 | protected $cache; | |
28 | ||
29 | /** | |
30 | * initialized languages | |
31 | * @var Language[] | |
32 | */ | |
33 | protected $languages = []; | |
34 | ||
35 | /** | |
36 | * active template scripting compiler | |
37 | * @var TemplateScriptingCompiler | |
38 | */ | |
39 | protected $scriptingCompiler; | |
40 | ||
41 | /** | |
42 | * @inheritDoc | |
43 | */ | |
44 | protected function init() | |
45 | { | |
46 | $this->loadCache(); | |
47 | } | |
48 | ||
49 | /** | |
50 | * Returns a Language object for the language with the given id. | |
51 | * | |
52 | * @param int $languageID | |
c0b28aa2 | 53 | * @return Language|null |
a9229942 TD |
54 | */ |
55 | public function getLanguage($languageID) | |
56 | { | |
57 | if (!isset($this->languages[$languageID])) { | |
58 | if (!isset($this->cache['languages'][$languageID])) { | |
c0b28aa2 | 59 | return null; |
a9229942 TD |
60 | } |
61 | ||
62 | $this->languages[$languageID] = $this->cache['languages'][$languageID]; | |
63 | } | |
64 | ||
65 | return $this->languages[$languageID]; | |
66 | } | |
67 | ||
68 | /** | |
69 | * Returns the preferred language of the current user. | |
70 | * | |
71 | * @param int $languageID | |
72 | * @return Language | |
73 | */ | |
74 | public function getUserLanguage($languageID = 0) | |
75 | { | |
76 | if ($languageID) { | |
77 | $language = $this->getLanguage($languageID); | |
78 | if ($language !== null) { | |
79 | return $language; | |
80 | } | |
81 | } | |
82 | ||
83 | $languageID = $this->findPreferredLanguage(); | |
84 | ||
85 | return $this->getLanguage($languageID); | |
86 | } | |
87 | ||
88 | /** | |
89 | * Returns the language with the given language code or null if no such | |
90 | * language exists. | |
91 | * | |
92 | * @param string $languageCode | |
93 | * @return Language | |
94 | */ | |
95 | public function getLanguageByCode($languageCode) | |
96 | { | |
97 | // called within WCFSetup | |
98 | if ($this->cache === false || empty($this->cache['codes'])) { | |
99 | $sql = "SELECT languageID | |
100 | FROM wcf" . WCF_N . "_language | |
101 | WHERE languageCode = ?"; | |
102 | $statement = WCF::getDB()->prepareStatement($sql); | |
103 | $statement->execute([$languageCode]); | |
104 | $row = $statement->fetchArray(); | |
105 | if (isset($row['languageID'])) { | |
106 | return new Language($row['languageID']); | |
107 | } | |
108 | } elseif (isset($this->cache['codes'][$languageCode])) { | |
109 | return $this->getLanguage($this->cache['codes'][$languageCode]); | |
110 | } | |
5227ebc7 MS |
111 | |
112 | return null; | |
a9229942 TD |
113 | } |
114 | ||
115 | /** | |
116 | * Returns true if the language category with the given name exists. | |
117 | * | |
118 | * @param string $categoryName | |
119 | * @return bool | |
120 | */ | |
121 | public function isValidCategory($categoryName) | |
122 | { | |
123 | return isset($this->cache['categories'][$categoryName]); | |
124 | } | |
125 | ||
126 | /** | |
127 | * Returns the language category with the given name. | |
128 | * | |
129 | * @param string $categoryName | |
5227ebc7 | 130 | * @return LanguageCategory|null |
a9229942 TD |
131 | */ |
132 | public function getCategory($categoryName) | |
133 | { | |
813c41ce | 134 | return $this->cache['categories'][$categoryName] ?? null; |
a9229942 TD |
135 | } |
136 | ||
137 | /** | |
138 | * Returns language category by id. | |
139 | * | |
140 | * @param int $languageCategoryID | |
5227ebc7 | 141 | * @return LanguageCategory|null |
a9229942 TD |
142 | */ |
143 | public function getCategoryByID($languageCategoryID) | |
144 | { | |
145 | if (isset($this->cache['categoryIDs'][$languageCategoryID])) { | |
146 | return $this->cache['categories'][$this->cache['categoryIDs'][$languageCategoryID]]; | |
147 | } | |
5227ebc7 MS |
148 | |
149 | return null; | |
a9229942 TD |
150 | } |
151 | ||
152 | /** | |
153 | * Returns a list of available language categories. | |
154 | * | |
155 | * @return LanguageCategory[] | |
156 | */ | |
157 | public function getCategories() | |
158 | { | |
159 | return $this->cache['categories']; | |
160 | } | |
161 | ||
162 | /** | |
163 | * Searches the preferred language of the current user. | |
164 | */ | |
165 | protected function findPreferredLanguage() | |
166 | { | |
167 | // get available language codes | |
168 | $availableLanguageCodes = []; | |
169 | foreach ($this->getLanguages() as $language) { | |
170 | $availableLanguageCodes[] = $language->languageCode; | |
171 | } | |
172 | ||
173 | // get default language | |
174 | $defaultLanguageCode = $this->cache['languages'][$this->cache['default']]->languageCode; | |
175 | ||
176 | // get preferred language | |
177 | $languageCode = self::getPreferredLanguage($availableLanguageCodes, $defaultLanguageCode); | |
178 | ||
179 | // get language id of preferred language | |
180 | foreach ($this->cache['languages'] as $key => $language) { | |
181 | if ($language->languageCode == $languageCode) { | |
182 | return $key; | |
183 | } | |
184 | } | |
185 | } | |
186 | ||
187 | /** | |
188 | * Determines the preferred language of the current user. | |
189 | * | |
190 | * @param array $availableLanguageCodes | |
191 | * @param string $defaultLanguageCode | |
192 | * @return string | |
193 | */ | |
194 | public static function getPreferredLanguage($availableLanguageCodes, $defaultLanguageCode) | |
195 | { | |
196 | if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && $_SERVER['HTTP_ACCEPT_LANGUAGE']) { | |
197 | $acceptedLanguages = \explode(',', \str_replace('_', '-', \strtolower($_SERVER['HTTP_ACCEPT_LANGUAGE']))); | |
198 | foreach ($acceptedLanguages as $acceptedLanguage) { | |
199 | foreach ($availableLanguageCodes as $availableLanguageCode) { | |
200 | $fixedCode = \strtolower(self::fixLanguageCode($availableLanguageCode)); | |
201 | ||
202 | if ( | |
203 | $fixedCode == $acceptedLanguage | |
204 | || $fixedCode == \preg_replace('%^([a-z]{2}).*$%i', '$1', $acceptedLanguage) | |
205 | ) { | |
206 | return $availableLanguageCode; | |
207 | } | |
208 | } | |
209 | } | |
210 | } | |
211 | ||
212 | return $defaultLanguageCode; | |
213 | } | |
214 | ||
215 | /** | |
216 | * Returns the active scripting compiler object. | |
217 | * | |
218 | * @return TemplateScriptingCompiler | |
219 | */ | |
220 | public function getScriptingCompiler() | |
221 | { | |
222 | if ($this->scriptingCompiler === null) { | |
223 | $this->scriptingCompiler = new TemplateScriptingCompiler(WCF::getTPL()); | |
224 | } | |
225 | ||
226 | return $this->scriptingCompiler; | |
227 | } | |
228 | ||
229 | /** | |
230 | * Loads the language cache. | |
231 | */ | |
232 | protected function loadCache() | |
233 | { | |
234 | if (\defined('WCF_N')) { | |
235 | $this->cache = LanguageCacheBuilder::getInstance()->getData(); | |
236 | } | |
237 | } | |
238 | ||
239 | /** | |
240 | * Clears languages cache. | |
241 | */ | |
242 | public function clearCache() | |
243 | { | |
244 | LanguageCacheBuilder::getInstance()->reset(); | |
245 | } | |
246 | ||
247 | /** | |
248 | * Removes additional language identifier from given language code. | |
249 | * Converts e.g. 'de-informal' to 'de'. | |
250 | * | |
251 | * @param string $languageCode | |
252 | * @return string $languageCode | |
253 | */ | |
254 | public static function fixLanguageCode($languageCode) | |
255 | { | |
256 | return \preg_replace('/-[a-z0-9]+/', '', $languageCode); | |
257 | } | |
258 | ||
259 | /** | |
260 | * Returns the default language object. | |
261 | * | |
262 | * @return Language | |
263 | * @since 3.0 | |
264 | */ | |
265 | public function getDefaultLanguage() | |
266 | { | |
267 | return $this->getLanguage($this->cache['default']); | |
268 | } | |
269 | ||
270 | /** | |
271 | * Returns the default language id | |
272 | * | |
273 | * @return int | |
274 | */ | |
275 | public function getDefaultLanguageID() | |
276 | { | |
277 | return $this->cache['default']; | |
278 | } | |
279 | ||
280 | /** | |
281 | * Returns all available languages. | |
282 | * | |
283 | * @return Language[] | |
284 | */ | |
285 | public function getLanguages() | |
286 | { | |
287 | return $this->cache['languages']; | |
288 | } | |
289 | ||
290 | /** | |
291 | * Returns all available content languages for given package. | |
292 | * | |
293 | * @return Language[] | |
294 | */ | |
295 | public function getContentLanguages() | |
296 | { | |
297 | $availableLanguages = []; | |
298 | foreach ($this->getLanguages() as $languageID => $language) { | |
299 | if ($language->hasContent) { | |
300 | $availableLanguages[$languageID] = $language; | |
301 | } | |
302 | } | |
303 | ||
304 | return $availableLanguages; | |
305 | } | |
306 | ||
307 | /** | |
308 | * Returns the list of content language ids. | |
309 | * | |
310 | * @return int[] | |
311 | * @since 3.1 | |
312 | */ | |
313 | public function getContentLanguageIDs() | |
314 | { | |
315 | $languageIDs = []; | |
316 | foreach ($this->getLanguages() as $language) { | |
317 | if ($language->hasContent) { | |
318 | $languageIDs[] = $language->languageID; | |
319 | } | |
320 | } | |
321 | ||
322 | return $languageIDs; | |
323 | } | |
324 | ||
325 | /** | |
326 | * Makes given language the default language. | |
327 | * | |
328 | * @param int $languageID | |
329 | */ | |
330 | public function makeDefault($languageID) | |
331 | { | |
332 | // remove old default language | |
333 | $sql = "UPDATE wcf" . WCF_N . "_language | |
334 | SET isDefault = 0 | |
335 | WHERE isDefault = 1"; | |
336 | $statement = WCF::getDB()->prepareStatement($sql); | |
337 | $statement->execute(); | |
338 | ||
339 | // make this language to default | |
340 | $sql = "UPDATE wcf" . WCF_N . "_language | |
341 | SET isDefault = 1 | |
342 | WHERE languageID = ?"; | |
343 | $statement = WCF::getDB()->prepareStatement($sql); | |
344 | $statement->execute([$languageID]); | |
345 | ||
346 | // rebuild language cache | |
347 | $this->clearCache(); | |
348 | } | |
349 | ||
350 | /** | |
351 | * Removes language cache and compiled templates. | |
352 | */ | |
353 | public function deleteLanguageCache() | |
354 | { | |
355 | LanguageEditor::deleteLanguageFiles(); | |
356 | ||
357 | foreach ($this->cache['languages'] as $language) { | |
358 | $languageEditor = new LanguageEditor($language); | |
359 | $languageEditor->deleteCompiledTemplates(); | |
360 | } | |
361 | } | |
362 | ||
363 | /** | |
364 | * Returns true if multilingualism is enabled. | |
365 | * | |
366 | * @return bool | |
367 | */ | |
368 | public function multilingualismEnabled() | |
369 | { | |
370 | return $this->cache['multilingualismEnabled']; | |
371 | } | |
372 | ||
373 | /** | |
374 | * Returns the number of phrases that have been automatically disabled in the past 7 days. | |
375 | * | |
376 | * @return int | |
377 | */ | |
378 | public function countRecentlyDisabledCustomValues() | |
379 | { | |
380 | $sql = "SELECT COUNT(*) AS count | |
381 | FROM wcf" . WCF_N . "_language_item | |
382 | WHERE languageCustomItemDisableTime >= ?"; | |
383 | $statement = WCF::getDB()->prepareStatement($sql, 1); | |
384 | $statement->execute([TIME_NOW - 86400 * 7]); | |
385 | ||
386 | return $statement->fetchSingleColumn(); | |
387 | } | |
11ade432 | 388 | } |