PHP中有简单的方法可以从国家代码获取语言代码吗?

17

我正在使用ISO 3166-1-alpha 2代码传递到应用程序以检索本地化的Feed,例如/feeds/us用于美国。我有一个switch语句根据该country_code提供Feed。

是否有一种方法将这个两位数字的代码转换为语言代码,例如en_US?我想知道在PHP中是否有标准/函数/库来完成这项工作,还是我需要构建自己的数组?


2
“CH”应该使用哪种编程语言代码?“IN”呢?“NO”呢? - Ignacio Vazquez-Abrams
看一下这个新列表,答案中提供的列表已经过时了。这个列表包含422-460个条目。http://msdn.microsoft.com/en-us/library/cc233968.aspx - Erx_VB.NExT.Coder
我原本想建议,如果你的目标是使用区域设置来为本地市场格式化货币,那么有一种策略可以通过“黑客”实现: - David Lundquist
如果您的语言环境目标是正确显示货币值,我发现这个简单的“HACK”可以起到一定作用:在您的国家代码前加上“en_”。货币显示将默认为该国家的通用标准。 "; ?> - David Lundquist
5个回答

18

正如其他人所指出的那样,由于许多国家有多种语言,因此没有内置此功能的函数。不幸的是,我无法为您指出可以执行此操作的库,但我已经编写了一个小函数来实现您想要的功能。

有两个注意事项,其一是如果未提供语言,则它将仅选择列表中的第一个语言环境。为了解决这个问题,您需要在函数调用周围放置一些逻辑来提供适当的语言。另一个注意事项是需要安装php5-intl才能使用此函数。

<?php

/**
/* Returns a locale from a country code that is provided.
/*
/* @param $country_code  ISO 3166-2-alpha 2 country code
/* @param $language_code ISO 639-1-alpha 2 language code
/* @returns  a locale, formatted like en_US, or null if not found
/**/
function country_code_to_locale($country_code, $language_code = '')
{
    // Locale list taken from:
    // https://dev59.com/oXA75IYBdhLWcg3wo6le
    // list-of-all-locales-and-their-short-codes
    $locales = array('af-ZA',
                    'am-ET',
                    'ar-AE',
                    'ar-BH',
                    'ar-DZ',
                    'ar-EG',
                    'ar-IQ',
                    'ar-JO',
                    'ar-KW',
                    'ar-LB',
                    'ar-LY',
                    'ar-MA',
                    'arn-CL',
                    'ar-OM',
                    'ar-QA',
                    'ar-SA',
                    'ar-SY',
                    'ar-TN',
                    'ar-YE',
                    'as-IN',
                    'az-Cyrl-AZ',
                    'az-Latn-AZ',
                    'ba-RU',
                    'be-BY',
                    'bg-BG',
                    'bn-BD',
                    'bn-IN',
                    'bo-CN',
                    'br-FR',
                    'bs-Cyrl-BA',
                    'bs-Latn-BA',
                    'ca-ES',
                    'co-FR',
                    'cs-CZ',
                    'cy-GB',
                    'da-DK',
                    'de-AT',
                    'de-CH',
                    'de-DE',
                    'de-LI',
                    'de-LU',
                    'dsb-DE',
                    'dv-MV',
                    'el-GR',
                    'en-029',
                    'en-AU',
                    'en-BZ',
                    'en-CA',
                    'en-GB',
                    'en-IE',
                    'en-IN',
                    'en-JM',
                    'en-MY',
                    'en-NZ',
                    'en-PH',
                    'en-SG',
                    'en-TT',
                    'en-US',
                    'en-ZA',
                    'en-ZW',
                    'es-AR',
                    'es-BO',
                    'es-CL',
                    'es-CO',
                    'es-CR',
                    'es-DO',
                    'es-EC',
                    'es-ES',
                    'es-GT',
                    'es-HN',
                    'es-MX',
                    'es-NI',
                    'es-PA',
                    'es-PE',
                    'es-PR',
                    'es-PY',
                    'es-SV',
                    'es-US',
                    'es-UY',
                    'es-VE',
                    'et-EE',
                    'eu-ES',
                    'fa-IR',
                    'fi-FI',
                    'fil-PH',
                    'fo-FO',
                    'fr-BE',
                    'fr-CA',
                    'fr-CH',
                    'fr-FR',
                    'fr-LU',
                    'fr-MC',
                    'fy-NL',
                    'ga-IE',
                    'gd-GB',
                    'gl-ES',
                    'gsw-FR',
                    'gu-IN',
                    'ha-Latn-NG',
                    'he-IL',
                    'hi-IN',
                    'hr-BA',
                    'hr-HR',
                    'hsb-DE',
                    'hu-HU',
                    'hy-AM',
                    'id-ID',
                    'ig-NG',
                    'ii-CN',
                    'is-IS',
                    'it-CH',
                    'it-IT',
                    'iu-Cans-CA',
                    'iu-Latn-CA',
                    'ja-JP',
                    'ka-GE',
                    'kk-KZ',
                    'kl-GL',
                    'km-KH',
                    'kn-IN',
                    'kok-IN',
                    'ko-KR',
                    'ky-KG',
                    'lb-LU',
                    'lo-LA',
                    'lt-LT',
                    'lv-LV',
                    'mi-NZ',
                    'mk-MK',
                    'ml-IN',
                    'mn-MN',
                    'mn-Mong-CN',
                    'moh-CA',
                    'mr-IN',
                    'ms-BN',
                    'ms-MY',
                    'mt-MT',
                    'nb-NO',
                    'ne-NP',
                    'nl-BE',
                    'nl-NL',
                    'nn-NO',
                    'nso-ZA',
                    'oc-FR',
                    'or-IN',
                    'pa-IN',
                    'pl-PL',
                    'prs-AF',
                    'ps-AF',
                    'pt-BR',
                    'pt-PT',
                    'qut-GT',
                    'quz-BO',
                    'quz-EC',
                    'quz-PE',
                    'rm-CH',
                    'ro-RO',
                    'ru-RU',
                    'rw-RW',
                    'sah-RU',
                    'sa-IN',
                    'se-FI',
                    'se-NO',
                    'se-SE',
                    'si-LK',
                    'sk-SK',
                    'sl-SI',
                    'sma-NO',
                    'sma-SE',
                    'smj-NO',
                    'smj-SE',
                    'smn-FI',
                    'sms-FI',
                    'sq-AL',
                    'sr-Cyrl-BA',
                    'sr-Cyrl-CS',
                    'sr-Cyrl-ME',
                    'sr-Cyrl-RS',
                    'sr-Latn-BA',
                    'sr-Latn-CS',
                    'sr-Latn-ME',
                    'sr-Latn-RS',
                    'sv-FI',
                    'sv-SE',
                    'sw-KE',
                    'syr-SY',
                    'ta-IN',
                    'te-IN',
                    'tg-Cyrl-TJ',
                    'th-TH',
                    'tk-TM',
                    'tn-ZA',
                    'tr-TR',
                    'tt-RU',
                    'tzm-Latn-DZ',
                    'ug-CN',
                    'uk-UA',
                    'ur-PK',
                    'uz-Cyrl-UZ',
                    'uz-Latn-UZ',
                    'vi-VN',
                    'wo-SN',
                    'xh-ZA',
                    'yo-NG',
                    'zh-CN',
                    'zh-HK',
                    'zh-MO',
                    'zh-SG',
                    'zh-TW',
                    'zu-ZA',);

    foreach ($locales as $locale)
    {
        $locale_region = locale_get_region($locale);
        $locale_language = locale_get_primary_language($locale);
        $locale_array = array('language' => $locale_language,
                             'region' => $locale_region);

        if (strtoupper($country_code) == $locale_region &&
            $language_code == '')
        {
            return locale_compose($locale_array);
        }
        elseif (strtoupper($country_code) == $locale_region &&
                strtolower($language_code) == $locale_language)
        {
            return locale_compose($locale_array);
        }
    }

    return null;
}
?>

1
你正在使用的这个列表已经过时了,请查看最新版本,其中包含约422-460个条目。http://msdn.microsoft.com/en-us/library/cc233968.aspx - Erx_VB.NExT.Coder
致命错误:在 PHP shell 代码中调用未定义的函数 locale_get_region()。 - talsibony
@talsibony,您是否已安装intl扩展? - alle
现在我已经安装了apt install php7.2-intl。 - talsibony

8

正如其他答案所指出的,国家和语言之间没有一对一的映射关系。然而,如果您安装了PHP Intl扩展,就可以使用Unicode CLDR likely subtags data来获取特定国家的“默认”或“可能”的语言:

function getLanguage(string $country): string {
    $subtags = \ResourceBundle::create('likelySubtags', 'ICUDATA', false);
    $country = \Locale::canonicalize('und_'.$country);
    $locale = $subtags->get($country) ?: $subtags->get('und');
    return \Locale::getPrimaryLanguage($locale);
}

现在,当您使用国家代码调用getLanguage()函数时,将返回相应的语言代码:
getLanguage('US'); // "en"
getLanguage('GB'); // "en"
getLanguage('DE'); // "de"
getLanguage('CH'); // "de"
getLanguage('IN'); // "hi"
getLanguage('NO'); // "nb"
getLanguage('BR'); // "pt"

这对于三个字母的国家代码也同样有效:
getLanguage('USA'); // "en"
getLanguage('GBR'); // "en"
getLanguage('AUT'); // "de"
getLanguage('FRA'); // "fr"

甚至包括联合国M49代码

getLanguage('003'); // "en"
getLanguage('013'); // "es"
getLanguage('039'); // "it"
getLanguage('155'); // "de"

在 PHP 7.4/Windows 上,您的代码对于所有上述示例都返回“en”(无论输入如何,您方法中的 $locale 始终为 'en_Latn_US')。 - atyachin
@atyachin 请检查以下代码在您的系统上打印出什么:print_r(iterator_to_array(\ResourceBundle::create('likelySubtags', 'ICUDATA', false))); 它应该看起来像这样:https://3v4l.org/lLgMd - ausi
问题在于canonicalize方法返回的格式是_US。可以通过以下代码修复:$locale = $subtags->get("und_".strtoupper($country)) ?: $subtags->get('und'); - atyachin
@atyachin如果\Locale::canonicalize('und_de')在您的系统中返回'en_US',那么我相信设置肯定有问题。您能否测试一下\Locale::canonicalize('und_gb')\Locale::canonicalize('en_GB')的输出是什么? - ausi
如果我从 $country = \Locale::canonicalize($country); 中删除 und_,它似乎可以工作。 - Tim Ramsey
值得一提的是,对于我来说 - 我不得不自己定义$country,使用$locale = $subtags['und_'.$countryCode];,然后这样就可以正常工作了... - Antony

6
您不能自动将国家代码转换为语言代码,因为一些国家使用多种语言。另一方面,操作系统本地化系统可能支持单个语言的多个变体,适用于不同的国家(例如,en_GB vs en_US)。
例如,瑞士(CH)普遍使用德语和法语(根据http://en.wikipedia.org/wiki/Switzerland,分别占人口的64%和20%)。如果您必须为国家代码CH选择单个语言,则这两种语言对某些人来说都是有意义的。请注意,瑞士的一些地区仅使用德语或法语作为官方语言(但不是两者都有,请参见http://en.wikipedia.org/wiki/File:Sprachen_CH_2000_EN.svg以获取详细信息)。
如果您必须为每个国家选择单个语言,则建议您为支持的每个国家手动进行选择。对于一个半吊子的自动实现,您可以浏览可用的本地化,并在下划线后选择具有匹配国家代码的第一个本地化。
还要注意一个推论:语言不能用国旗来代表,因为语言和国家之间并没有一一对应的关系。在两个方向上都可以找到一对多的关系。

Mikko,你明白这个世界和一个高质量的回答。作为一个瑞士人,我想说,在一个多语国家里选择使用本地语言是很常见的。以苹果为例,他们在瑞士会切换 CH_de 和 CH_fr,或者用 Schweiz-German 和 Suisse-Français 来表达。 - endo.anaconda
@endo.anaconda:我猜你是指de_CH和fr_CH。我不知道使用国家名称后跟语言名称作为常见的标签风格。在芬兰,地区设置sv_FI通常被称为“suomenruotsi”,直接翻译为“芬兰的瑞典语”,而不是“芬兰的瑞典语”。 - Mikko Rantalainen

1

1

TheJF的回答很不错,但是我遇到了一些(一般性的)问题:

  • 如果你调用country_code_to_locale("FR"),他的代码将返回br-FR。现在,根据维基百科,布列塔尼语甚至都不是法国的官方语言。虽然fr-FR在列表中,但br-FR排在数组的第一位。这种情况也发生在许多其他国家。

  • 许多其他区域设置列表试图非常完整地考虑所有可能的语言。

  • 在这里划清界限很困难,你肯定希望保留一个国家的多种语言的好例子是:加拿大和瑞士。

我采取了一个简单的方法

  • 对于大多数国家,我只保留了一种语言,而对于一些国家(如BE、CA、CH、ZA),我保留了多种语言。我保留了es-US,但我不确定这一点(维基百科说:官方语言:联邦层面没有官方语言)。

  • 对于我懒得研究或同时使用拉丁字母和西里尔字母的国家,我也保留了多种语言。

  • 我添加了shuffle($locales);,它将随机化数组,以便我们可以获取具有多种语言的国家的随机语言环境。对于我的用例来说,这是有意义的,但你可能想要删除它。

  • 对于我的目的,只有在网络上具有相关普及率的语言才具有兴趣。这个列表并不完整或正确,但很实用。

所以这是我的语言环境列表:

$locales = array('af-ZA',
                'am-ET',
                'ar-AE',
                'ar-BH',
                'ar-DZ',
                'ar-EG',
                'ar-IQ',
                'ar-JO',
                'ar-KW',
                'ar-LB',
                'ar-LY',
                'ar-MA',
                'ar-OM',
                'ar-QA',
                'ar-SA',
                'ar-SY',
                'ar-TN',
                'ar-YE',
                'az-Cyrl-AZ',
                'az-Latn-AZ',
                'be-BY',
                'bg-BG',
                'bn-BD',
                'bs-Cyrl-BA',
                'bs-Latn-BA',
                'cs-CZ',
                'da-DK',
                'de-AT',
                'de-CH',
                'de-DE',
                'de-LI',
                'de-LU',
                'dv-MV',
                'el-GR',
                'en-AU',
                'en-BZ',
                'en-CA',
                'en-GB',
                'en-IE',
                'en-JM',
                'en-MY',
                'en-NZ',
                'en-SG',
                'en-TT',
                'en-US',
                'en-ZA',
                'en-ZW',
                'es-AR',
                'es-BO',
                'es-CL',
                'es-CO',
                'es-CR',
                'es-DO',
                'es-EC',
                'es-ES',
                'es-GT',
                'es-HN',
                'es-MX',
                'es-NI',
                'es-PA',
                'es-PE',
                'es-PR',
                'es-PY',
                'es-SV',
                'es-US',
                'es-UY',
                'es-VE',
                'et-EE',
                'fa-IR',
                'fi-FI',
                'fil-PH',
                'fo-FO',
                'fr-BE',
                'fr-CA',
                'fr-CH',
                'fr-FR',
                'fr-LU',
                'fr-MC',
                'he-IL',
                'hi-IN',
                'hr-BA',
                'hr-HR',
                'hu-HU',
                'hy-AM',
                'id-ID',
                'ig-NG',
                'is-IS',
                'it-CH',
                'it-IT',
                'ja-JP',
                'ka-GE',
                'kk-KZ',
                'kl-GL',
                'km-KH',
                'ko-KR',
                'ky-KG',
                'lb-LU',
                'lo-LA',
                'lt-LT',
                'lv-LV',
                'mi-NZ',
                'mk-MK',
                'mn-MN',
                'ms-BN',
                'ms-MY',
                'mt-MT',
                'nb-NO',
                'ne-NP',
                'nl-BE',
                'nl-NL',
                'pl-PL',
                'prs-AF',
                'ps-AF',
                'pt-BR',
                'pt-PT',
                'ro-RO',
                'ru-RU',
                'rw-RW',
                'sv-SE',
                'si-LK',
                'sk-SK',
                'sl-SI',
                'sq-AL',
                'sr-Cyrl-BA',
                'sr-Cyrl-CS',
                'sr-Cyrl-ME',
                'sr-Cyrl-RS',
                'sr-Latn-BA',
                'sr-Latn-CS',
                'sr-Latn-ME',
                'sr-Latn-RS',
                'sw-KE',
                'tg-Cyrl-TJ',
                'th-TH',
                'tk-TM',
                'tr-TR',
                'uk-UA',
                'ur-PK',
                'uz-Cyrl-UZ',
                'uz-Latn-UZ',
                'vi-VN',
                'wo-SN',
                'yo-NG',
                'zh-CN',
                'zh-HK',
                'zh-MO',
                'zh-SG',
                'zh-TW');

和代码:

function country_code_to_locale($country_code)
{
    $locales = ...

    // randomize the array, such that we get random locales
    // for countries with multiple languages (CA, CH)
    shuffle($locales);

    foreach ($locales as $locale) {
        $locale_region = locale_get_region($locale);

        if (strtoupper($country_code) == $locale_region) {
            return $locale;
        }
    }

    return "en-US";
}

如果你在 PHP 中收到“undefined function locale_get_region()”的错误信息,那是因为你需要启用intl库。为此,你需要打开php.ini文件并取消注释这一行:;extension=intl。如果你在Windows上运行,并且出现了“icuuc57.dll”未找到的情况,你需要确保PHP可执行文件夹中有这个库,并且该文件夹在系统PATH中。祝好运,让Eugen函数工作起来真是一次过山车之旅! - Gustavo Rodríguez

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接