PHP 找到 setlocale 设置的字符集
PHP find the charset set by setlocale
我所有的网站都使用 UTF-8 作为字符集。但是在设置 setlocale
并从 strftime
获取月份名称和工作日名称的本地化字符串时存在一些问题。
- 问题:本地化月份名称在服务器上不起作用。
- 问题:如何知道语言环境字符串是 UTF-8 还是 ISO?
具体:我这样设置语言环境:
$locales = ['de_DE.utf-8/utf-8', 'de_DE@euro/utf-8', 'de_DE', 'de-DE', 'german', 'de', 'ge'];
$locale = setlocale(LC_ALL, $locales);
在我的开发系统 (Windows 10, XAMPP) 上它找到并设置 $locale = 'de-DE'.
在我的服务器(Linux、Apache)上,它找到并设置 $locale = 'de_DE'.
因为 DateTime class 中内置的 PHP 不支持本地化名称,我创建了一个 class 来扩展 DateTime class:
class DateTimeExt extends DateTime {
private function isUTF8() : bool {
$locale = setlocale(LC_ALL, null);
if (!$locale) return false;
$locale = strtoupper($locale);
return strpos($locale, 'UTF8') !== false || strpos($locale, 'UTF-8') !== false;
}
public function weekdayName() : string {
$weekday = strftime('%A', $this->getTimestamp());
if (!$weekday) return 'unknown';
return $this->isUTF8() ? $weekday : utf8_encode($weekday);
}
public function monthName() : string {
$month = strftime('%B', $this->getTimestamp());
if (!$month) return 'unknown';
return $this->isUTF8() ? $month : utf8_encode($month);
}
}
测试:
$date = new DateTimeExt('2021-03-02');
echo $date->weekdayName().'<br />';
echo $date->monthName().'<br />';
开发环境的结果:
// Dienstag
// März
两者都是正确的。如果没有 UTF-8 编码,它将返回:
// Dienstag
// M�rz
但在服务器上结果为:
// Dienstag
// March
卧槽???服务器可以本地化工作日,但不能本地化月份,并且默认为英语?为什么?这是第 1 期。
问题二是检测设置的locale是否支持UTF-8。我的函数 isUTF8
只是获取当前语言环境并在其中搜索模式 'UTF8'
和 'UTF-8'
,如果是,我假定为 UTF-8,否则我假定为 ISO 和所需的 UTF-8编码。我认为这不是最聪明的方法,而且可能很容易出错。有没有更好的方法?
语言环境取决于系统。确保您想要的语言环境显示在 locale -a
.
中
与 setLocale()
混为一谈是全球性的,可能会产生意想不到的副作用,我建议改为 IntlDateFormatter
:
$d = new DateTime('2021-03-15');
$mon_formatter = new IntlDateFormatter('de_DE', IntlDateFormatter::NONE, IntlDateFormatter::NONE);
$mon_formatter->setPattern('MMMM');
$day_formatter = new IntlDateFormatter('de_DE', IntlDateFormatter::NONE, IntlDateFormatter::NONE);
$day_formatter->setPattern('EEEE');
var_dump(
$mon_formatter->format($d),
$day_formatter->format($d)
);
输出
string(5) "März"
string(6) "Montag"
或者,更可能的是,使用 pattern you define.
格式化整个日期
我所有的网站都使用 UTF-8 作为字符集。但是在设置 setlocale
并从 strftime
获取月份名称和工作日名称的本地化字符串时存在一些问题。
- 问题:本地化月份名称在服务器上不起作用。
- 问题:如何知道语言环境字符串是 UTF-8 还是 ISO?
具体:我这样设置语言环境:
$locales = ['de_DE.utf-8/utf-8', 'de_DE@euro/utf-8', 'de_DE', 'de-DE', 'german', 'de', 'ge'];
$locale = setlocale(LC_ALL, $locales);
在我的开发系统 (Windows 10, XAMPP) 上它找到并设置 $locale = 'de-DE'.
在我的服务器(Linux、Apache)上,它找到并设置 $locale = 'de_DE'.
因为 DateTime class 中内置的 PHP 不支持本地化名称,我创建了一个 class 来扩展 DateTime class:
class DateTimeExt extends DateTime {
private function isUTF8() : bool {
$locale = setlocale(LC_ALL, null);
if (!$locale) return false;
$locale = strtoupper($locale);
return strpos($locale, 'UTF8') !== false || strpos($locale, 'UTF-8') !== false;
}
public function weekdayName() : string {
$weekday = strftime('%A', $this->getTimestamp());
if (!$weekday) return 'unknown';
return $this->isUTF8() ? $weekday : utf8_encode($weekday);
}
public function monthName() : string {
$month = strftime('%B', $this->getTimestamp());
if (!$month) return 'unknown';
return $this->isUTF8() ? $month : utf8_encode($month);
}
}
测试:
$date = new DateTimeExt('2021-03-02');
echo $date->weekdayName().'<br />';
echo $date->monthName().'<br />';
开发环境的结果:
// Dienstag
// März
两者都是正确的。如果没有 UTF-8 编码,它将返回:
// Dienstag
// M�rz
但在服务器上结果为:
// Dienstag
// March
卧槽???服务器可以本地化工作日,但不能本地化月份,并且默认为英语?为什么?这是第 1 期。
问题二是检测设置的locale是否支持UTF-8。我的函数 isUTF8
只是获取当前语言环境并在其中搜索模式 'UTF8'
和 'UTF-8'
,如果是,我假定为 UTF-8,否则我假定为 ISO 和所需的 UTF-8编码。我认为这不是最聪明的方法,而且可能很容易出错。有没有更好的方法?
语言环境取决于系统。确保您想要的语言环境显示在 locale -a
.
与 setLocale()
混为一谈是全球性的,可能会产生意想不到的副作用,我建议改为 IntlDateFormatter
:
$d = new DateTime('2021-03-15');
$mon_formatter = new IntlDateFormatter('de_DE', IntlDateFormatter::NONE, IntlDateFormatter::NONE);
$mon_formatter->setPattern('MMMM');
$day_formatter = new IntlDateFormatter('de_DE', IntlDateFormatter::NONE, IntlDateFormatter::NONE);
$day_formatter->setPattern('EEEE');
var_dump(
$mon_formatter->format($d),
$day_formatter->format($d)
);
输出
string(5) "März"
string(6) "Montag"
或者,更可能的是,使用 pattern you define.
格式化整个日期