* * @throws LanguageNotFoundException */ public static function getLanguageList(string $path = "") : array{ if($path === ""){ $path = \pocketmine\LOCALE_DATA_PATH; } if(is_dir($path)){ $allFiles = scandir($path, SCANDIR_SORT_NONE); if($allFiles !== false){ $files = array_filter($allFiles, function(string $filename) : bool{ return substr($filename, -4) === ".ini"; }); $result = []; foreach($files as $file){ $code = explode(".", $file)[0]; $strings = self::loadLang($path, $code); if(isset($strings["language.name"])){ $result[$code] = $strings["language.name"]; } } return $result; } } throw new LanguageNotFoundException("Language directory $path does not exist or is not a directory"); } protected string $langName; /** * @var string[] * @phpstan-var array */ protected array $lang = []; /** * @var string[] * @phpstan-var array */ protected array $fallbackLang = []; /** * @throws LanguageNotFoundException */ public function __construct(string $lang, ?string $path = null, string $fallback = self::FALLBACK_LANGUAGE){ $this->langName = strtolower($lang); if($path === null){ $path = \pocketmine\LOCALE_DATA_PATH; } $this->lang = self::loadLang($path, $this->langName); $this->fallbackLang = self::loadLang($path, $fallback); } public function getName() : string{ return $this->get(KnownTranslationKeys::LANGUAGE_NAME); } public function getLang() : string{ return $this->langName; } /** * @return string[] * @phpstan-return array */ protected static function loadLang(string $path, string $languageCode) : array{ $file = Path::join($path, $languageCode . ".ini"); if(file_exists($file)){ return array_map('\stripcslashes', Utils::assumeNotFalse(parse_ini_file($file, false, INI_SCANNER_RAW), "Missing or inaccessible required resource files")); } throw new LanguageNotFoundException("Language \"$languageCode\" not found"); } /** * @param (float|int|string|Translatable)[] $params */ public function translateString(string $str, array $params = [], ?string $onlyPrefix = null) : string{ $baseText = $this->get($str); $baseText = $this->parseTranslation(($onlyPrefix === null || strpos($str, $onlyPrefix) === 0) ? $baseText : $str, $onlyPrefix); foreach($params as $i => $p){ $replacement = $p instanceof Translatable ? $this->translate($p) : (string) $p; $baseText = str_replace("{%$i}", $replacement, $baseText); } return $baseText; } public function translate(Translatable $c) : string{ $baseText = $this->internalGet($c->getText()); $baseText = $this->parseTranslation($baseText ?? $c->getText()); foreach($c->getParameters() as $i => $p){ $replacement = $p instanceof Translatable ? $this->translate($p) : $p; $baseText = str_replace("{%$i}", $replacement, $baseText); } return $baseText; } protected function internalGet(string $id) : ?string{ return $this->lang[$id] ?? $this->fallbackLang[$id] ?? null; } public function get(string $id) : string{ return $this->internalGet($id) ?? $id; } protected function parseTranslation(string $text, ?string $onlyPrefix = null) : string{ $newString = ""; $replaceString = null; $len = strlen($text); for($i = 0; $i < $len; ++$i){ $c = $text[$i]; if($replaceString !== null){ $ord = ord($c); if( ($ord >= 0x30 && $ord <= 0x39) // 0-9 || ($ord >= 0x41 && $ord <= 0x5a) // A-Z || ($ord >= 0x61 && $ord <= 0x7a) || // a-z $c === "." || $c === "-" ){ $replaceString .= $c; }else{ if(($t = $this->internalGet(substr($replaceString, 1))) !== null && ($onlyPrefix === null || strpos($replaceString, $onlyPrefix) === 1)){ $newString .= $t; }else{ $newString .= $replaceString; } $replaceString = null; if($c === "%"){ $replaceString = $c; }else{ $newString .= $c; } } }elseif($c === "%"){ $replaceString = $c; }else{ $newString .= $c; } } if($replaceString !== null){ if(($t = $this->internalGet(substr($replaceString, 1))) !== null && ($onlyPrefix === null || strpos($replaceString, $onlyPrefix) === 1)){ $newString .= $t; }else{ $newString .= $replaceString; } } return $newString; } }