我借用了漂亮的CokidooDateTime类,它将常规DateTime转换为"ago格式"。
我正在开发多语言网站,想用变量取代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),
请帮忙吗?
如果该类不扩展DateTime
,它将更加有用。它所做的唯一一件事就是格式化日期,它根本没有理由是日期。它可以很容易地根据需要创建一个DateTime
,并使用它来代替$this
。
如果您进行了此修改(并将类适当地重命名为例如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分钟前"或类似的格式,这是一个非常糟糕的想法。数字需要是格式字符串的一部分,因为在许多文化中,它不在"多久以前"部分之前。
更新
我调整了伊利亚的候选解决方案,使其符合上述建议;结果就在这里。
在不需要撇号的地方有撇号。
你在追求:
$month_ago = 'month ago';
$months_ago = 'months ago';
//Further on within the array
'm' -> array('1 '.$month_ago, '%d '.$months_ago);
基于建议的想法,我终于找到了一个可以工作的多语言解决方案来返回时差。
请对我温和一点,因为我是面向对象风格编程的完全初学者,这实际上是我的第一项任务。如果你留下评论或建议,我会非常高兴。
特别感谢Jon,很抱歉我没能体现你所有的想法。我接受你的回答,因为它有很好的建议和解释!
说明
-
在我的数据库中,我有
added_time
字段,它指的是以Unix时间戳格式上传的每个视频的创建时间,例如1345284190
此时间戳被传递给类似new creationTime( '@' . $timestamp)
的构造函数; -
我有一个特殊的功能,可以循环播放每个视频并插入
,例如:视频是27天前添加的。
我最终通过使用Cokidoo在PHP Time Manual上提供的一个漂亮的例子实现了这一点,并添加了对多语言网站的支持,用从语言文件派生的任何文本替换了years ago
、months ago
、days ago
等。
调整
-
我已经将用英语书写的初始值(即:年前、月前天前等)更改为易于处理的值,例如:
year_ago
、month_ago
、day_ago
等。 -
然后,我分解了返回输出的初始
$value
变量,例如:1年前、1个月前、一天前,并按照建议用于返回sprintf
。 -
最后,我添加了
getLocalized
函数,它将这个类与我的语言文件连接起来。
这是最后一个不发出警告的工作代码(警告已启用;PHP版本5.4.6)。
我已将类名从Cokidoo_DateTime
重命名为creationTime
:
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);