4

我借用了漂亮的 Cokidoo DateTime类,它将常规 DateTime 转换为“以前的格式”。

我正在开发多语言网站并想用变量替换year ago, years ago, 。month ago

代码示例:

protected $strings = array(
        'y' => array('1 year ago', '%d years ago'),
        'm' => array('1 month ago', '%d months ago'),
        'd' => array('1 day ago', '%d days ago'),
        'h' => array('1 hour ago', '%d hours ago'),
        'i' => array('1 minute ago', '%d minutes ago'),
        's' => array('now', '%d secons ago'),
    );


这是否可以在不使用替换方法的情况下做到这一点?

显然这不起作用:

'm' => array('1' . $month_ago, '%d' . $months_ago),

请问有什么帮助吗?

4

3 回答 3

4

如果该类不扩展,它会更有用DateTime。它唯一做的就是格式化日期,它根本没有理由成为日期。它可以很容易地创建一个DateTime按需并在其上工作,而不是$this.

如果您进行此修改(并将类适当地重命名为 eg DateTimeDiffFormatter),那么突然所有可能性都打开了:您可以将参数传递给确定要使用的语言的构造函数,或者甚至更好地传递对您的 i18n 组件的一些引用。然后例如你可以有

// I have no idea why this was protected, and probably the class author did not as well
private $strings = array(
    'y' => array('years_ago_1', 'years_ago_n'),
    // etc etc
);

return sprintf($localizer->get_string($this->strings[$intervalKey][$pluralKey]),
               $value);

最后,假设您可以将本地化字符串的格式硬编码为“X 分钟前”等,这是一个非常糟糕的主意。该数字需要成为格式字符串的一部分,因为在许多文化中它不在“多久以前”部分之前。

更新

我调整了 Ilia 的候选解决方案,使其符合上述建议;结果就在这里

于 2012-09-14T08:48:47.493 回答
0

您在不需要它们的地方有撇号。

您是否追求:

 $month_ago = 'month ago';
 $months_ago = 'months ago';

//Further on within the array
'm' -> array('1 '.$month_ago, '%d '.$months_ago);
于 2012-09-14T08:48:42.607 回答
0

根据建议的想法,我终于想出了一个可行的多语言解决方案来返回时差。

请对我温柔一点,因为我是面向对象风格编程的完全初学者,这实际上是我的第一个任务。如果您留下评论或建议的想法,我会非常高兴。

特别感谢乔恩,我很抱歉我不能体现你所有的想法。我接受你的回答,因为它有很好的建议和解释!

描述

  1. 在我的数据库中,我有一个added_time字段,它指的是每个上传的 Unix 时间戳格式的视频的创建时间,例如1345284190.
    这个时间戳被传递给构造函数,比如 new creationTime( '@' . $timestamp)

  2. 我有一个特殊的功能,可以循环播放每个视频并插入
    例如:视频是在27 天前添加的。

我终于通过使用 Cokidoo 在PHP Time Manual上提供的一个漂亮的例子来实现这一点,并添加了对多语言网站的支持,用从语言文件派生的任何文本替换years agomonths ago等。days ago

调整

  1. 我已将用英语编写的初始值(即: 一年前一个月前一天前等)(以便能够在多语言网站中使用它们)更改为可以轻松处理的内容,例如: year_ago, month_ago,day_ago等等。

  2. 然后我分解了$value返回输出的初始变量,例如:1 year ago1 month ago1 day ago并按照建议使用作为回报sprintf

  3. 最后我添加getLocalized了将这个类与我的语言文件连接起来的函数。

这是不引发警告的最终和工作代码(警告已启用;PHP 版本 5.4.6)。
我已将类名重命名Cokidoo_DateTimecreationTime

class creationTime extends DateTime {

    private $strings = array(
        'y' => array('1 year_ago', '%d years_ago'),
        'm' => array('1 month_ago', '%d months_ago'),
        'd' => array('1 day_ago', '%d days_ago'),
        'h' => array('1 hour_ago', '%d hours_ago'),
        'i' => array('1 minute_ago', '%d minutes_ago'),
        's' => array('just_now', '%d seconds_ago'),
    );

   private function getLocalized($string) {

        global $lang;

        $string == 'year_ago' ? $string = $lang['global.year_ago'] : null;
        $string == 'years_ago' ? $string = $lang['global.years_ago'] : null;
        $string == 'month_ago' ? $string = $lang['global.month_ago'] : null;
        $string == 'months_ago' ? $string = $lang['global.months_ago'] : null;
        $string == 'day_ago' ? $string = $lang['global.day_ago'] : null;
        $string == 'days_ago' ? $string = $lang['global.days_ago'] : null;
        $string == 'hour_ago' ? $string = $lang['global.hour_ago'] : null;
        $string == 'hours_ago' ? $string = $lang['global.hours_ago'] : null;
        $string == 'hour_ago' ? $string = $lang['global.hour_ago'] : null;
        $string == 'hours_ago' ? $string = $lang['global.hours_ago'] : null;
        $string == 'minute_ago' ? $string = $lang['global.minute_ago'] : null;
        $string == 'minutes_ago' ? $string = $lang['global.minutes_ago'] : null;
        $string == 'just_now' ? $string = $lang['global.just_now'] : null;
        $string == 'seconds_ago' ? $string = $lang['global.seconds_ago'] : null;

        return $string;
    }

    /**
     * Returns the difference from the current time in the format X time ago
     * @return string
     */

   public function __toString() {
        $now = new DateTime('now');
        $diff = $this->diff($now);
        foreach($this->strings as $key => $value){
            if( ($text = $this->getDiffText($key, $diff)) ){
                return $text;
            }
        }
        return '';
    }

    /**
     * Try to construct the time diff text with the specified interval key
     * @param string $intervalKey A value of: [y,m,d,h,i,s]
     * @param DateInterval $diff
     * @return string|null
     */
    protected function getDiffText($intervalKey, $diff){
        $pluralKey = 1;
        $value = $diff->$intervalKey;
        if($value > 0){
            if($value < 2){
                $pluralKey = 0;
            }
            $value = explode(' ', sprintf($this->strings[$intervalKey][$pluralKey], $value) );          
            return sprintf('%d %s', implode(array_slice($value, 0)), $this->getLocalized(implode(array_slice($value, 1))));
        }
        return null;
    }
}


已编辑

这个绝妙的解决方案虽然做同样的事情,但具有更好的格式和结构(由Jon提供)。

class DateFormatter {
    private $localizer;

    private $strings = array(
        'y' => array('global.years_ago_1', 'global.years_ago_n'),
        'm' => array('global.months_ago_1', 'global.months_ago_n'),
        'd' => array('global.days_ago_1', 'global.days_ago_n'),
        'h' => array('global.hours_ago_1', 'global.hours_ago_n'),
        'i' => array('global.minutes_ago_1', 'global.minutes_ago_n'),
        's' => array('global.seconds_ago_1', 'global.seconds_ago_n'),
    );

    public function __construct(Localizer $localizer) {
        $this->localizer = $localizer;
    }

    /**
     * Returns the difference from the current time in the format X time ago
     * @return string
     */
    public function formatHowLongAgo(DateTime $date) {
        $now = new DateTime('now');
        $diff = $date->diff($now);
        foreach($this->strings as $unitOfTime => $formatStrings){
            $howMany = $diff->$unitOfTime;
            if (!$howMany) {
                continue;
            }

            $plural = $howMany > 1;
            return $this->localizer->format($this->strings[$unitOfTime][$plural], $howMany);
        }
        return '??';
    }
}

// Packaged the localization stuff inside a class so that it's not
// just hanging around in the global scope. Not much to see here,
// a "real" localizer would have more features.
class Localizer {
    private $lang = array(
        'global.years_ago_1'    => '1 year ago',
        'global.years_ago_n'    => '%d years ago',
        'global.months_ago_1'   => '1 month ago',
        'global.months_ago_n'   => '%d months ago',
        'global.days_ago_1'     => '1 day ago',
        'global.days_ago_n'     => '%d days ago',
        'global.hours_ago_1'    => '1 hour ago',
        'global.hours_ago_n'    => '%d hours ago',
        'global.minutes_ago_1'  => '1 minute ago',
        'global.minutes_ago_n'  => '%d minutes ago',
        'global.seconds_ago_1'  => 'just now',
        'global.seconds_ago_n'  => '%d seconds ago',
    );

    public function format($string /*, $param1, $param2, ... */) {
        $params = func_get_args(); // get variable # of params
        array_shift($params); // remove first item, we already have it in $string
        if (!isset($this->lang[$string])) {
            return '[['.$string.']]'; // a placeholder
        }

        return vsprintf($this->lang[$string], $params);
    }
}

$localizer = new Localizer;
$timestamp = '1345284190';  // Example of Unix Timestamp
$datetime = new DateTime("@$timestamp");
$formatter = new DateFormatter($localizer);

echo $formatter->formatHowLongAgo($datetime);
于 2012-09-14T17:35:01.727 回答