From 2e76e337a672f21daa0c4a88dfb0a020cdfc20dd Mon Sep 17 00:00:00 2001 From: Kuba Brecka Date: Thu, 7 Mar 2013 20:05:18 +0100 Subject: [PATCH] 1st attempt to support i18n in dates and times --- app/assets/javascripts/application.js.erb | 2 + .../discourse/helpers/application_helpers.js | 25 ++-- app/assets/javascripts/external/humane.js | 134 ------------------ .../javascripts/locales/date_locales.js | 36 +++++ config/locales/client.cs.yml | 1 + config/locales/client.en.yml | 1 + lib/age_words.rb | 13 +- 7 files changed, 54 insertions(+), 158 deletions(-) delete mode 100644 app/assets/javascripts/external/humane.js create mode 100644 app/assets/javascripts/locales/date_locales.js diff --git a/app/assets/javascripts/application.js.erb b/app/assets/javascripts/application.js.erb index 8525d0bed50..686ca618d5e 100644 --- a/app/assets/javascripts/application.js.erb +++ b/app/assets/javascripts/application.js.erb @@ -24,6 +24,8 @@ //= require ./discourse/helpers/i18n_helpers //= require ./discourse +//= require ./locales/date_locales.js + // Stuff we need to load first //= require_tree ./discourse/mixins //= require ./discourse/views/view diff --git a/app/assets/javascripts/discourse/helpers/application_helpers.js b/app/assets/javascripts/discourse/helpers/application_helpers.js index 0c51062d285..55c95911ee5 100644 --- a/app/assets/javascripts/discourse/helpers/application_helpers.js +++ b/app/assets/javascripts/discourse/helpers/application_helpers.js @@ -1,5 +1,3 @@ -/*global humaneDate:true */ - /** Breaks up a long string @@ -162,7 +160,7 @@ Handlebars.registerHelper('avatar', function(user, options) { Handlebars.registerHelper('unboundDate', function(property, options) { var dt; dt = new Date(Ember.Handlebars.get(this, property, options)); - return dt.format("{d} {Mon}, {yyyy} {hh}:{mm}"); + return dt.format("long"); }); /** @@ -176,9 +174,9 @@ Handlebars.registerHelper('editDate', function(property, options) { dt = Date.create(Ember.Handlebars.get(this, property, options)); yesterday = new Date() - (60 * 60 * 24 * 1000); if (yesterday > dt.getTime()) { - return dt.format("{d} {Mon}, {yyyy} {hh}:{mm}"); + return dt.format("long"); } else { - return humaneDate(dt); + return dt.relative(); } }); @@ -215,7 +213,7 @@ Handlebars.registerHelper('number', function(property, options) { @for Handlebars **/ Handlebars.registerHelper('date', function(property, options) { - var displayDate, dt, fiveDaysAgo, fullReadable, humanized, leaveAgo, val; + var displayDate, dt, fiveDaysAgo, oneMinuteAgo, fullReadable, humanized, leaveAgo, val; if (property.hash) { if (property.hash.leaveAgo) { leaveAgo = property.hash.leaveAgo === "true"; @@ -229,23 +227,26 @@ Handlebars.registerHelper('date', function(property, options) { return new Handlebars.SafeString("—"); } dt = new Date(val); - fullReadable = dt.format("{d} {Mon}, {yyyy} {hh}:{mm}"); + fullReadable = dt.format("long"); displayDate = ""; fiveDaysAgo = (new Date()) - 432000000; - if (fiveDaysAgo > (dt.getTime())) { + oneMinuteAgo = (new Date()) - 60000; + if (oneMinuteAgo <= dt.getTime() && dt.getTime() <= (new Date())) { + displayDate = Em.String.i18n("now"); + } else if (fiveDaysAgo > (dt.getTime())) { if ((new Date()).getFullYear() !== dt.getFullYear()) { - displayDate = dt.format("{d} {Mon} '{yy}"); + displayDate = dt.format("short"); } else { - displayDate = dt.format("{d} {Mon}"); + displayDate = dt.format("short_no_year"); } } else { - humanized = humaneDate(dt); + humanized = dt.relative(); if (!humanized) { return ""; } displayDate = humanized; if (!leaveAgo) { - displayDate = displayDate.replace(' ago', ''); + displayDate = (dt.millisecondsAgo()).duration(); } } return new Handlebars.SafeString("" + displayDate + ""); diff --git a/app/assets/javascripts/external/humane.js b/app/assets/javascripts/external/humane.js deleted file mode 100644 index adbd630edb6..00000000000 --- a/app/assets/javascripts/external/humane.js +++ /dev/null @@ -1,134 +0,0 @@ -/* - * Javascript Humane Dates - * Copyright (c) 2008 Dean Landolt (deanlandolt.com) - * Re-write by Zach Leatherman (zachleat.com) - * - * Adopted from the John Resig's pretty.js - * at http://ejohn.org/blog/javascript-pretty-date - * and henrah's proposed modification - * at http://ejohn.org/blog/javascript-pretty-date/#comment-297458 - * - * Licensed under the MIT license. - */ - -function humaneDate(date, compareTo){ - - if(!date) { - return; - } - - var lang = { - ago: 'ago', - from: '', - now: 'just now', - minute: 'minute', - minutes: 'minutes', - hour: 'hour', - hours: 'hours', - day: 'day', - days: 'days', - week: 'week', - weeks: 'weeks', - month: 'month', - months: 'months', - year: 'year', - years: 'years' - }, - formats = [ - [60, lang.now], - [3600, lang.minute, lang.minutes, 60], // 60 minutes, 1 minute - [86400, lang.hour, lang.hours, 3600], // 24 hours, 1 hour - [604800, lang.day, lang.days, 86400], // 7 days, 1 day - [2628000, lang.week, lang.weeks, 604800], // ~1 month, 1 week - [31536000, lang.month, lang.months, 2628000], // 1 year, ~1 month - [Infinity, lang.year, lang.years, 31536000] // Infinity, 1 year - ], - isString = typeof date == 'string', - date = isString ? - new Date(('' + date).replace(/-/g,"/").replace(/[TZ]/g," ")) : - date, - compareTo = compareTo || new Date, - seconds = (compareTo - date + - (compareTo.getTimezoneOffset() - - // if we received a GMT time from a string, doesn't include time zone bias - // if we got a date object, the time zone is built in, we need to remove it. - (isString ? 0 : date.getTimezoneOffset()) - ) * 60000 - ) / 1000, - token; - - if(seconds < 0) { - seconds = Math.abs(seconds); - token = lang.from ? ' ' + lang.from : ''; - } else { - token = lang.ago ? ' ' + lang.ago : ''; - } - - /* - * 0 seconds && < 60 seconds Now - * 60 seconds 1 Minute - * > 60 seconds && < 60 minutes X Minutes - * 60 minutes 1 Hour - * > 60 minutes && < 24 hours X Hours - * 24 hours 1 Day - * > 24 hours && < 7 days X Days - * 7 days 1 Week - * > 7 days && < ~ 1 Month X Weeks - * ~ 1 Month 1 Month - * > ~ 1 Month && < 1 Year X Months - * 1 Year 1 Year - * > 1 Year X Years - * - * Single units are +10%. 1 Year shows first at 1 Year + 10% - */ - - function normalize(val, single) - { - var margin = 0.1; - if(val >= single && val <= single * (1+margin)) { - return single; - } - return val; - } - - for(var i = 0, format = formats[0]; formats[i]; format = formats[++i]) { - if(seconds < format[0]) { - if(i === 0) { - // Now - return format[1]; - } - - var val = Math.ceil(normalize(seconds, format[3]) / (format[3])); - return val + - ' ' + - (val != 1 ? format[2] : format[1]) + - (i > 0 ? token : ''); - } - } -}; - -if(typeof jQuery != 'undefined') { - jQuery.fn.humaneDates = function(options) - { - var settings = jQuery.extend({ - 'lowercase': false - }, options); - - return this.each(function() - { - var $t = jQuery(this), - date = $t.attr('datetime') || $t.attr('title'); - - date = humaneDate(date); - - if(date && settings['lowercase']) { - date = date.toLowerCase(); - } - - if(date && $t.html() != date) { - // don't modify the dom if we don't have to - $t.html(date); - } - }); - }; -} \ No newline at end of file diff --git a/app/assets/javascripts/locales/date_locales.js b/app/assets/javascripts/locales/date_locales.js new file mode 100644 index 00000000000..10aadc96b91 --- /dev/null +++ b/app/assets/javascripts/locales/date_locales.js @@ -0,0 +1,36 @@ +// fix EN locale +Date.getLocale('en').short_no_year = '{d} {Mon}'; + +// create CS locale +Date.addLocale('cs', { + 'plural': true, + 'capitalizeUnit': false, + 'months': 'ledna,února,března,dubna,května,června,července,srpna,září,října,listopadu,prosince', + 'weekdays': 'neděle,pondělí,úterý,středa,čtvrtek,pátek,sobota', + 'units': 'milisekund:a|y||ou|ami,sekund:a|y||ou|ami,minut:a|y||ou|ami,hodin:a|y||ou|ami,den|dny|dnů|dnem|dny,týden|týdny|týdnů|týdnem|týdny,měsíc:|e|ů|em|emi,rok|roky|let|rokem|lety', + 'short': '{d}. {month} {yyyy}', + 'short_no_year': '{d}. {month}', + 'long': '{d}. {month} {yyyy} {H}:{mm}', + 'full': '{weekday} {d}. {month} {yyyy} {H}:{mm}:{ss}', + 'relative': function(num, unit, ms, format) { + var numberWithUnit, last = num.toString().slice(-1); + var mult; + if (format === 'past' || format === 'future') { + if (num === 1) mult = 3; + else mult = 4; + } else { + if (num === 1) mult = 0; + else if (num >= 2 && num <= 4) mult = 1; + else mult = 2; + } + numberWithUnit = num + ' ' + this.units[(mult * 8) + unit]; + switch(format) { + case 'duration': return numberWithUnit; + case 'past': return 'před ' + numberWithUnit; + case 'future': return 'za ' + numberWithUnit; + } + } +}); + +// set the current date locale +Date.setLocale(I18n.locale); diff --git a/config/locales/client.cs.yml b/config/locales/client.cs.yml index 4e5f25ac525..c5b4d8df8a9 100644 --- a/config/locales/client.cs.yml +++ b/config/locales/client.cs.yml @@ -24,6 +24,7 @@ cs: you: "Vy" ok: "ok" or: "nebo" + now: "právě teď" suggested_topics: title: "Doporučená témata" diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 102d0970a87..4463e7db403 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -24,6 +24,7 @@ en: you: "You" ok: "ok" or: "or" + now: "just now" suggested_topics: title: "Suggested Topics" diff --git a/lib/age_words.rb b/lib/age_words.rb index 1d9bf6fda50..1c590d0b320 100644 --- a/lib/age_words.rb +++ b/lib/age_words.rb @@ -3,18 +3,7 @@ module AgeWords def self.age_words(secs) return "—" if secs.blank? - mins = (secs / 60.0) - hours = (mins / 60.0) - days = (hours / 24.0) - months = (days / 30.0) - years = (months / 12.0) - - return "#{years.floor}y" if years > 1 - return "#{months.floor}mo" if months > 1 - return "#{days.floor}d" if days > 1 - return "#{hours.floor}h" if hours > 1 - return "< 1m" if mins < 1 - return "#{mins.floor}m" + return FreedomPatches::Rails4.distance_of_time_in_words(Time.now, Time.now + secs) end end \ No newline at end of file