英语用PHP表示俄语

时间:2015-10-04 15:34:18

标签: php date datetime localization multilingual

我正在建立一个多语言网站,将以英语和俄语显示。除日期外,翻译方面的所有内容都运作良好。

据我所知,PHP的strtotime()函数严格用于英文日期,正如官方文档“Parse about any English textual datetime description into a Unix timestamp”中所述。

我已尝试使用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日”,我假设是问题的一部分,因为“十月”的俄语翻译是“Октябрь”所以最终的结果是我最终试图解析的是“Октябрь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
}

这完美地解析了日期的英语表示,但其他一切似乎搞砸了。作为一个临时的后退,我已经从最终显示中删除了一周中的那一天,我只是从初始日期字符串中删除了“十月”或“Октябрь”并显示了这一点,但这不是客户所期望的。

我也尝试过这种格式:strftime('%B %e, %Y', $unix_date);希望将strftime()格式与最初显示日期的方式相匹配会有效,但这给了我相同的最终结果。

P.S。我在我的localhost MAMP服务器上运行这一切。生产/登台服务器在nginx上运行。

编辑:这是一个WordPress网站,日期是通过“Advanced Custom Fields 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;   

现在有效,但我想翻译日期名称。例如, 2015年10月13日星期二,此方法无法提供可靠的方法。

3 个答案:

答案 0 :(得分:6)

我在这里看到三个选项。

  1. 编写自己的解析器。
  2. 您始终可以编写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
    
    1. 使用图书馆。
    2. 例如,PECL intl module有一个IntlDateFormatter

      $formatter = new IntlDateFormatter( 'ru', IntlDateFormatter::LONG, IntlDateFormatter::NONE );
      $datetime = $formatter->parse( "13 октября 2015 r." );
      $weekday = $datetime->format( 'l' ); // 'Tuesday'
      

      然而国际航空公司非常挑剔;日期字符串必须与其完全格式匹配: 没有大写,没有oктябрь,日期必须在月之前,并且必须以“r。”结尾。

      如果你问我,那就不够灵活了。

      1. Ask 企业数据库。
      2. 我爱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 ) );
        -- 'вторник'
        

        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模块 - 它们内置了它们。

          

        MySQL无法解析国际日期 - 就像PHP一样。

        我知道最常见的配置不会提供SQL Server或Oracle,但它们是免费的,您不需要将它们用作主数据库。 一旦你完成设置和连接,就可以通过一次查询解决许多datetime i18n问题。

        但要小心。这正是我fell in love与SQL Server的对比。

答案 1 :(得分:3)

使用DateTime::createFromFormatdate_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);
}

答案 2 :(得分:1)

您的理解是正确的:strtotime()只会将 english 字符串解析为整数。您可能错过了当函数无法进行转换时,它返回一个布尔值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));
    // ...
}

您需要支持的每种语言都需要手动添加,这是此策略的主要缺点。但是,对于此问题,您使用字符串而不是时间戳的方式有一些严重code smell

将来,您应该将日期存储为时间戳(请参阅DateTime),因为它们与语言无关,并且不需要执行额外的处理步骤。