22declare(strict_types=1);
24namespace pocketmine\lang;
27use Symfony\Component\Filesystem\Path;
28use
function array_filter;
29use
function array_map;
32use
function file_exists;
35use
function parse_ini_file;
37use
function str_ends_with;
38use
function str_replace;
39use
function str_starts_with;
42use
function strtolower;
44use
const INI_SCANNER_RAW;
45use
const SCANDIR_SORT_NONE;
49 public const FALLBACK_LANGUAGE =
"eng";
59 $path = \pocketmine\LOCALE_DATA_PATH;
63 $allFiles = scandir($path, SCANDIR_SORT_NONE);
65 if($allFiles !==
false){
66 $files = array_filter($allFiles,
function(
string $filename) :
bool{
67 return str_ends_with($filename,
".ini");
72 foreach($files as $file){
74 $code = explode(
".", $file)[0];
76 if(isset($strings[KnownTranslationKeys::LANGUAGE_NAME])){
77 $result[$code] = $strings[KnownTranslationKeys::LANGUAGE_NAME];
79 }
catch(LanguageNotFoundException $e){
88 throw new LanguageNotFoundException(
"Language directory $path does not exist or is not a directory");
91 protected string $langName;
96 protected array $lang = [];
101 protected array $fallbackLang = [];
106 public function __construct(
string $lang, ?
string $path =
null,
string $fallback = self::FALLBACK_LANGUAGE){
107 $this->langName = strtolower($lang);
110 $path = \pocketmine\LOCALE_DATA_PATH;
113 $this->lang = self::loadLang($path, $this->langName);
114 $this->fallbackLang = self::loadLang($path, $fallback);
117 public function getName() : string{
121 public function getLang() : string{
122 return $this->langName;
129 protected static function loadLang(
string $path,
string $languageCode) : array{
130 $file = Path::join($path, $languageCode .
".ini");
131 if(file_exists($file)){
132 $strings = array_map(
'stripcslashes', Utils::assumeNotFalse(parse_ini_file($file,
false, INI_SCANNER_RAW),
"Missing or inaccessible required resource files"));
133 if(count($strings) > 0){
144 public function translateString(
string $str, array $params = [], ?
string $onlyPrefix =
null) : string{
145 $baseText = ($onlyPrefix === null || str_starts_with($str, $onlyPrefix)) ? $this->internalGet($str) : null;
146 if($baseText ===
null){
147 $baseText = $this->parseTranslation($str, $onlyPrefix);
150 foreach($params as $i => $p){
151 $replacement = $p instanceof
Translatable ? $this->translate($p) : (string) $p;
152 $baseText = str_replace(
"{%$i}", $replacement, $baseText);
158 public function translate(Translatable $c) : string{
159 $baseText = $this->internalGet($c->getText());
160 if($baseText ===
null){
161 $baseText = $this->parseTranslation($c->getText());
164 foreach($c->getParameters() as $i => $p){
165 $replacement = $p instanceof Translatable ? $this->translate($p) : $p;
166 $baseText = str_replace(
"{%$i}", $replacement, $baseText);
172 protected function internalGet(
string $id) : ?string{
173 return $this->lang[$id] ?? $this->fallbackLang[$id] ?? null;
176 public function get(
string $id) :
string{
177 return $this->internalGet($id) ?? $id;
204 $replaceString =
null;
206 $len = strlen($text);
207 for($i = 0; $i < $len; ++$i){
209 if($replaceString !==
null){
212 ($ord >= 0x30 && $ord <= 0x39)
213 || ($ord >= 0x41 && $ord <= 0x5a)
214 || ($ord >= 0x61 && $ord <= 0x7a) ||
215 $c ===
"." || $c ===
"-"
217 $replaceString .= $c;
219 if(($t = $this->internalGet(substr($replaceString, 1))) !==
null && ($onlyPrefix ===
null || strpos($replaceString, $onlyPrefix) === 1)){
222 $newString .= $replaceString;
224 $replaceString =
null;
239 if($replaceString !==
null){
240 if(($t = $this->internalGet(substr($replaceString, 1))) !==
null && ($onlyPrefix ===
null || strpos($replaceString, $onlyPrefix) === 1)){
243 $newString .= $replaceString;
parseTranslation(string $text, ?string $onlyPrefix=null)
static loadLang(string $path, string $languageCode)
static getLanguageList(string $path="")
__construct(string $lang, ?string $path=null, string $fallback=self::FALLBACK_LANGUAGE)
translateString(string $str, array $params=[], ?string $onlyPrefix=null)