@@ -184,7 +184,7 @@ public static function getTranslation(string $phrase) : string {
184184 */
185185 public static function getTranslationWithParameters (string $ phrase , array $ parameters ) : string {
186186 if (is_null (self ::$ translator ) && self ::isUseTranslator ()) {
187- self ::setTranslator (self :: getModule () );
187+ self ::setTranslator ();
188188 }
189189 if (!self ::isUseTranslator ()) return self ::nonTranslator ($ phrase , $ parameters );
190190
@@ -234,24 +234,29 @@ public static function getTranslationPlural(string $phrase, int $count) : string
234234 * @see self::getTranslationWithParameters() Получение перевода фразы с подстановкой параметров.
235235 * @see self::nonTranslator() Возвращение строки без перевода.
236236 */
237- public static function getTranslationPluralWithParameters (string $ phrase , int $ count , array $ parameters ) : string {
238- if (is_null (self ::$ translator ) && self ::isUseTranslator ()) {
239- self ::setTranslator (self ::getModule ());
237+ public static function getTranslationPluralWithParameters (string $ phrase , int $ count , array $ parameters ): string {
238+ // Инициализация переводчика, если он еще не установлен
239+ if (self ::$ translator === null && self ::isUseTranslator ()) {
240+ self ::setTranslator ();
240241 }
241- $ parameters = array_merge ($ parameters , ['%count% ' => $ count , '{{count}} ' => $ count ]);
242242
243+ // Обогащение параметров информацией о числе
244+ $ parameters += ['%count% ' => $ count , '{{count}} ' => $ count ];
245+
246+ // Если переводчик не используется, возвращаем обработанный текст без перевода
243247 if (!self ::isUseTranslator ()) {
244248 return self ::nonTranslator ($ phrase , $ parameters );
245249 }
246250
247- $ phrases = explode ( ' |~| ' , self :: getTranslationWithParameters ( $ phrase , $ parameters ));
248-
249- return $ phrases [( $ count % 10 === 1 && $ count % 100 !== 11 )
250- ? 0
251- : ( $ count % 10 >= 2 &&
252- $ count % 10 <= 4 &&
253- ( $ count % 100 < 10 || $ count % 100 >= 20 ) ? 1 : 2 )] ;
251+ // Определение корректной формы множественного числа
252+ $ variants = explode ( ' |~| ' , self :: getTranslationWithParameters ( $ phrase , $ parameters ));
253+ $ index = match ( true ) {
254+ $ count % 10 === 1 && $ count % 100 !== 11 => 0 ,
255+ $ count % 10 >= 2 && $ count % 10 <= 4 && ( $ count % 100 < 10 || $ count % 100 >= 20 ) => 1 ,
256+ default => 2 ,
257+ } ;
254258
259+ return $ variants [$ index ] ?? $ variants [0 ];
255260 }
256261
257262 /**
@@ -287,85 +292,77 @@ public static function setLocalizationPath(string $localization_path) : void {
287292 /**
288293 * Возвращает массив переводов из XLIFF файла в виде ассоциативного массива,
289294 * где ключами являются исходные строки, а значениями — переведённые строки.
290- *
291295 * Если файл перевода отсутствует или возникает ошибка при его обработке,
292296 * возвращается пустой массив. Реализована поддержка кеширования для ускорения
293297 * получения данных при последующих вызовах.
294298 *
295- * @param string|null $file Путь к XLIFF файлу. Если не указан, путь будет сгенерирован автоматически.
296- *
299+ * @version 173.3.0
300+ * @since 173.3.0
297301 * @return array Ассоциативный массив переводов.
298- *
299302 * @throws JsonException Исключение при ошибке работы с JSON при кэшировании.
300303 * @throws Throwable Исключение при неизвестной ошибке в процессе обработки файла.
301- *
302- * @version 173.3.0
303- * @since 173.3.0
304- *
305- * @see DataManager::normalizePath() Для нормализации пути к XLIFF файлу.
306- * @see LogGenerator::generateLog() Для логирования ошибок и предупреждений.
307- * @see CacheControl::getCache() Для получения данных из кэша.
308- * @see CacheControl::setCache() Для сохранения данных в кэше.
304+ * @see DataManager::normalizePath() Для нормализации пути к XLIFF файлу.
305+ * @see LogGenerator::generateLog() Для логирования ошибок и предупреждений.
306+ * @see CacheControl::getCache() Для получения данных из кэша.
307+ * @see CacheControl::setCache() Для сохранения данных в кэше.
309308 */
310- private static function getTranslationArray (?string $ file = null ) : array {
311- $ file = $ file ?? DataManager::normalizePath (sprintf (
312- "%s/%s/%s.xliff " ,
313- self ::getLocalizationPath (),
314- self ::getLocale (),
315- self ::getModule ()
316- ));
317- if (!file_exists ($ file )) {
318- // Логируем и завершаем выполнение сразу, если файл отсутствует
309+ private static function getTranslationArray (): array {
310+ $ directory = DataManager::normalizePath (self ::getLocalizationPath () . '/ ' . self ::getLocale ());
311+
312+ if (!is_dir ($ directory )) {
319313 LogGenerator::generateLog (
320314 'MhTranslation ' ,
321315 'getTranslationArray ' ,
322- "Файл перевода \"{$ file }\" не был найден ! " ,
316+ "Директория с переводами \"{$ directory }\" не найдена ! " ,
323317 "warn "
324318 );
325319 self ::setUseTranslator (false );
326-
327320 return [];
328321 }
329322
330- // Берем данные из кэша
331323 $ data = CacheControl::getCache ('MhTranslation ' , 'lang_ ' . self ::getLocale ());
332- if ($ data ) {
333- return $ data ; // Если данные есть в кэше, возвращаем их, чтобы пропустить парсинг
334- }
324+ if (!$ data ) {
335325
336- try {
337- // Пытаемся загрузить и обработать файл
338- // Читаем содержимое файла корректировкой в одну строку
339- $ fileContent = str_replace (["\n" , "\r" , "\t" ], '' , file_get_contents ($ file ));
326+ $ data = [];
327+ try {
328+ $ files = DataManager::dirToArray ($ directory );
329+
330+ // Чтение и обработка файлов с использованием array_reduce для избежания array_merge в цикле
331+ $ data = array_reduce (
332+ $ files ,
333+ static fn (array $ carry , string $ fileName ): array => [
334+ ...$ carry , ...self ::parseXliffFile ($ fileName )],
335+ []
336+ );
340337
341- // Используем `SimpleXMLElement` для обработки XML
342- $ xml = new SimpleXMLElement ($ fileContent , LIBXML_NOCDATA );
338+ CacheControl::setCache ('MhTranslation ' , 'lang_ ' . self ::getLocale (), $ data );
339+ } catch (Exception $ e ) {
340+ LogGenerator::generateLog (
341+ 'MhTranslation ' ,
342+ 'getTranslationArray ' ,
343+ "Ошибка чтения и обработки файлов перевода: {$ e ->getMessage ()}" ,
344+ "critical "
345+ );
346+ }
347+ }
348+ return $ data ;
349+ }
350+
351+ private static function parseXliffFile (string $ filePath ): array {
352+ $ data = [];
353+ if (pathinfo ($ filePath , PATHINFO_EXTENSION ) === 'xliff ' ) {
354+ $ fileContent = str_replace (["\n" , "\r" , "\t" ], '' , file_get_contents ($ filePath ));
355+ $ xml = new SimpleXMLElement ($ fileContent , LIBXML_NOCDATA );
343356
344- // Безопасно приводим содержимое XML в массив
345- $ data = [];
346357 if (!empty ($ xml ->file ->body ->{'trans-unit ' })) {
347358 foreach ($ xml ->file ->body ->{'trans-unit ' } as $ unit ) {
348- $ source = (string ) $ unit ->source ;
349- $ target = trim ((string ) $ unit ->target );
350-
351- // Пропускаем пустые строки
352- if ($ source !== '' ) {
359+ $ source = (string )$ unit ->source ;
360+ $ target = trim ((string )$ unit ->target );
361+ if ($ source !== '' && !isset ($ data [$ source ])) {
353362 $ data [$ source ] = $ target ;
354363 }
355364 }
356365 }
357-
358- // Сохраняем в кэш
359- CacheControl::setCache ('MhTranslation ' , 'lang_ ' . self ::getLocale (), $ data );
360- } catch (Exception $ e ) {
361- // Добавляем логирование ошибок для упрощения отладки
362- LogGenerator::generateLog (
363- 'MhTranslation ' ,
364- 'getTranslationArray ' ,
365- "Ошибка чтения и обработки файла перевода: {$ e ->getMessage ()}" ,
366- "critical "
367- );
368- return []; // Возвращаем пустой массив в случае ошибки
369366 }
370367
371368 return $ data ;
@@ -459,32 +456,30 @@ public static function getFormattedLanguageList(string $format = '{original} ({e
459456 * - `iso2` (string): Код ISO 639-1 языка.
460457 * - `tag` (string): Полный тег языка.
461458 *
462- * @global function __ Используется для получения локализованных строк.
463- *
464459 * @see __ Для получения локализованных данных о языке.
465460 */
466461 private static function languageList ($ lang ) : array {
467462 $ langs = [
468463 'ru_RU ' => [
469- 'original ' => __ ('mhadmin ' , ' Русский ' ),
464+ 'original ' => __ ('Русский ' ),
470465 'english ' => 'Russian ' ,
471466 'iso2 ' => 'ru ' ,
472467 'tag ' => 'ru_RU ' ,
473468 ],
474469 'en_US ' => [
475- 'original ' => __ ('mhadmin ' , ' Английский ' ),
470+ 'original ' => __ ('Английский ' ),
476471 'english ' => 'English ' ,
477472 'iso2 ' => 'en ' ,
478473 'tag ' => 'en_US ' ,
479474 ],
480475 'de_DE ' => [
481- 'original ' => __ ('mhadmin ' , ' Немецкий ' ),
476+ 'original ' => __ ('Немецкий ' ),
482477 'english ' => 'German ' ,
483478 'iso2 ' => 'de ' ,
484479 'tag ' => 'de_DE ' ,
485480 ],
486481 'uk_UA ' => [
487- 'original ' => __ ('mhadmin ' , ' Украинский ' ),
482+ 'original ' => __ ('Украинский ' ),
488483 'english ' => 'Ukrainian ' ,
489484 'iso2 ' => 'uk ' ,
490485 'tag ' => 'uk_UA ' ,
@@ -578,11 +573,7 @@ public static function convertXliffToJs(): void {
578573 LogGenerator::generateLog (
579574 'MhTranslation ' ,
580575 'convertXliffToJs ' ,
581- __ (
582- 'mhadmin ' ,
583- "Директория перевода не найдена: :langFilesPath " ,
584- [':langFilesPath ' => $ langFilesPath ]
585- )
576+ __ ("Директория перевода не найдена: :langFilesPath " , [':langFilesPath ' => $ langFilesPath ] )
586577 );
587578 continue ;
588579 }
@@ -614,11 +605,7 @@ public static function convertXliffToJs(): void {
614605 LogGenerator::generateLog (
615606 'MhTranslation ' ,
616607 'convertXliffToJs ' ,
617- __ (
618- 'mhadmin ' ,
619- "Файл перевода успешно преобразован в JS: :outputFile " ,
620- [':outputFile ' => $ outputFile ]
621- ),
608+ __ ("Файл перевода успешно преобразован в JS: :outputFile " , [':outputFile ' => $ outputFile ] ),
622609 'info '
623610 );
624611 }
@@ -663,7 +650,7 @@ private static function writeJsFile(string $path, string $content): bool {
663650 LogGenerator::generateLog (
664651 'MhTranslation ' ,
665652 'writeJsFile ' ,
666- __ (' mhadmin ' , "Ошибка создания JS файла: :path " , [':path ' => $ path ]),
653+ __ ("Ошибка создания JS файла: :path " , [':path ' => $ path ]),
667654 'critical '
668655 );
669656 return false ;
@@ -674,7 +661,7 @@ private static function writeJsFile(string $path, string $content): bool {
674661 'writeJsFile ' ,
675662 [
676663 $ e ->getMessage (),
677- __ (' mhadmin ' , "Ошибка создания JS файла: :path " , [':path ' => $ path ])
664+ __ ("Ошибка создания JS файла: :path " , [':path ' => $ path ])
678665 ],
679666 'critical '
680667 );
@@ -687,7 +674,7 @@ private static function writeJsFile(string $path, string $content): bool {
687674 LogGenerator::generateLog (
688675 'MhTranslation ' ,
689676 'writeJsFile ' ,
690- __ (' mhadmin ' , "Ошибка записи JS файла: :path " , [':path ' => $ path ]),
677+ __ ("Ошибка записи JS файла: :path " , [':path ' => $ path ]),
691678 'critical '
692679 );
693680 return false ;
@@ -698,7 +685,7 @@ private static function writeJsFile(string $path, string $content): bool {
698685 'writeJsFile ' ,
699686 [
700687 $ e ->getMessage (),
701- __ (' mhadmin ' , "Ошибка записи JS файла: :path " , [':path ' => $ path ])
688+ __ ("Ошибка записи JS файла: :path " , [':path ' => $ path ])
702689 ],
703690 'critical '
704691 );
0 commit comments