我正在建立一个多语言网站,将在英语和俄语显示。翻译方面的一切都很好,除了日期。
据我所知,PHP的strtotime()
函数严格适用于英文日期,正如它在官方文档中所说的"将任何英文文本日期时间描述解析为Unix时间戳"。
我已经尝试使用setlocale( LC_TIME, 'ru_RU', 'russian' );
,然后strftime()
,但它只是不断返回unix January 1970
日期。
我要做的是从日期中获取日名(即星期三)并显示它。通常,对于英语日期,我会像$this->day = date('l', strtotime( $date ));
那样做,但因为我想同时使用英语和俄语,所以我这样做$this->day = strftime("%A", strtotime($date) );
我的日期格式为" 2015年10月13日",我认为这是问题的一部分,因为"10月"的俄语翻译是"Октябрь",所以我最终试图解析的最终结果是"Октябрь 13,2015",它总是返回"星期四",而实际上10月13日是星期二。
下面是我解析日期所做的一切:
$this->month_arr = array();
// Loop through $event_dates array created above
if(isset($_GET['lang']) && $_GET['lang'] == 'ru') {
setlocale(LC_ALL, 'ru_RU.utf8', 'rus_RUS.1251', 'rus', 'russian');
}
foreach($this->event_dates as $date => $time) {
// Create the unix timestamp to parse with PHP
$unix_date = strtotime($date);
$this->month = strftime("%B", $unix_date);
$this->day = strftime("%A", $unix_date);
$this->year = strftime("%G", $unix_date);
// Create new array with date info
$this->month_arr[$this->month][] = $this->day; // Day of week
$this->month_arr[$this->month][] = $date; // Full textual date
$this->month_arr[$this->month][] = $this->year; // 4 Digit Year
$this->month_arr[$this->month][] = $time; // Start/end time array
}
这完美地解析了日期的英文表示,但其他一切似乎都搞砸了。作为暂时的退步,我已经从最后的显示中删除了星期几,并且只是从初始日期字符串中剥离"October"或"Октябрь"并显示它,但这不是客户端所期望的。
我也尝试过这种格式:strftime('%B %e, %Y', $unix_date);
,希望将strftime()
格式与最初显示日期的方式相匹配,但这给了我相同的最终结果。
注:我在我的本地主机MAMP服务器上运行这一切。生产/登台服务器运行在nginx上。
EDIT:这是一个WordPress网站,日期是通过"高级自定义字段专业版"插件创建的。该插件不允许用户将日期保存为时间戳。我已经尝试过使用WP的内置date_i18n($format, $unix_timestamp);
功能,没有运气。
EDIT x2:我目前正在做这样的事情:
// Russian Months
$ru_months = array( 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' );
// English Months
$en_months = array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' );
// Get date string from ACF
$date_arr = explode(" ", get_sub_field('date'));
// Get the month name
$month = $date_arr[0];
// Get the array index of the month name
$month_index = array_search($month, $en_months);
// Piece together new date string in Russian translation
$date = $ru_months[$month_index] . " " . $day . ", " . $year;
目前可以工作,但我也想翻译日期名称。例如,星期二,2015年10月13日这个方法并没有提供一个可靠的方法来做到这一点
我看到这里有三个选项。
你可以自己编写PHP代码来转换日期。它是肮脏的,它是蛮力的,但它是直接的。
function add_weekday( $date ) {
$ru_weekdays = array( 'Понедельник', 'Вторник', 'Среда', 'Четверг', 'Пятница', 'Суббота', 'Воскресенье' );
$en_weekdays = array( 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' );
$ru_months = array( 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' );
$en_months = array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' );
$en_date = str_replace( $ru_months, $en_months, $date );
$weekdays = $en_date === $date ? $en_weekdays : $ru_weekdays;
// $wday = strptime( $en_date, '%B %e, %Y' ); // Linux/Mac
// return $weekdays[ $wday['tm_wday']-1 ]." $date"; // Linux/Mac
return $weekdays[ DateTime::createFromFormat( 'M j, Y', $en_date )->format( 'N' )-1 ]." $date"; // PHP 5.3+
}
echo add_weekday( 'Октябрь 13, 2015' ); // Вторник Октябрь 13, 2015
echo add_weekday( 'October 13, 2015' ); // Tuesday October 13, 2015
- 问一个企业数据库。 我爱SQL Server。看:
例如,PECL intl模块有一个IntlDateFormatter:
$formatter = new IntlDateFormatter( 'ru', IntlDateFormatter::LONG, IntlDateFormatter::NONE );
$datetime = $formatter->parse( "13 октября 2015 r." );
$weekday = $datetime->format( 'l' ); // 'Tuesday'
然而intl是非常挑剔的;日期字符串必须匹配它的精确的格式:无大写,无oктябр * * ,日期必须在月之前,且必须以"r "结尾。
如果你问我的话,我觉得不够灵活,不值得麻烦。
SELECT datename( dw, Try_Parse( N'Октябрь 13, 2015' AS date USING 'Ru-RU' ) );
-- 'Tuesday', if default language is English
SET LANGUAGE 'Russian';
SELECT datename( dw, Try_Parse( N'Октябрь 13, 2015' AS date ) );
-- 'вторник'
或Oracle,也可以完成工作:
SELECT TO_CHAR( TO_DATE( 'Октябрь 13, 2015', 'MON DD, YYYY', 'nls_date_language = Russian' )
, 'DAY', 'nls_date_language = Russian' ) FROM DUAL;
-- 'ВТОРНИК'
ALTER SESSION SET NLS_LANGUAGE = 'RUSSIAN';
SELECT TO_CHAR( TO_DATE( 'Октябрь 13, 2015', 'MON DD, YYYY' ), 'DAY' ) FROM DUAL;
-- 'ВТОРНИК'
你不需要任何i18n模块——它们是内置的。
我知道最常见的配置不给你SQL Server或Oracle,但他们是免费的,你不需要使用它们作为你的主数据库。一旦你把它们设置好并连接起来,许多datetime i18n问题都可以用一个查询来解决。MySQL不能解析国际日期-就像PHP。
但是要小心。我就是这样爱上SQL Server的
使用DateTime::createFromFormat
和date_default_timezone_set
,即:
date_default_timezone_set('Europe/Moscow');
$ruDate = 'Октябрь 13, 2015';
$enDate = DateTime::createFromFormat('F j, Y', ruMonthsToEn($ruDate));
echo $enDate->format('l, F, j, Y');
//Tuesday, October, 13, 2015
echo $enDate->getTimestamp();
//1444764954
function ruMonthsToEn($date){
$ruMonths = array( 'Январь', 'Февраль', 'Март', 'Апрель', 'Май', 'Июнь', 'Июль', 'Август', 'Сентябрь', 'Октябрь', 'Ноябрь', 'Декабрь' );
$enMonths = array( 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' );
return str_replace($ruMonths, $enMonths, $date);
}
您的理解是正确的:strtotime()
只会将英文字符串解析为整数。您可能没有注意到,当函数无法进行转换时,它会返回一个布尔值false:
$date = "October 13, 2015";
$rudate = "октября 13, 2015";
var_dump(strtotime( $date )); //outputs int(1444687200)
var_dump(strtotime( $rudate )); //ouputs bool(false)
当你试图用布尔值调用date()
或strftime()
时,PHP出于某种原因决定默认为某个日期,而这个日期恰好是星期四。
var_dump(date('l', false)); //outputs string(8) "Thursday"
var_dump(strftime("%A", false)); //outputs string(8) "Thursday"
由于数据已经存储,因此必须在使用现有PHP函数处理数据之前对其进行修改。由于您只需要将俄语翻译成英语,因此更改相当轻松:
//You should, of course, add the other months in.
function dateToEnglish($str)
{
$str = str_replace('января', 'January', $str);
//...
$str = str_replace('октября', 'October', $str);
//...
$str = str_replace('Декабрь', 'December', $str);
return $str;
}
var_dump(strtotime(dateToEnglish($rudate))); //outputs int(1444687200)
在进一步处理之前,您可以使用它将日期解析为英语:
foreach($this->event_dates as $date => $time) {
// Create the unix timestamp to parse with PHP
$unix_date = strtotime(dateToEnglish($date));
// ...
}
您想要支持的每种语言都需要手动添加,这是该策略的主要缺点。但是,您处理这个问题的方法有一些严重的代码味道,因为您使用字符串而不是时间戳。
将来,您应该将日期存储为时间戳(参见DateTime),因为它们与语言无关,并且不需要这个额外的处理步骤。