PHP Intl函数在某些国家/地区不起作用

问题描述 投票:2回答:2

我试图从语言代码中获取语言名称,我运行

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

$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,表明国际错误为

无法加载资源元素'fr':U_MISSING_RESOURCE_ERROR“

\ResourceBundle::create函数的第三个参数用于回调,这意味着它应该回退到其父语言环境。有趣的是parent locale of en_AUen_AU

是错误还是我错过了一些东西?

php localization icu intl
2个回答
0
投票

背景

en_001的ICU数据目录中(请注意,您位于发布分支而非主分支上),既没有you listed on GitHub的文件,也没有en_US的文件。在master分支上,您可以找到一个en_UK文件,该文件似乎是正确的语言环境代码,而不是UK。

尽管我不能说为什么en_GB不存在(就像您所做的那样,这是我绝对希望的),但看来,在所有测试中,结果都是“法语”加载正确的ICU路径,但是因为找不到该路径,所以已加载根路径。

您已经通过尝试en_US证明了这一点。如果您尝试加载该数据目录中不存在的其他任何废话语言环境,则同样有效,en_foobaren_US都一样(因为它们都不存在,如前所述)。

作为旁注:我认为您可能误解了fallback参数。这样一来,如果无法加载该语言,则将加载后备语言-而不是直接在父级上请求您请求的任何数据。

代码示例

为了更清楚我在说什么,这里有一些例子。

使用无意义的语言环境进行加载始终会加载整个目录数据,因此您可以访问所有根数据:

en_UK

从en_NZ加载存在[[不存在的子语言:

$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加载存在[[do
的子语言:

$bundle = \ResourceBundle::create('en_NZ', 'ICUDATA-lang', true); var_dump($bundle->get('Languages')->get('fr')); // NULL var_dump($bundle->get('Languages')->get('de')); // NULL 概括地说:它实际上按预期工作,并在可用的地方提供数据,而在没有可用的地方则没有数据。

调试

我是怎么发现的?基于PHP ResourceBundle文档页面上的$bundle = \ResourceBundle::create('en_NZ', 'ICUDATA-lang', true); var_dump($bundle->get('Languages')->get('mi')); // string(6) "Māori" 。我添加了深度输出并具有非常方便的调试功能:

this user comment

这会打印出一个(实际上很长,这就是为什么我不在这里添加它的)输出,它看起来像根数据。

最后一点: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);
似乎也是en_GB,但我不确定效果如何。

TL; DR:数据集中没有真正存在的前三个语言环境,因此加载了根数据,aliased to en_001 hereen_NZ像它们应该的那样工作。


0
投票
en_AU

将永远不会受到加载有或没有

fallback的存储库的影响。

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

“ en”,“ en_AU和” en_NS“直接是$locals = ['en', 'en_US', 'foo', 'en_AU', 'en_NZ'];:因此可以全部加载它们[[有或没有

    后备
  • “ en_US”是not定义的,BUT以“ en_”开头。这意味着它提供了加载“ en_US”的机会,这将回退到“ en”。如果使用“ en_FooBar”,情况也是如此。如果尝试使用defined in the repository of ICU,它将在'bas_il_ic'后退。
  • “ foo”是完全定义的[[not AND不能回退,这意味着'bas'的创建不会因ResourceBundle而失败,但是,您可以从中得到的全部是fallback = true s。
  • 这意味着NULL参数只允许在fallback时对
  • locale
  • 进行某种严格/非严格的匹配,但要了解到语言环境ResourceBundle::create()parent是xx_YY。它与xx定义引起的inheritance无关,它不遵循上面定义的

    parent locale的原理,而是一种跨语言环境共享通用定义的方法。

    因此,您得到的结果和文档都正确:后备为%%Parent{"xxxxxx"}'en':“法语”,因为存在语言环境“ en”,并且“法语”是true的一部分>

    'en_US':“法语”,因为未定义语言环境“ en_US”,因此它落在“ en”上,并且“法语”是en.txt的一部分>

    ''foo':en.txt,因为语言环境“ foo”不存在,也不能回退。

      'en_AU':NULL,因为语言环境NULL扩展了"en_AU" exists,但是它们都没有定义“ fr”。
    • 'en_NZ':与“ en_AU”相同。
    • 后备为"en_001"
    • 'en':“法语”,因为存在语言环境“ en”,并且“法语”是false的一部分>
    • 'en_US':“未找到en_US捆绑包”:显而易见,确实没有定义“ en_US”。

    ''foo':“找不到foo束”:显然,“ foo”的确未定义。

      'en_AU':与回退为en.txt的解释相同。
    • 'en_NZ':与回退为true时的解释相同。
    • 您可能会问自己:“为什么语言环境true的ICU语言数据不继承xx_YY之一?”这对所有语言环境均有效,不仅适用于基于英语的语言环境。
    • PHP与ICU库提供的一致,但是您可能会质疑ICU的内部数据。
    © www.soinside.com 2019 - 2024. All rights reserved.