[ Index ] |
PHP Cross Reference of phpBB-3.3.14-deutsch |
[Summary view] [Print] [Text view]
1 <?php 2 /** 3 * 4 * This file is part of the phpBB Forum Software package. 5 * 6 * @copyright (c) phpBB Limited <https://www.phpbb.com> 7 * @license GNU General Public License, version 2 (GPL-2.0) 8 * 9 * For full copyright and license information, please see 10 * the docs/CREDITS.txt file. 11 * 12 */ 13 14 namespace phpbb\language; 15 16 use phpbb\language\exception\invalid_plural_rule_exception; 17 18 /** 19 * Wrapper class for loading translations 20 */ 21 class language 22 { 23 /** 24 * Global fallback language 25 * 26 * ISO code of the language to fallback to when the specified language entries 27 * cannot be found. 28 * 29 * @var string 30 */ 31 const FALLBACK_LANGUAGE = 'en'; 32 33 /** 34 * @var array List of common language files 35 */ 36 protected $common_language_files; 37 38 /** 39 * @var bool 40 */ 41 protected $common_language_files_loaded; 42 43 /** 44 * @var string ISO code of the default board language 45 */ 46 protected $default_language; 47 48 /** 49 * @var string ISO code of the User's language 50 */ 51 protected $user_language; 52 53 /** 54 * @var array Language fallback array (the order is important) 55 */ 56 protected $language_fallback; 57 58 /** 59 * @var array Array of language variables 60 */ 61 protected $lang; 62 63 /** 64 * @var array Loaded language sets 65 */ 66 protected $loaded_language_sets; 67 68 /** 69 * @var \phpbb\language\language_file_loader Language file loader 70 */ 71 protected $loader; 72 73 /** 74 * Constructor 75 * 76 * @param \phpbb\language\language_file_loader $loader Language file loader 77 * @param array|null $common_modules Array of common language modules to load (optional) 78 */ 79 public function __construct(language_file_loader $loader, $common_modules = null) 80 { 81 $this->loader = $loader; 82 83 // Set up default information 84 $this->user_language = false; 85 $this->default_language = false; 86 $this->lang = array(); 87 $this->loaded_language_sets = array( 88 'core' => array(), 89 'ext' => array(), 90 ); 91 92 // Common language files 93 if (is_array($common_modules)) 94 { 95 $this->common_language_files = $common_modules; 96 } 97 else 98 { 99 $this->common_language_files = array( 100 'common', 101 ); 102 } 103 104 $this->common_language_files_loaded = false; 105 106 $this->language_fallback = array(self::FALLBACK_LANGUAGE); 107 } 108 109 /** 110 * Function to set user's language to display. 111 * 112 * @param string $user_lang_iso ISO code of the User's language 113 * @param bool $reload Whether or not to reload language files 114 */ 115 public function set_user_language($user_lang_iso, $reload = false) 116 { 117 $this->user_language = $user_lang_iso; 118 119 $this->set_fallback_array($reload); 120 } 121 122 /** 123 * Function to set the board's default language to display. 124 * 125 * @param string $default_lang_iso ISO code of the board's default language 126 * @param bool $reload Whether or not to reload language files 127 */ 128 public function set_default_language($default_lang_iso, $reload = false) 129 { 130 $this->default_language = $default_lang_iso; 131 132 $this->set_fallback_array($reload); 133 } 134 135 /** 136 * Returns language array 137 * 138 * Note: This function is needed for the BC purposes, until \phpbb\user::lang[] is 139 * not removed. 140 * 141 * @return array Array of loaded language strings 142 */ 143 public function get_lang_array() 144 { 145 // Load common language files if they not loaded yet 146 if (!$this->common_language_files_loaded) 147 { 148 $this->load_common_language_files(); 149 } 150 151 return $this->lang; 152 } 153 154 /** 155 * Add Language Items 156 * 157 * Examples: 158 * <code> 159 * $component = array('posting'); 160 * $component = array('posting', 'viewtopic') 161 * $component = 'posting' 162 * </code> 163 * 164 * @param string|array $component The name of the language component to load 165 * @param string|null $extension_name Name of the extension to load component from, or null for core file 166 */ 167 public function add_lang($component, $extension_name = null) 168 { 169 // Load common language files if they not loaded yet 170 // This needs to be here to correctly merge language arrays 171 if (!$this->common_language_files_loaded) 172 { 173 $this->load_common_language_files(); 174 } 175 176 if (!is_array($component)) 177 { 178 if (!is_null($extension_name)) 179 { 180 $this->load_extension($extension_name, $component); 181 } 182 else 183 { 184 $this->load_core_file($component); 185 } 186 } 187 else 188 { 189 foreach ($component as $lang_file) 190 { 191 $this->add_lang($lang_file, $extension_name); 192 } 193 } 194 } 195 196 /** 197 * @param array|string $key The language key we want to know more about. Can be string or array. 198 * 199 * @return bool Returns whether the language key is set. 200 */ 201 public function is_set($key) 202 { 203 // Load common language files if they not loaded yet 204 if (!$this->common_language_files_loaded) 205 { 206 $this->load_common_language_files(); 207 } 208 209 if (is_array($key)) 210 { 211 $lang = &$this->lang[array_shift($key)]; 212 213 foreach ($key as $_key) 214 { 215 $lang = &$lang[$_key]; 216 } 217 } 218 else 219 { 220 $lang = &$this->lang[$key]; 221 } 222 223 return isset($lang); 224 } 225 226 /** 227 * Advanced language substitution 228 * 229 * Function to mimic sprintf() with the possibility of using phpBB's language system to substitute nullar/singular/plural forms. 230 * Params are the language key and the parameters to be substituted. 231 * This function/functionality is inspired by SHS` and Ashe. 232 * 233 * Example call: <samp>$user->lang('NUM_POSTS_IN_QUEUE', 1);</samp> 234 * 235 * If the first parameter is an array, the elements are used as keys and subkeys to get the language entry: 236 * Example: <samp>$user->lang(array('datetime', 'AGO'), 1)</samp> uses $user->lang['datetime']['AGO'] as language entry. 237 * 238 * @return string Return localized string or the language key if the translation is not available 239 */ 240 public function lang() 241 { 242 $args = func_get_args(); 243 $key = array_shift($args); 244 245 return $this->lang_array($key, $args); 246 } 247 248 /** 249 * Returns the raw value associated to a language key or the language key no translation is available. 250 * No parameter substitution is performed, can be a string or an array. 251 * 252 * @param string|array $key Language key 253 * 254 * @return array|string 255 */ 256 public function lang_raw($key) 257 { 258 // Load common language files if they not loaded yet 259 if (!$this->common_language_files_loaded) 260 { 261 $this->load_common_language_files(); 262 } 263 264 if (is_array($key)) 265 { 266 $lang = &$this->lang[array_shift($key)]; 267 268 foreach ($key as $_key) 269 { 270 $lang = &$lang[$_key]; 271 } 272 } 273 else 274 { 275 $lang = &$this->lang[$key]; 276 } 277 278 // Return if language string does not exist 279 if (!isset($lang) || (!is_string($lang) && !is_array($lang))) 280 { 281 return $key; 282 } 283 284 return $lang; 285 } 286 287 /** 288 * Act like lang() but takes a key and an array of parameters instead of using variadic 289 * 290 * @param string|array $key Language key 291 * @param array $args Parameters 292 * 293 * @return string 294 */ 295 public function lang_array($key, array $args = []) 296 { 297 $lang = $this->lang_raw($key); 298 299 if ($lang === $key) 300 { 301 return $key; 302 } 303 304 // If the language entry is a string, we simply mimic sprintf() behaviour 305 if (is_string($lang)) 306 { 307 if (count($args) === 0) 308 { 309 return $lang; 310 } 311 312 // Replace key with language entry and simply pass along... 313 return vsprintf($lang, $args); 314 } 315 else if (count($lang) == 0) 316 { 317 // If the language entry is an empty array, we just return the language key 318 return $key; 319 } 320 321 // It is an array... now handle different nullar/singular/plural forms 322 $key_found = false; 323 324 // We now get the first number passed and will select the key based upon this number 325 for ($i = 0, $num_args = count($args); $i < $num_args; $i++) 326 { 327 if (is_int($args[$i]) || is_float($args[$i])) 328 { 329 if ($args[$i] == 0 && isset($lang[0])) 330 { 331 // We allow each translation using plural forms to specify a version for the case of 0 things, 332 // so that "0 users" may be displayed as "No users". 333 $key_found = 0; 334 break; 335 } 336 else 337 { 338 $use_plural_form = $this->get_plural_form($args[$i]); 339 if (isset($lang[$use_plural_form])) 340 { 341 // The key we should use exists, so we use it. 342 $key_found = $use_plural_form; 343 } 344 else 345 { 346 // If the key we need to use does not exist, we fall back to the previous one. 347 $numbers = array_keys($lang); 348 349 foreach ($numbers as $num) 350 { 351 if ($num > $use_plural_form) 352 { 353 break; 354 } 355 356 $key_found = $num; 357 } 358 } 359 break; 360 } 361 } 362 } 363 364 // Ok, let's check if the key was found, else use the last entry (because it is mostly the plural form) 365 if ($key_found === false) 366 { 367 $numbers = array_keys($lang); 368 $key_found = end($numbers); 369 } 370 371 // Use the language string we determined and pass it to sprintf() 372 return vsprintf($lang[$key_found], $args); 373 } 374 375 /** 376 * Loads common language files 377 */ 378 protected function load_common_language_files() 379 { 380 if (!$this->common_language_files_loaded) 381 { 382 foreach ($this->common_language_files as $lang_file) 383 { 384 $this->load_core_file($lang_file); 385 } 386 387 $this->common_language_files_loaded = true; 388 } 389 } 390 391 /** 392 * Determine which plural form we should use. 393 * 394 * For some languages this is not as simple as for English. 395 * 396 * @param int|float $number The number we want to get the plural case for. Float numbers are floored. 397 * @param int|bool $force_rule False to use the plural rule of the language package 398 * or an integer to force a certain plural rule 399 * 400 * @return int The plural-case we need to use for the number plural-rule combination 401 * 402 * @throws invalid_plural_rule_exception When $force_rule has an invalid value 403 */ 404 public function get_plural_form($number, $force_rule = false) 405 { 406 $number = (int) $number; 407 $plural_rule = ($force_rule !== false) ? $force_rule : ((isset($this->lang['PLURAL_RULE'])) ? $this->lang['PLURAL_RULE'] : 1); 408 409 if ($plural_rule > 15 || $plural_rule < 0) 410 { 411 throw new invalid_plural_rule_exception('INVALID_PLURAL_RULE', array( 412 'plural_rule' => $plural_rule, 413 )); 414 } 415 416 /** 417 * The following plural rules are based on a list published by the Mozilla Developer Network 418 * https://developer.mozilla.org/en/Localization_and_Plurals 419 */ 420 switch ($plural_rule) 421 { 422 case 0: 423 /** 424 * Families: Asian (Chinese, Japanese, Korean, Vietnamese), Persian, Turkic/Altaic (Turkish), Thai, Lao 425 * 1 - everything: 0, 1, 2, ... 426 */ 427 return 1; 428 429 case 1: 430 /** 431 * Families: Germanic (Danish, Dutch, English, Faroese, Frisian, German, Norwegian, Swedish), Finno-Ugric (Estonian, Finnish, Hungarian), Language isolate (Basque), Latin/Greek (Greek), Semitic (Hebrew), Romanic (Italian, Portuguese, Spanish, Catalan) 432 * 1 - 1 433 * 2 - everything else: 0, 2, 3, ... 434 */ 435 return ($number === 1) ? 1 : 2; 436 437 case 2: 438 /** 439 * Families: Romanic (French, Brazilian Portuguese) 440 * 1 - 0, 1 441 * 2 - everything else: 2, 3, ... 442 */ 443 return (($number === 0) || ($number === 1)) ? 1 : 2; 444 445 case 3: 446 /** 447 * Families: Baltic (Latvian) 448 * 1 - 0 449 * 2 - ends in 1, not 11: 1, 21, ... 101, 121, ... 450 * 3 - everything else: 2, 3, ... 10, 11, 12, ... 20, 22, ... 451 */ 452 return ($number === 0) ? 1 : ((($number % 10 === 1) && ($number % 100 != 11)) ? 2 : 3); 453 454 case 4: 455 /** 456 * Families: Celtic (Scottish Gaelic) 457 * 1 - is 1 or 11: 1, 11 458 * 2 - is 2 or 12: 2, 12 459 * 3 - others between 3 and 19: 3, 4, ... 10, 13, ... 18, 19 460 * 4 - everything else: 0, 20, 21, ... 461 */ 462 return ($number === 1 || $number === 11) ? 1 : (($number === 2 || $number === 12) ? 2 : (($number >= 3 && $number <= 19) ? 3 : 4)); 463 464 case 5: 465 /** 466 * Families: Romanic (Romanian) 467 * 1 - 1 468 * 2 - is 0 or ends in 01-19: 0, 2, 3, ... 19, 101, 102, ... 119, 201, ... 469 * 3 - everything else: 20, 21, ... 470 */ 471 return ($number === 1) ? 1 : ((($number === 0) || (($number % 100 > 0) && ($number % 100 < 20))) ? 2 : 3); 472 473 case 6: 474 /** 475 * Families: Baltic (Lithuanian) 476 * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ... 477 * 2 - ends in 0 or ends in 10-20: 0, 10, 11, 12, ... 19, 20, 30, 40, ... 478 * 3 - everything else: 2, 3, ... 8, 9, 22, 23, ... 29, 32, 33, ... 479 */ 480 return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 < 2) || (($number % 100 >= 10) && ($number % 100 < 20))) ? 2 : 3); 481 482 case 7: 483 /** 484 * Families: Slavic (Croatian, Serbian, Russian, Ukrainian) 485 * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, ... 486 * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ... 487 * 3 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 25, 26, ... 488 */ 489 return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 2 : 3); 490 491 case 8: 492 /** 493 * Families: Slavic (Slovak, Czech) 494 * 1 - 1 495 * 2 - 2, 3, 4 496 * 3 - everything else: 0, 5, 6, 7, ... 497 */ 498 return ($number === 1) ? 1 : ((($number >= 2) && ($number <= 4)) ? 2 : 3); 499 500 case 9: 501 /** 502 * Families: Slavic (Polish) 503 * 1 - 1 504 * 2 - ends in 2-4, not 12-14: 2, 3, 4, 22, 23, 24, 32, ... 104, 122, ... 505 * 3 - everything else: 0, 5, 6, ... 11, 12, 13, 14, 15, ... 20, 21, 25, ... 506 */ 507 return ($number === 1) ? 1 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 2 : 3); 508 509 case 10: 510 /** 511 * Families: Slavic (Slovenian, Sorbian) 512 * 1 - ends in 01: 1, 101, 201, ... 513 * 2 - ends in 02: 2, 102, 202, ... 514 * 3 - ends in 03-04: 3, 4, 103, 104, 203, 204, ... 515 * 4 - everything else: 0, 5, 6, 7, 8, 9, 10, 11, ... 516 */ 517 return ($number % 100 === 1) ? 1 : (($number % 100 === 2) ? 2 : ((($number % 100 === 3) || ($number % 100 === 4)) ? 3 : 4)); 518 519 case 11: 520 /** 521 * Families: Celtic (Irish Gaeilge) 522 * 1 - 1 523 * 2 - 2 524 * 3 - is 3-6: 3, 4, 5, 6 525 * 4 - is 7-10: 7, 8, 9, 10 526 * 5 - everything else: 0, 11, 12, ... 527 */ 528 return ($number === 1) ? 1 : (($number === 2) ? 2 : (($number >= 3 && $number <= 6) ? 3 : (($number >= 7 && $number <= 10) ? 4 : 5))); 529 530 case 12: 531 /** 532 * Families: Semitic (Arabic) 533 * 1 - 1 534 * 2 - 2 535 * 3 - ends in 03-10: 3, 4, ... 10, 103, 104, ... 110, 203, 204, ... 536 * 4 - ends in 11-99: 11, ... 99, 111, 112, ... 537 * 5 - everything else: 100, 101, 102, 200, 201, 202, ... 538 * 6 - 0 539 */ 540 return ($number === 1) ? 1 : (($number === 2) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : (($number != 0) ? 5 : 6)))); 541 542 case 13: 543 /** 544 * Families: Semitic (Maltese) 545 * 1 - 1 546 * 2 - is 0 or ends in 01-10: 0, 2, 3, ... 9, 10, 101, 102, ... 547 * 3 - ends in 11-19: 11, 12, ... 18, 19, 111, 112, ... 548 * 4 - everything else: 20, 21, ... 549 */ 550 return ($number === 1) ? 1 : ((($number === 0) || (($number % 100 > 1) && ($number % 100 < 11))) ? 2 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 3 : 4)); 551 552 case 14: 553 /** 554 * Families: Slavic (Macedonian) 555 * 1 - ends in 1: 1, 11, 21, ... 556 * 2 - ends in 2: 2, 12, 22, ... 557 * 3 - everything else: 0, 3, 4, ... 10, 13, 14, ... 20, 23, ... 558 */ 559 return ($number % 10 === 1) ? 1 : (($number % 10 === 2) ? 2 : 3); 560 561 case 15: 562 /** 563 * Families: Icelandic 564 * 1 - ends in 1, not 11: 1, 21, 31, ... 101, 121, 131, ... 565 * 2 - everything else: 0, 2, 3, ... 10, 11, 12, ... 20, 22, ... 566 */ 567 return (($number % 10 === 1) && ($number % 100 != 11)) ? 1 : 2; 568 } 569 } 570 571 /** 572 * Returns the ISO code of the used language 573 * 574 * @return string The ISO code of the currently used language 575 */ 576 public function get_used_language() 577 { 578 return $this->language_fallback[0]; 579 } 580 581 /** 582 * Returns language fallback data 583 * 584 * @param bool $reload Whether or not to reload language files 585 * 586 * @return array 587 */ 588 protected function set_fallback_array($reload = false) 589 { 590 $fallback_array = array(); 591 592 if ($this->user_language) 593 { 594 $fallback_array[] = $this->user_language; 595 } 596 597 if ($this->default_language) 598 { 599 $fallback_array[] = $this->default_language; 600 } 601 602 $fallback_array[] = self::FALLBACK_LANGUAGE; 603 604 $this->language_fallback = $fallback_array; 605 606 if ($reload) 607 { 608 $this->reload_language_files(); 609 } 610 } 611 612 /** 613 * Load core language file 614 * 615 * @param string $component Name of the component to load 616 */ 617 protected function load_core_file($component) 618 { 619 // Check if the component is already loaded 620 if (isset($this->loaded_language_sets['core'][$component])) 621 { 622 return; 623 } 624 625 $this->loader->load($component, $this->language_fallback, $this->lang); 626 $this->loaded_language_sets['core'][$component] = true; 627 } 628 629 /** 630 * Load extension language file 631 * 632 * @param string $extension_name Name of the extension to load language from 633 * @param string $component Name of the component to load 634 */ 635 protected function load_extension($extension_name, $component) 636 { 637 // Check if the component is already loaded 638 if (isset($this->loaded_language_sets['ext'][$extension_name][$component])) 639 { 640 return; 641 } 642 643 $this->loader->load_extension($extension_name, $component, $this->language_fallback, $this->lang); 644 $this->loaded_language_sets['ext'][$extension_name][$component] = true; 645 } 646 647 /** 648 * Reload language files 649 */ 650 protected function reload_language_files() 651 { 652 $loaded_files = $this->loaded_language_sets; 653 $this->loaded_language_sets = array( 654 'core' => array(), 655 'ext' => array(), 656 ); 657 658 // Reload core files 659 foreach ($loaded_files['core'] as $component => $value) 660 { 661 $this->load_core_file($component); 662 } 663 664 // Reload extension files 665 foreach ($loaded_files['ext'] as $ext_name => $ext_info) 666 { 667 foreach ($ext_info as $ext_component => $value) 668 { 669 $this->load_extension($ext_name, $ext_component); 670 } 671 } 672 } 673 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Mon Nov 25 19:05:08 2024 | Cross-referenced by PHPXref 0.7.1 |