0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-02-10 23:36:14 -05:00

Updated default format for date helper to locale-based date string (#12733)

refs https://github.com/TryGhost/Casper/pull/741
closes https://github.com/TryGhost/Team/issues/524

- Use a local-based format as the default format as suggested in https://github.com/TryGhost/Casper/pull/741
- reworked the helper to be easier to read and follow the different use cases
- introduced setting and resetting locale in tests via settingsCache and themei18n
- updated tests to cover more cases e.g. passing a date, this.published_at and no date
- added validation for user inputted dates because they could literally be anything

Co-authored-by: Hannah Wolfe <erisds@gmail.com>
This commit is contained in:
Matt Hanley 2021-03-05 13:35:31 +00:00 committed by GitHub
parent 226607a203
commit b4140d4310
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 149 additions and 26 deletions

View file

@ -5,42 +5,51 @@
const {SafeString, themeI18n} = require('../services/proxy');
const moment = require('moment-timezone');
const _ = require('lodash');
module.exports = function (date, options) {
let timezone;
module.exports = function (...attrs) {
// Options is the last argument
const options = attrs.pop();
let date;
if (!options && Object.prototype.hasOwnProperty.call(date, 'hash')) {
options = date;
date = undefined;
timezone = options.data.site.timezone;
// If there is any more arguments, date is the first one
if (!_.isEmpty(attrs)) {
date = attrs.shift();
// set to published_at by default, if it's available
// otherwise, this will print the current date
if (this.published_at) {
date = moment(this.published_at).tz(timezone).format();
}
// If there is no date argument & the current context contains published_at use that by default,
// else date being undefined means moment will use the current date
} else if (this.published_at) {
date = this.published_at;
}
// ensure that date is undefined, not null, as that can cause errors
date = date === null ? undefined : date;
const timezone = options.data.site.timezone;
const {
format = 'MMM DD, YYYY',
format = 'll',
timeago
} = options.hash;
// ensure that context is undefined, not null, as that can cause errors
date = date === null ? undefined : date;
timezone = options.data.site.timezone;
const timeNow = moment().tz(timezone);
// Our date might be user input
let testDateInput = Date.parse(date);
let dateMoment;
if (isNaN(testDateInput) === false) {
dateMoment = moment.parseZone(date);
} else {
dateMoment = timeNow;
}
// i18n: Making dates, including month names, translatable to any language.
// Documentation: http://momentjs.com/docs/#/i18n/
// Locales: https://github.com/moment/moment/tree/develop/locale
const dateMoment = moment(date);
dateMoment.locale(themeI18n.locale());
if (timeago) {
date = timezone ? dateMoment.tz(timezone).from(timeNow) : dateMoment.fromNow();
date = dateMoment.tz(timezone).from(timeNow);
} else {
date = timezone ? dateMoment.tz(timezone).format(format) : dateMoment.format(format);
date = dateMoment.tz(timezone).format(format);
}
return new SafeString(date);

View file

@ -1,11 +1,20 @@
const sinon = require('sinon');
const should = require('should');
// Stuff we are testing
const helpers = require('../../../core/frontend/helpers');
const proxy = require('../../../core/frontend/services/proxy');
const settingsCache = require('../../../core/server/services/settings/cache');
const moment = require('moment-timezone');
describe('{{date}} helper', function () {
afterEach(function () {
settingsCache.reset();
proxy.themeI18n._loadLocale();
});
it('creates properly formatted date strings', function () {
const testDates = [
'2013-12-31T11:28:58.593+02:00',
@ -14,7 +23,7 @@ describe('{{date}} helper', function () {
'2014-03-01T01:28:58.593+00:00'
];
const timezones = 'Europe/Dublin';
const timezone = 'Europe/Dublin';
const format = 'MMM Do, YYYY';
const context = {
@ -23,16 +32,78 @@ describe('{{date}} helper', function () {
},
data: {
site: {
timezone: 'Europe/Dublin'
timezone
}
}
};
let rendered;
testDates.forEach(function (d) {
const rendered = helpers.date.call({published_at: d}, context);
rendered = helpers.date.call({published_at: d}, context);
should.exist(rendered);
String(rendered).should.equal(moment(d).tz(timezones).format(format));
String(rendered).should.equal(moment(d).tz(timezone).format(format));
rendered = helpers.date.call({}, d, context);
should.exist(rendered);
String(rendered).should.equal(moment(d).tz(timezone).format(format));
});
// No date falls back to now
rendered = helpers.date.call({}, context);
should.exist(rendered);
String(rendered).should.equal(moment().tz(timezone).format(format));
});
it('creates properly localised date strings', function () {
const testDates = [
'2013-12-31T23:58:58.593+02:00',
'2014-01-01T00:28:58.593+11:00',
'2014-11-20T01:28:58.593-04:00',
'2014-03-01T01:28:58.593+00:00'
];
const locales = [
'en',
'en-gb',
'de'
];
const timezone = 'Europe/Dublin';
const format = 'll';
const context = {
hash: {},
data: {
site: {
timezone
}
}
};
locales.forEach(function (l) {
settingsCache.set('lang', {value: l});
proxy.themeI18n._loadLocale();
let rendered;
testDates.forEach(function (d) {
rendered = helpers.date.call({published_at: d}, context);
should.exist(rendered);
String(rendered).should.equal(moment(d).tz(timezone).locale(l).format(format));
rendered = helpers.date.call({}, d, context);
should.exist(rendered);
String(rendered).should.equal(moment(d).tz(timezone).locale(l).format(format));
});
// No date falls back to now
rendered = helpers.date.call({}, context);
should.exist(rendered);
String(rendered).should.equal(moment().tz(timezone).locale(l).format(format));
});
});
@ -44,7 +115,7 @@ describe('{{date}} helper', function () {
'2014-03-01T01:28:58.593+00:00'
];
const timezones = 'Europe/Dublin';
const timezone = 'Europe/Dublin';
const timeNow = moment().tz('Europe/Dublin');
const context = {
@ -53,16 +124,57 @@ describe('{{date}} helper', function () {
},
data: {
site: {
timezone: 'Europe/Dublin'
timezone
}
}
};
let rendered;
testDates.forEach(function (d) {
const rendered = helpers.date.call({published_at: d}, context);
rendered = helpers.date.call({published_at: d}, context);
should.exist(rendered);
String(rendered).should.equal(moment(d).tz(timezones).from(timeNow));
String(rendered).should.equal(moment(d).tz(timezone).from(timeNow));
rendered = helpers.date.call({}, d, context);
should.exist(rendered);
String(rendered).should.equal(moment(d).tz(timezone).from(timeNow));
});
// No date falls back to now
rendered = helpers.date.call({}, context);
should.exist(rendered);
String(rendered).should.equal('a few seconds ago');
});
it('ignores an invalid date, defaulting to now', function () {
const timezone = 'Europe/Dublin';
const timeNow = moment().tz('Europe/Dublin');
const context = {
hash: {
timeago: true
},
data: {
site: {
timezone
}
}
};
let invalidDate = 'Fred';
let rendered;
rendered = helpers.date.call({published_at: invalidDate}, context);
should.exist(rendered);
String(rendered).should.equal('a few seconds ago');
rendered = helpers.date.call({}, invalidDate, context);
should.exist(rendered);
String(rendered).should.equal('a few seconds ago');
});
});

View file

@ -6,10 +6,12 @@ const proxy = require('../../../core/frontend/services/proxy');
describe('{{lang}} helper', function () {
beforeEach(function () {
settingsCache.set('lang', {value: 'en'});
proxy.themeI18n._loadLocale();
});
afterEach(function () {
settingsCache.shutdown();
proxy.themeI18n._loadLocale();
});
it('returns correct language tag', function () {