Я создаю многоязычный сайт, который будет отображаться на английском и русском языках. Все с точки зрения перевода работает очень хорошо, за исключением дат.
Насколько я понимаю, 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) );
Моя дата отформатирована словами «13 октября 2015 г.«Я предполагаю, что это часть проблемы, потому что русский перевод« Октябрь »-« Октябрь ». Таким образом, конечный результат, который я в итоге пытаюсь разобрать, -« Октябрь 13, 2015 », который всегда возвращает« четверг », когда на самом деле 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
}
Это отлично разбирает английское представление даты, но все остальное, похоже, испортилось. В качестве временного отступления я удалил день недели из окончательного отображения и просто убираю «октябрь» или «октябрь» из начальной строки даты и отображаю это, но это не то, чего ожидает клиент.
Я также попробовал этот формат: strftime('%B %e, %Y', $unix_date);
в надежде, что соответствует strftime()
будет работать формат, в котором будет отображаться дата, но это дало мне тот же конечный результат.
Постскриптум Я запускаю все это на моем локальном сервере MAMP. Производственные / промежуточные серверы работают на nginx.
РЕДАКТИРОВАТЬ: Это веб-сайт WordPress, и дата создается с помощьюРасширенные пользовательские поля Proплагин. Плагин не позволяет пользователям сохранять дату как отметку времени. Я уже пробовал использовать встроенный WP date_i18n($format, $unix_timestamp);
функционировать без удачи.
РЕДАКТИРОВАТЬ 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;
Сейчас это работает, но я хочу перевести и название дня. Например, Вторник 13 октября 2015 г. и этот метод не обеспечивает надежного способа сделать это.
Я вижу три варианта здесь.
Вы всегда можете написать код 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
Например, PECL международный модуль имеет IntlDateFormatter:
$formatter = new IntlDateFormatter( 'ru', IntlDateFormatter::LONG, IntlDateFormatter::NONE );
$datetime = $formatter->parse( "13 октября 2015 r." );
$weekday = $datetime->format( 'l' ); // 'Tuesday'
Однако международный очень придирчив; строка даты должна соответствовать точный формат:
Нет заглавных букв, нет октябрь, дата должна быть раньше месяца, и она должна заканчиваться на «r».
Не достаточно гибок, чтобы стоить хлопот, если вы спросите меня.
я люблю SQL Server. Посмотрите:
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 ) );
-- 'вторник'
Или же оракул, также выполняет свою работу:
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 — они встроены.
MySQL не может анализировать международную дату — так же, как PHP.
Я знаю, что большинство распространенных конфигураций не предоставляют SQL Server или Oracle, но они бесплатны, и вам не нужно использовать их в качестве основной базы данных.
Как только вы их настроите и подключитесь, многие проблемы с datetime i18n могут быть решены с помощью одного запроса.
Но будь осторожен. Это именно то, как я влюбиться с 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) поскольку они не зависят от языка и не требуют дополнительного шага обработки.