Using variables in an array

I borrowed the beautiful Cokidoo DateTime class , which converts a regular DateTime to the back format.

I am developing a multilingual website and would like to replace the variables a year ago , years ago , a month ago .

Code example:

 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'), ); 


Can this be done without using replacement methods?

Obviously this did not work:

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

Any help please?

+4
source share
3 answers

This class would be much more useful if it did not extend DateTime . The only thing he does is format the date; she has no reason to be a date. It can also easily create a DateTime on demand and work on it instead of $this .

If you make this modification (and rename the class accordingly, for example, DateTimeDiffFormatter ), then all the possibilities will suddenly open: you can pass a parameter to the constructor, which determines the language that will be used, or it is even better to go to some link to your i18n component. Then, for example, you could

 // 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 ); 

and

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

Finally, it’s a really bad idea to assume that you can hardcode the format of localized strings to “X minutes ago” and the like. The number must be part of the format string, as in many cultures it does not precede the "how long" part.

Update

I adapted the decision of the Ilia candidate to bring it into line with the above suggestions; the result is here .

+4
source

You have apostrophes in which you do not need them.

You after:

  $month_ago = 'month ago'; $months_ago = 'months ago'; //Further on within the array 'm' -> array('1 '.$month_ago, '%d '.$months_ago); 
0
source

Based on the suggested ideas, I finally came up with a working multilingual solution to return the time difference.

Be careful with me as I am a complete newbie in object-oriented style programming, and this is actually my first task. I would be more than happy if you left comments or suggested ideas.

Special thanks to John, and I'm sorry that I could not realize all your ideas. I accept your answer because he has very good suggestions and explanations!

Description

  • In my database, I have an added_time field that refers to the time of creation of each uploaded video in Unix timestamp format, for example. 1345284190 .
    This timestamp is passed to a constructor of type new creationTime( '@' . $timestamp) ;

  • I have a special function that goes through each video and inserts: for example, a video was added 27 days ago.

I finally achieved this using the excellent example provided by Cokidoo on the “PHP Time Guide” and added support for multilingual websites, replacing years ago , months ago , days ago , etc. any text received from the language file.

Tweaking

  • I changed the initial values ​​(e.g. a year ago, a month ago, a day ago, etc.) that were written in English (to be able to use them on multilingual websites) to something that could be easily processed year_ago .: year_ago , month_ago , day_ago , etc.

  • Then I blew up the original $value variable that returns the output, for example: 1 year ago, 1 month ago, 1 day ago and used sprintf as the return, as suggested.

  • Finally, I added a getLocalized function that would connect this class with my language files.

This is the final and working code that does not cause any warnings (Warnings are included; PHP version 5.4.6).
I renamed the class name from Cokidoo_DateTime to 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; } } 


EDITED

This is a great solution, does the same, but has the best formatting and structure ( 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 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); 
0
source

Source: https://habr.com/ru/post/1434148/


All Articles