PHP Intl-функции не работают в некоторых странах - PullRequest
2 голосов
/ 30 января 2020

Пытаясь получить название языка из кода языка, я запускаю

function test($local, $fallback)
{
    $bundle = \ResourceBundle::create($local, 'ICUDATA-lang', $fallback);
    if ($bundle === null) {
        return "$local bundle not found";
    }
    $var = $bundle->get('Languages',$fallback);
    return $var->get('fr',$fallback);
}

$locals = ['en', 'en_US', 'foo', 'en_AU', 'en_NZ'];

foreach ($locals as $local) {
    var_dump(test($local, true));
}
echo PHP_EOL;
foreach ($locals as $local) {
    var_dump(test($local, false));
}
string(6) "French"
string(6) "French"
NULL
NULL
NULL

string(6) "French"
string(22) "en_US bundle not found"
string(20) "foo bundle not found"
NULL
NULL

Возвращает null для Австралии и Новой Зеландии, что указывает на ошибку Intl

Невозможно загрузить элемент ресурса 'fr': U_MISSING_RESOURCE_ERROR "

Третий параметр функций \ResourceBundle::create предназначен для обратного вызова, что означает, что он должен откатиться к своему родительскому языку. Интересно, что родитель en_AU это en_001.

Это ошибка или я что-то пропустил?

Ответы [ 3 ]

0 голосов
/ 24 февраля 2020

Что вы получаете от:

->get('Languages')->get($lang)

Никогда не будет влиять тот факт, что вы загрузили хранилище с или без отступления .

$locals = ['en', 'en_US', 'foo', 'en_AU', 'en_NZ'];

  1. "en", "en_AU и" en_NS "непосредственно определены в хранилище ICU : так что они могут быть загружены все с или без отступление .
  2. "en_US" определено не определено, НО начинается с "en_". Это означает, что оно дает возможность загрузить "en_US", который будет откат на "en". Это также имеет место, если вы используете "en_FooBar". Если вы попытаетесь с 'bas_il_ic', это будет откат на 'bas'.
  3. «foo» не определен вообще И не может отступить, так что это означает, что создание ResourceBundle не будет неудачным с fallback = true, однако, все, что вы можете получить из это NULL с.

Это означает, что аргумент fallback допускает только некое строгое / нестрогое сопоставление локали во время ResourceBundle::create() с пониманием g, что родитель локали xx_YY равен xx. Он не имеет ничего общего с наследованием , вызванным %%Parent{"xxxxxx"} определениями, которое не соответствует принципу родительской локали , определенному выше, а скорее способом совместного использования общих определений между локалями.

Итак, у вас есть правильные результаты и документация:

С запасным значением true:

  • 'en': "французский", потому что локаль "en" существует, а "French" является частью en.txt
  • 'en_US': "French", поскольку языковой стандарт "en_US" не определен, он возвращается к "en ", и" French "является частью en.txt
  • 'foo': NULL, потому что локаль" foo "не существует и не может быть откатом.
  • 'en_AU': NULL, поскольку локаль "en_AU" существует , расширяется "en_001" , но ни один из них не определяет "fr".
  • ' en_NZ ': то же, что и для "en_AU".

С отступлением false:

  • ' en ': "французский", так как локаль "en" существует, и "французский" является частью en.txt * 108 8 *
  • 'en_US': "пакет en_US не найден": очевидно, "en_US" действительно не определен.
  • 'foo': "пакет foo не найден": вид очевиден, " foo "на самом деле не определено.
  • 'en_AU': то же самое объяснение, что и для отката true.
  • 'en_NZ': то же самое объяснение, что и для отката true.

Скорее всего, вы спросите себя: «Почему данные языка ICU локали xx_YY не наследуют данные xx?» и это действительно для всех локалей, не только на основе Engli sh.

PHP согласуется с тем, что предоставляет библиотека ICU, но вы можете подвергнуть сомнению внутренние данные ICU.

0 голосов
/ 08 марта 2020

Оба метода ResourceBundle::create и ResourceBundle::get имеют параметр fallback. Но только первый метод фактически использует этот параметр, а метод get просто игнорирует его. Это не то, что объясняется в документации .

отступление

Должен ли региональный язык точно соответствовать или отступить на родительский язык.

Используя пакет Cosmopolitan , он работает как положено.

<?php
require_once "vendor/autoload.php";

use Salarmehr\Cosmopolitan\Intl;

function test($local)
{
    return Cosmo::create($local)->get('ICUDATA-lang','Languages','fr');
}

$locals = ['en', 'en_US', 'foo', 'en_AU', 'en_NZ'];

foreach ($locals as $local) {
    var_dump(test($local));
}

вывод

string(6) "French"
string(6) "French"
NULL
string(6) "French"
string(6) "French"
0 голосов
/ 20 февраля 2020

Фон

В каталоге данных ICU, который указан в GitHub (обратите внимание, что вы работали в ветке выпуска, а не в основной ветке), нет файлов для en_US ни en_UK присутствует. В основной ветке вы можете найти файл en_GB, который, кажется, является правильным кодом локали, а не Великобританией.

Хотя я не могу сказать, почему нет en_US (чего я совершенно точно ожидал, как и вы), похоже, что во всех ваших тестах, в которых вы получаете «французский», вы фактически не загружаете правильный путь ICU, а потому, что этот путь не может быть найден, путь root загружен .

Вы уже доказали это, попробовав с en_foobar. То же самое работает, если вы пытаетесь загрузить любую другую бессмысленную локаль, которая просто не существует в этом каталоге данных, и то же самое верно и для en_US, и для en_UK (так как они оба не существуют, как объяснено ранее).

В качестве примечания: Я думаю, что вы, возможно, неправильно поняли запасной параметр. Это происходит так, что если язык не может быть загружен, загружается запасной язык, а не то, что любые запрашиваемые вами данные будут напрямую запрашиваться у родителя.

Примеры кода

Чтобы сделать немного более понятно, о чем я говорю, вот несколько примеров.

Загрузка с бессмысленными локалями всегда загружает данные целого каталога , поэтому у вас есть доступ ко всем данным root:

$bundle = \ResourceBundle::create('stackoverflow-is-great', 'ICUDATA-lang', true);
var_dump($bundle->get('Languages')->get('fr')); // string(6) "French"
var_dump($bundle->get('Languages')->get('de')); // string(6) "German"

Загрузка под-языков из en_NZ, которые не существуют:

$bundle = \ResourceBundle::create('en_NZ', 'ICUDATA-lang', true);
var_dump($bundle->get('Languages')->get('fr')); // NULL
var_dump($bundle->get('Languages')->get('de')); // NULL

Загрузка под-языков из en_NZ, которые do существуют :

$bundle = \ResourceBundle::create('en_NZ', 'ICUDATA-lang', true);
var_dump($bundle->get('Languages')->get('mi')); // string(6) "Māori"

Короче говоря, он работает так, как ожидалось, и дает вам данные там, где они есть, и нет данных там, где их нет.

Отладка

Как я это узнал? На основе этого комментария пользователя на странице документов PHP ResourceBundle. Я добавил вывод глубины и имел очень удобную функцию отладки:

function t($rb, $depth = 0) {
    foreach($rb as $k => $v) {
        echo str_repeat('->', $depth);
        if(is_object($v)) {
            print_r($v);
            var_dump($k);
            t($v, ++$depth);
        } else {
            var_dump($k . " " . $v);
        }
    }
}
$rb = new ResourceBundle('en_UK', 'ICUDATA-lang', true);
var_dump($rb->get('Languages')->get('fr'));

t($rb);

Это печатает вывод (очень длинный, поэтому я не добавляю его здесь), который выглядит подозрительно как данные root.

Последнее замечание: en_GB похоже, что здесь также есть с псевдонимом en_001 , но я не уверен в том, какой эффект.

TL; DR: Первые три локали на самом деле не существуют в наборе данных, и, следовательно, root данные загружены, en_NZ и en_AU работают так, как должны.

...