4

通常の DateTime を「前の形式」に変換する美しいCokidoo DateTimeクラスを借りてきました。

私は多言語 Web サイトを開発しており、、、を変数に置き換えたいと考えていyear agoましyears agomonth 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

提案されたアイデアに基づいて、最終的に時差を返すための実用的な多言語ソリューションにたどり着きました。

私はオブジェクト指向スタイルのプログラミングの完全な初心者であり、これは実際には私の最初のタスクであるため、優しくしてください。コメントや提案されたアイデアを残していただければ幸いです。

Jon に感謝します。あなたのアイデアをすべて具現化できなかったことを残念に思います。とても素敵な提案と説明があるので、あなたの答えを受け入れます!

説明

  1. 私のデータベースにはadded_time、アップロードされた各ビデオの作成時刻を Unix タイムスタンプ形式で参照するフィールドがあります1345284190
    このタイムスタンプは、次のようにコンストラクターに渡され new creationTime( '@' . $timestamp)ます。

  2. 各ビデオをループして挿入する特別な機能があります。
    例: ビデオは27 日前に追加されました。

PHP Time ManualでCokidoo が提供する美しい例を使用して、最終的にこれを達成し、多言語 Web サイトのサポートを追加してyears agomonths agodays ago、などを言語ファイルから派生したテキストに置き換えました。

微調整

  1. 英語で書かれた初期値 (つまり 、 year agomonth agoday agoなど) を (多言語 Web サイトで使用できるようにするために) 簡単に処理できるものに変更しました。 : year_agomonth_agoday_agoなど

  2. 次に、出力を返していた初期$value変数を展開しました。たとえば、 1年前1か月前1日前sprintf、提案されたとおりに使用されました。

  3. 最後に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);
于 2012-09-14T17:35:01.727 に答える