PluginProbe
VikBooking Hotel Booking Engine & PMS / 1.8.6
VikBooking Hotel Booking Engine & PMS v1.8.6
1.8.15 1.8.14 1.8.13 1.8.12 1.8.11 1.8.10 1.8.9 1.8.6 1.8.7 1.8.8 trunk 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.7 1.6.8 1.6.9 1.7.0 1.7.1 1.7.2 1.7.3 All 36 releases
vikbooking / libraries / adapter / language / language.php

language.php in VikBooking Hotel Booking Engine & PMS 1.8.6, at libraries/adapter/language/language.php

567 lines 13.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * @package VikWP - Libraries
4 * @subpackage adapter.language
5 * @author E4J s.r.l.
6 * @copyright Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
7 * @license http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
8 * @link https://vikwp.com
9 */
10
11 // No direct access
12 defined('ABSPATH') or die('No script kiddies please!');
13
14 JLoader::import('adapter.language.handler');
15
16 /**
17 * Languages/translation adapter class.
18 *
19 * @since 10.0
20 */
21 #[\AllowDynamicProperties]
22 class JLanguage
23 {
24 /**
25 * Array of Language objects.
26 *
27 * @var array
28 */
29 protected static $instances = array();
30
31 /**
32 * The current language tag.
33 *
34 * @var string
35 */
36 private $tag = null;
37
38 /**
39 * A list of handlers to switch the lang keys.
40 *
41 * @var array
42 */
43 private $handlers = array();
44
45 /**
46 * Name of the transliterator function for this language.
47 *
48 * @var Callable
49 */
50 private $transliterator = null;
51
52 /**
53 * Class constructor.
54 *
55 * @param string $lang The language to use.
56 *
57 * @uses load()
58 */
59 public function __construct($lang = null)
60 {
61 $this->tag = $lang;
62 }
63
64 /**
65 * Returns a language object.
66 *
67 * @param string $lang The language to use.
68 *
69 * @return self The Language object.
70 */
71 public static function getInstance($lang = null)
72 {
73 if (!isset(static::$instances[$lang]))
74 {
75 static::$instances[$lang] = new static($lang);
76 }
77
78 return static::$instances[$lang];
79 }
80
81 /**
82 * Loads a single language file. This method doesn't update the
83 * current user locale.
84 *
85 * @param string $extension The extension for which a language file should be loaded.
86 * @param string $basePath The basepath to use.
87 * @param string $lang The language to load, default null for the current language.
88 *
89 * @return boolean True if the file has been successfully loaded.
90 *
91 * @uses getLocaleFilter()
92 */
93 public function load($extension, $basePath = '', $lang = null)
94 {
95 // make sure we are not using the Joomla tag standards
96 $lang = is_null($lang) ? null : str_replace('-', '_', $lang);
97
98 // make sure the name of the plugin is correct
99 $extension = preg_replace("/^com_/", '', $extension);
100
101 $this->localeFilter = $lang;
102
103 /**
104 * Action triggered before loading the text domain.
105 *
106 * @param string $extension The plugin text domain to look for.
107 * @param string $basePath The base path containing the languages.
108 * @param mixed $lang An optional language tag to use.
109 *
110 * @return void
111 *
112 * @since 10.1.30
113 */
114 do_action('vik_plugin_before_load_language', $extension, $basePath, $lang);
115
116 /**
117 * In case the base path was not provided, or a default Joomla constant was passed,
118 * we need to try to auto-detect the standard folder where the language files
119 * should be placed.
120 *
121 * @since 10.1.24
122 */
123 if (!$basePath || $basePath == 'JPATH_ADMINISTRATOR' || $basePath == 'JPATH_SITE')
124 {
125 // create constant name to retrieve standard languages folder
126 $const = strtoupper($extension) . '_LANG';
127
128 // try to retrieve language path from constant, if defined
129 $basePath = defined($const) ? constant($const) : '';
130 }
131
132 // check if the lang tag has been specified,
133 // otherwise use the default locale
134 if (!is_null($lang))
135 {
136 // create a filter to override the 'plugin_locale'
137 add_filter('plugin_locale', array($this, 'getLocaleFilter'));
138 }
139
140 // we need to attach an action to 'load_textdomain' to unset the
141 // cache related to the existing language, if any
142 add_action('load_textdomain', array($this, 'refreshDomain'));
143
144 /**
145 * Register 2 hooks to prevent the hack defined by Polylang to support the
146 * lazy loading of the translations. Since our plugin might run before
147 * Polylang, we need to by pass this limitation and always load the translations
148 * without waiting the latter is ready.
149 *
150 * @since 10.1.33
151 */
152 add_filter('load_textdomain_mofile', array($this, 'storeDefaultMofile'), 1, 2);
153 add_filter('load_textdomain_mofile', array($this, 'preventPolylangHack'), 100, 2);
154
155 // init language
156 $loaded = load_plugin_textdomain($extension, false, $basePath);
157
158 /**
159 * Hook used to load plugin translations from different folders.
160 *
161 * @param boolean $loaded True if a language translation has been already loaded.
162 * @param string $extension The plugin text domain to look for.
163 *
164 * @return boolean True if a new translation is loaded.
165 *
166 * @since 10.1.28
167 */
168 $loaded = apply_filters('vik_plugin_load_language', $loaded, $extension);
169
170 // remove the action to avoid affecting other plugins
171 remove_action('load_textdomain', array($this, 'refreshDomain'));
172
173 // remove the filter to avoid affecting other plugins
174 remove_filter('plugin_locale', array($this, 'getLocaleFilter'));
175
176 return $loaded;
177 }
178
179 /**
180 * Returns the lang tag to load for 'locale' filter.
181 *
182 * @return string The locale.
183 */
184 public function getLocaleFilter()
185 {
186 /**
187 * @var $localeFilter is declared in self::load()
188 */
189 return isset($this->localeFilter) ? $this->localeFilter : null;
190 }
191
192 /**
193 * Used to unset the cache related to a language already loaded.
194 *
195 * @param string $domain The language domain to unset.
196 *
197 * @return void
198 */
199 public function refreshDomain()
200 {
201 $args = func_get_args();
202 $domain = array_shift($args);
203
204 if (!$domain)
205 {
206 return;
207 }
208
209 // the global $l10n var contains all the cached languages
210 global $l10n;
211
212 // if the domain is set in the cache, unset it
213 if (isset($l10n[$domain]))
214 {
215 unset($l10n[$domain]);
216 }
217 }
218
219 /**
220 * Every time Gettext tries to fetch the path of a MO file,
221 * we need to internally save the default given path.
222 *
223 * This method should be executed as soon as possible.
224 *
225 * @param string $mofile Path to the MO file.
226 * @param string $domain Unique identifier for retrieving translated strings.
227 *
228 * @return string The updated MO file.
229 *
230 * @since 10.1.33
231 */
232 public function storeDefaultMofile($mofile, $domain)
233 {
234 // always track the default MO file path
235 $this->defaultMoFile = $mofile;
236
237 return $mofile;
238 }
239
240 /**
241 * Polylang always unset the given MO files to load them all together when
242 * this latter already loaded all the resources. In order to prevent this
243 * behavior/hack, we need to reset the empty path with the previously
244 * registered one (@see storeDefaultMofile).
245 *
246 * This method should be executed as late as possible.
247 *
248 * @param string $mofile Path to the MO file.
249 * @param string $domain Unique identifier for retrieving translated strings.
250 *
251 * @return string The updated MO file.
252 *
253 * @since 10.1.33
254 */
255 public function preventPolylangHack($mofile, $domain)
256 {
257 if (!$mofile)
258 {
259 // the path has been probably emptied by Polylang, reset it
260 $mofile = $this->defaultMoFile;
261 }
262
263 return $mofile;
264 }
265
266 /**
267 * Translates a string into the current language.
268 *
269 * @param string $string The string to translate.
270 * @param boolean $jsSafe Make the result javascript safe.
271 * @param boolean $interpretBackSlashes To interpret backslashes (\\=\, \n=carriage return, \t=tabulation)
272 *
273 * @return string The translated string.
274 *
275 * @uses findTranslation()
276 */
277 public function _($string, $jsSafe = false, $interpretBackSlashes = true)
278 {
279 $return = $this->findTranslation($string);
280
281 if (empty($return))
282 {
283 return $string;
284 }
285
286 if ($jsSafe)
287 {
288 // javascript filter
289 $return = addslashes($return);
290 }
291 else if ($interpretBackSlashes)
292 {
293 if (strpos($return, '\\') !== false)
294 {
295 // interpret \n and \t characters
296 $return = str_replace(array('\\\\', '\t', '\n'), array("\\", "\t", "\n"), $return);
297 }
298 }
299
300 return $return;
301 }
302
303 /**
304 * Dispatches the attached handlers to find the specified string.
305 *
306 * @param string $string The string to translate.
307 *
308 * @return string The translated string, otherwise null.
309 */
310 protected function findTranslation($string)
311 {
312 foreach ($this->handlers as $handler)
313 {
314 $result = $handler->translate($string);
315
316 if ($result !== null)
317 {
318 return $result;
319 }
320 }
321
322 return null;
323 }
324
325 /**
326 * Getter for the language tag (as defined in RFC 3066).
327 *
328 * @return string The language tag.
329 */
330 public function getTag()
331 {
332 $tag = $this->tag;
333
334 // if no tag set, return the current one
335 if (is_null($tag))
336 {
337 /**
338 * Take the locale specified by the user.
339 * In case of missing locale, the function
340 * always fallback to the default one.
341 *
342 * @since 10.1.31
343 */
344 $tag = get_user_locale();
345 }
346
347 // replace the underscore with an hyphen
348 return str_replace('_', '-', $tag);
349 }
350
351 /**
352 * Determines is a key exists.
353 *
354 * @param string $string The key to check.
355 *
356 * @return boolean True if the key exists, otherwise false.
357 *
358 * @uses _()
359 */
360 public function hasKey($string)
361 {
362 /**
363 * Fixed return value, which was exactly a negation of
364 * the expected boolean.
365 *
366 * @since 10.1.35
367 */
368 return strcmp($this->_($string), $string) === 0 ? false : true;
369 }
370
371 /**
372 * Attaches an handler to evaluate the key to translate.
373 *
374 * @param mixed $handler Either a file path or an handler (@since 10.1.46 added support to JLanguageHandler).
375 * @param string $domain The plugin domain name.
376 *
377 * @return self This object to support chaining.
378 */
379 public function attachHandler($handler, $domain)
380 {
381 /**
382 * Strip any unexpected characters from domain.
383 *
384 * @since 10.1.29
385 */
386 $domain = preg_replace("/[^a-z0-9_]+/i", '', $domain);
387
388 $sign = serialize([$handler, $domain]);
389
390 if (!isset($this->handlers[$sign]))
391 {
392 /**
393 * Auto-load the class handler only in case a file path is provided.
394 *
395 * @since 10.1.46
396 */
397 if (is_string($handler))
398 {
399 require_once $handler;
400
401 $name = basename($handler);
402 $name = substr($name, 0, strrpos($name, '.'));
403
404 $classname = ucwords($domain) . 'Language' . ucwords($name);
405 $handler = new $classname();
406 }
407
408 if ($handler instanceof JLanguageHandler)
409 {
410 $this->handlers[$sign] = $handler;
411 }
412 }
413
414 return $this;
415 }
416
417 /**
418 * Transliterate function.
419 * This method processes a string and replaces all accented UTF-8 characters by unaccented
420 * ASCII-7 "equivalents".
421 *
422 * @param string $string The string to transliterate.
423 *
424 * @return string The transliteration of the string.
425 */
426 public function transliterate($string)
427 {
428 if ($this->transliterator !== null)
429 {
430 return call_user_func($this->transliterator, $string);
431 }
432
433 JLoader::import('adapter.language.transliterate');
434
435 $string = Transliterate::utf8_latin_to_ascii($string);
436
437 return $string;
438 }
439
440 /**
441 * Getter for transliteration function.
442 *
443 * @return callable The transliterator function.
444 */
445 public function getTransliterator()
446 {
447 return $this->transliterator;
448 }
449
450 /**
451 * Set the transliteration function.
452 *
453 * @param callable $function Function name or the actual function.
454 *
455 * @return callable The previous function.
456 */
457 public function setTransliterator($function)
458 {
459 $previous = $this->transliterator;
460 $this->transliterator = $function;
461
462 return $previous;
463 }
464
465 /**
466 * Get the first day of the week for this language.
467 *
468 * @return integer The first day of the week according to the language
469 *
470 * @since 10.1.28
471 */
472 public function getFirstDay()
473 {
474 // since we have not enough information to know
475 // the first day of the week for this region,
476 // we should rely on the global configuration
477 return get_option('start_of_week', 0);
478 }
479
480 /**
481 * Get the RTL property.
482 *
483 * @return boolean True is it an RTL language.
484 *
485 * @since 10.1.28
486 */
487 public function isRtl()
488 {
489 // checks whether the current locale is RTL
490 return is_rtl();
491 }
492
493 /**
494 * Returns a list of known languages.
495 *
496 * @return array Key/value pair with the language file and related metadata.
497 *
498 * @since 10.1.9
499 */
500 public static function getKnownLanguages()
501 {
502 /**
503 * Get installed languages.
504 *
505 * @since 10.1.55 Get rid of the keys because third-party plugins might attach
506 * custom languages by using non-integer keys.
507 */
508 $list = array_values(get_available_languages());
509
510 // if the default US lang is in the array, remove it
511 if ($index = array_search('en_US', $list))
512 {
513 array_splice($list, $index, 1);
514 }
515
516 // insert en_US default lang at the beginning of the list
517 array_unshift($list, 'en_US');
518
519 // replace all the underscores with an hyphen
520 $list = array_map(function($elem)
521 {
522 return str_replace('_', '-', $elem);
523 }, $list);
524
525 // obtain WP available translations
526 require_once ABSPATH . 'wp-admin/includes/translation-install.php';
527 $translations = wp_get_available_translations();
528
529 $map = array();
530
531 foreach ($list as $lang)
532 {
533 // get the original locale
534 $key = str_replace('-', '_', $lang);
535
536 if (isset($translations[$key]))
537 {
538 $name = $translations[$key]['english_name'];
539 $native = $translations[$key]['native_name'];
540 $locale = implode(', ', $translations[$key]['iso']);
541
542 unset($translations[$key]);
543 }
544 else
545 {
546 $name = $native = $lang;
547 $locale = substr($lang, 0, 2);
548 }
549
550 $map[$lang] = array(
551 'name' => $name,
552 'nativeName' => $native,
553 'tag' => $lang,
554 'locale' => $locale,
555 'rtl' => 0,
556 'firstDay' => 0,
557 );
558 }
559
560 // fix en_US property because its details don't exist
561 $map['en-US']['name'] = 'English (United States)';
562 $map['en-US']['nativeName'] = 'English (United States)';
563
564 return $map;
565 }
566 }
567