PageRenderTime 50ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/concrete/vendor/gettext/languages/src/CldrData.php

https://gitlab.com/koodersmiikka/operaatio-terveys
PHP | 320 lines | 296 code | 3 blank | 21 comment | 16 complexity | b1cf9ab322af8ff3855d81d9f6fd2c1e MD5 | raw file
  1. <?php
  2. namespace Gettext\Languages;
  3. use Exception;
  4. /**
  5. * Holds the CLDR data.
  6. */
  7. class CldrData
  8. {
  9. /**
  10. * Super-special plural category: this should always be present for any language.
  11. * @var string
  12. */
  13. const OTHER_CATEGORY = 'other';
  14. /**
  15. * The list of the plural categories, sorted from 'zero' to 'other'.
  16. * @var string[]
  17. */
  18. public static $categories = array('zero', 'one', 'two', 'few', 'many', self::OTHER_CATEGORY);
  19. /**
  20. * The loaded CLDR data
  21. * @var array
  22. */
  23. private static $data;
  24. /**
  25. * Returns the loaded CLDR data.
  26. * @param string $key Can be 'languages', 'territories', 'plurals', 'supersededLanguages', 'scripts', 'standAloneScripts'
  27. */
  28. private static function getData($key)
  29. {
  30. if (!isset(self::$data)) {
  31. $fixKeys = function ($list, &$standAlone = null) {
  32. $result = array();
  33. $standAlone = array();
  34. $match = null;
  35. foreach ($list as $key => $value) {
  36. $variant = '';
  37. if (preg_match('/^(.+)-alt-(short|variant|stand-alone)$/', $key, $match)) {
  38. $key = $match[1];
  39. $variant = $match[2];
  40. }
  41. $key = str_replace('-', '_', $key);
  42. switch ($key) {
  43. case 'root': // Language: Root
  44. case 'und': // Language: Unknown Language
  45. case 'zxx': // Language: No linguistic content
  46. case 'ZZ': // Territory: Unknown Region
  47. case 'Zinh': // Script: Inherited
  48. case 'Zmth': // Script: Mathematical Notation
  49. case 'Zsym': // Script: Symbols
  50. case 'Zxxx': // Script: Unwritten
  51. case 'Zyyy': // Script: Common
  52. case 'Zzzz': // Script: Unknown Script
  53. break;
  54. default:
  55. if (
  56. ((strlen($key) !== 4) || ($key < 'Qaaa') || ($key > 'Qabx')) // Script: Reserved for private use
  57. ) {
  58. switch ($variant) {
  59. case 'stand-alone':
  60. $standAlone[$key] = $value;
  61. break;
  62. case '':
  63. $result[$key] = $value;
  64. break;
  65. }
  66. }
  67. break;
  68. }
  69. }
  70. return $result;
  71. };
  72. $data = array();
  73. $json = json_decode(file_get_contents(__DIR__.'/cldr-data/main/en-US/languages.json'), true);
  74. $data['languages'] = $fixKeys($json['main']['en-US']['localeDisplayNames']['languages']);
  75. $json = json_decode(file_get_contents(__DIR__.'/cldr-data/main/en-US/territories.json'), true);
  76. $data['territories'] = $fixKeys($json['main']['en-US']['localeDisplayNames']['territories']);
  77. $json = json_decode(file_get_contents(__DIR__.'/cldr-data/supplemental/plurals.json'), true);
  78. $data['plurals'] = $fixKeys($json['supplemental']['plurals-type-cardinal']);
  79. $json = json_decode(file_get_contents(__DIR__.'/cldr-data/main/en-US/scripts.json'), true);
  80. $data['scripts'] = $fixKeys($json['main']['en-US']['localeDisplayNames']['scripts'], $data['standAloneScripts']);
  81. $data['standAloneScripts'] = array_merge($data['scripts'], $data['standAloneScripts']);
  82. $data['scripts'] = array_merge($data['standAloneScripts'], $data['scripts']);
  83. $data['supersededLanguages'] = array();
  84. // Remove the languages for which we don't have plurals
  85. $m = null;
  86. foreach (array_keys(array_diff_key($data['languages'], $data['plurals'])) as $missingPlural) {
  87. if (preg_match('/^([a-z]{2,3})_/', $missingPlural, $m)) {
  88. if (!isset($data['plurals'][$m[1]])) {
  89. unset($data['languages'][$missingPlural]);
  90. }
  91. } else {
  92. unset($data['languages'][$missingPlural]);
  93. }
  94. }
  95. // Fix the languages for which we have plurals
  96. $formerCodes = array(
  97. 'in' => 'id', // former Indonesian
  98. 'iw' => 'he', // former Hebrew
  99. 'ji' => 'yi', // former Yiddish
  100. 'jw' => 'jv', // former Javanese
  101. 'mo' => 'ro_MD', // former Moldavian
  102. );
  103. $knownMissingLanguages = array(
  104. 'bh' => 'Bihari',
  105. 'guw' => 'Gun',
  106. 'nah' => 'Nahuatl',
  107. 'smi' => 'Sami',
  108. );
  109. foreach (array_keys(array_diff_key($data['plurals'], $data['languages'])) as $missingLanguage) {
  110. if (isset($formerCodes[$missingLanguage]) && isset($data['languages'][$formerCodes[$missingLanguage]])) {
  111. $data['languages'][$missingLanguage] = $data['languages'][$formerCodes[$missingLanguage]];
  112. $data['supersededLanguages'][$missingLanguage] = $formerCodes[$missingLanguage];
  113. } else {
  114. if (isset($knownMissingLanguages[$missingLanguage])) {
  115. $data['languages'][$missingLanguage] = $knownMissingLanguages[$missingLanguage];
  116. } else {
  117. throw new Exception("We have the plural rule for the language '$missingLanguage' but we don't have its language name");
  118. }
  119. }
  120. }
  121. ksort($data['languages'], SORT_STRING);
  122. ksort($data['territories'], SORT_STRING);
  123. ksort($data['plurals'], SORT_STRING);
  124. ksort($data['scripts'], SORT_STRING);
  125. ksort($data['standAloneScripts'], SORT_STRING);
  126. ksort($data['supersededLanguages'], SORT_STRING);
  127. self::$data = $data;
  128. }
  129. if (!@isset(self::$data[$key])) {
  130. throw new Exception("Invalid CLDR data key: '$key'");
  131. }
  132. return self::$data[$key];
  133. }
  134. /**
  135. * Returns a dictionary containing the language names.
  136. * The keys are the language identifiers.
  137. * The values are the language names in US English.
  138. * @return string[]
  139. */
  140. public static function getLanguageNames()
  141. {
  142. return self::getData('languages');
  143. }
  144. /**
  145. * Return a dictionary containing the territory names (in US English).
  146. * The keys are the territory identifiers.
  147. * The values are the territory names in US English.
  148. * @return string[]
  149. */
  150. public static function getTerritoryNames()
  151. {
  152. return self::getData('territories');
  153. }
  154. /**
  155. * Return a dictionary containing the script names (in US English).
  156. * The keys are the script identifiers.
  157. * The values are the script names in US English.
  158. * @param bool $standAlone Set to true to retrieve the stand-alone script names, false otherwise.
  159. * @return string[]
  160. */
  161. public static function getScriptNames($standAlone)
  162. {
  163. return self::getData($standAlone ? 'standAloneScripts' : 'scripts');
  164. }
  165. /**
  166. * @var array
  167. */
  168. private static $plurals;
  169. /**
  170. * A dictionary containing the plural rules.
  171. * The keys are the language identifiers.
  172. * The values are arrays whose keys are the CLDR category names and the values are the CLDR category definition.
  173. * @example The English key-value pair is somethink like this:
  174. * <code><pre>
  175. * "en": {
  176. * "pluralRule-count-one": "i = 1 and v = 0 @integer 1",
  177. * "pluralRule-count-other": " @integer 0, 2~16, 100, 1000, 10000, 100000, 1000000, … @decimal 0.0~1.5, 10.0, 100.0, 1000.0, 10000.0, 100000.0, 1000000.0, …"
  178. * }
  179. * </pre></code>
  180. * @var array
  181. */
  182. public static function getPlurals()
  183. {
  184. return self::getData('plurals');
  185. }
  186. /**
  187. * Return a list of superseded language codes.
  188. * @return array Keys are the former language codes, values are the new language/locale codes.
  189. */
  190. public static function getSupersededLanguages()
  191. {
  192. return self::getData('supersededLanguages');
  193. }
  194. /**
  195. * Retrieve the name of a language, as well as if a language code is deprecated in favor of another language code.
  196. * @param string $id The language identifier.
  197. * @return array|null Returns an array with the keys 'id' (normalized), 'name', 'supersededBy' (optional), 'territory' (optional), 'script' (optional), 'baseLanguage' (optional), 'categories'. If $id is not valid returns null.
  198. */
  199. public static function getLanguageInfo($id)
  200. {
  201. $result = null;
  202. $matches = array();
  203. if (preg_match('/^([a-z]{2,3})(?:[_\-]([a-z]{4}))?(?:[_\-]([a-z]{2}|[0-9]{3}))?(?:$|-)/i', $id, $matches)) {
  204. $languageId = strtolower($matches[1]);
  205. $scriptId = (isset($matches[2]) && ($matches[2] !== '')) ? ucfirst(strtolower($matches[2])) : null;
  206. $territoryId = (isset($matches[3]) && ($matches[3] !== '')) ? strtoupper($matches[3]) : null;
  207. $normalizedId = $languageId;
  208. if (isset($scriptId)) {
  209. $normalizedId .= '_'.$scriptId;
  210. }
  211. if (isset($territoryId)) {
  212. $normalizedId .= '_'.$territoryId;
  213. }
  214. // Structure precedence: see Likely Subtags - http://www.unicode.org/reports/tr35/tr35-31/tr35.html#Likely_Subtags
  215. $variants = array();
  216. $variantsWithScript = array();
  217. $variantsWithTerritory = array();
  218. if (isset($scriptId) && isset($territoryId)) {
  219. $variantsWithTerritory[] = $variantsWithScript[] = $variants[] = "{$languageId}_{$scriptId}_{$territoryId}";
  220. }
  221. if (isset($scriptId)) {
  222. $variantsWithScript[] = $variants[] = "{$languageId}_{$scriptId}";
  223. }
  224. if (isset($territoryId)) {
  225. $variantsWithTerritory[] = $variants[] = "{$languageId}_{$territoryId}";
  226. }
  227. $variants[] = $languageId;
  228. $allGood = true;
  229. $scriptName = null;
  230. $scriptStandAloneName = null;
  231. if (isset($scriptId)) {
  232. $scriptNames = self::getScriptNames(false);
  233. if (isset($scriptNames[$scriptId])) {
  234. $scriptName = $scriptNames[$scriptId];
  235. $scriptStandAloneNames = self::getScriptNames(true);
  236. $scriptStandAloneName = $scriptStandAloneNames[$scriptId];
  237. } else {
  238. $allGood = false;
  239. }
  240. }
  241. $territoryName = null;
  242. if (isset($territoryId)) {
  243. $territoryNames = self::getTerritoryNames();
  244. if (isset($territoryNames[$territoryId])) {
  245. if ($territoryId !== '001') {
  246. $territoryName = $territoryNames[$territoryId];
  247. }
  248. } else {
  249. $allGood = false;
  250. }
  251. }
  252. $languageName = null;
  253. $languageNames = self::getLanguageNames();
  254. foreach ($variants as $variant) {
  255. if (isset($languageNames[$variant])) {
  256. $languageName = $languageNames[$variant];
  257. if (isset($scriptName) && (!in_array($variant, $variantsWithScript))) {
  258. $languageName = $scriptName.' '.$languageName;
  259. }
  260. if (isset($territoryName) && (!in_array($variant, $variantsWithTerritory))) {
  261. $languageName .= ' ('.$territoryNames[$territoryId].')';
  262. }
  263. break;
  264. }
  265. }
  266. if (!isset($languageName)) {
  267. $allGood = false;
  268. }
  269. $baseLanguage = null;
  270. if (isset($scriptId) || isset($territoryId)) {
  271. if (isset($languageNames[$languageId]) && ($languageNames[$languageId] !== $languageName)) {
  272. $baseLanguage = $languageNames[$languageId];
  273. }
  274. }
  275. $plural = null;
  276. $plurals = self::getPlurals();
  277. foreach ($variants as $variant) {
  278. if (isset($plurals[$variant])) {
  279. $plural = $plurals[$variant];
  280. break;
  281. }
  282. }
  283. if (!isset($plural)) {
  284. $allGood = false;
  285. }
  286. $supersededBy = null;
  287. $supersededBys = self::getSupersededLanguages();
  288. foreach ($variants as $variant) {
  289. if (isset($supersededBys[$variant])) {
  290. $supersededBy = $supersededBys[$variant];
  291. break;
  292. }
  293. }
  294. if ($allGood) {
  295. $result = array();
  296. $result['id'] = $normalizedId;
  297. $result['name'] = $languageName;
  298. if (isset($supersededBy)) {
  299. $result['supersededBy'] = $supersededBy;
  300. }
  301. if (isset($scriptStandAloneName)) {
  302. $result['script'] = $scriptStandAloneName;
  303. }
  304. if (isset($territoryName)) {
  305. $result['territory'] = $territoryName;
  306. }
  307. if (isset($baseLanguage)) {
  308. $result['baseLanguage'] = $baseLanguage;
  309. }
  310. $result['categories'] = $plural;
  311. }
  312. }
  313. return $result;
  314. }
  315. }