Skip to content

Commit

Permalink
Use proper locale inheritance for the base locale
Browse files Browse the repository at this point in the history
Previously english locale was defined mostly in Locale.prototype. Now it's
moved in locale config (similar to all other locales) that is merged the same
way locales are patched (updated).

Fixes moment#3137
  • Loading branch information
ichernev committed Jun 16, 2016
1 parent 79597d1 commit 4c2342c
Show file tree
Hide file tree
Showing 8 changed files with 119 additions and 64 deletions.
56 changes: 56 additions & 0 deletions src/lib/locale/base-config.js
@@ -0,0 +1,56 @@
import { defaultCalendar } from './calendar';
import { defaultLongDateFormat } from './formats';
import { defaultInvalidDate } from './invalid';
import { defaultOrdinal, defaultOrdinalParse } from './ordinal';
import { defaultRelativeTime } from './relative';

// months
import {
defaultLocaleMonths,
defaultLocaleMonthsShort,
defaultMonthsRegex,
defaultMonthsShortRegex,
} from '../units/month';

// week
import { defaultLocaleWeek } from '../units/week';

// weekdays
import {
defaultLocaleWeekdays,
defaultLocaleWeekdaysMin,
defaultLocaleWeekdaysShort,

defaultWeekdaysRegex,
defaultWeekdaysShortRegex,
defaultWeekdaysMinRegex,
} from '../units/day-of-week';

// meridiem
import { defaultLocaleMeridiemParse } from '../units/hour';

export var baseConfig = {
calendar: defaultCalendar,
longDateFormat: defaultLongDateFormat,
invalidDate: defaultInvalidDate,
ordinal: defaultOrdinal,
ordinalParse: defaultOrdinalParse,
relativeTime: defaultRelativeTime,

months: defaultLocaleMonths,
monthsShort: defaultLocaleMonthsShort,
monthsRegex: defaultMonthsRegex,
monthsShortRegex: defaultMonthsShortRegex,

week: defaultLocaleWeek,

weekdays: defaultLocaleWeekdays,
weekdaysMin: defaultLocaleWeekdaysMin,
weekdaysShort: defaultLocaleWeekdaysShort,

weekdaysRegex: defaultWeekdaysRegex,
weekdaysShortRegex: defaultWeekdaysShortRegex,
weekdaysMinRegex: defaultWeekdaysMinRegex,

meridiemParse: defaultLocaleMeridiemParse
};
24 changes: 19 additions & 5 deletions src/lib/locale/locales.js
@@ -1,11 +1,14 @@
import isArray from '../utils/is-array';
import hasOwnProp from '../utils/has-own-prop';
import isUndefined from '../utils/is-undefined';
import compareArrays from '../utils/compare-arrays';
import { deprecateSimple } from '../utils/deprecate';
import { mergeConfigs } from './set';
import { Locale } from './constructor';
import keys from '../utils/keys';

import { baseConfig } from './base-config';

// internal storage for locale config files
var locales = {};
var globalLocale;
Expand Down Expand Up @@ -79,26 +82,35 @@ export function getSetGlobalLocale (key, values) {
return globalLocale._abbr;
}

function sanitizeLocaleConfig(config) {
if (!hasOwnProp(config, 'longDateFormat')) {
config.longDateFormat = {};
}
return config;
}

export function defineLocale (name, config) {
if (config !== null) {
config = sanitizeLocaleConfig(config);
var parentConfig = baseConfig;
config.abbr = name;
if (locales[name] != null) {
deprecateSimple('defineLocaleOverride',
'use moment.updateLocale(localeName, config) to change ' +
'an existing locale. moment.defineLocale(localeName, ' +
'config) should only be used for creating a new locale ' +
'See http://momentjs.com/guides/#/warnings/define-locale/ for more info.');
config = mergeConfigs(locales[name]._config, config);
parentConfig = locales[name]._config;
} else if (config.parentLocale != null) {
if (locales[config.parentLocale] != null) {
config = mergeConfigs(locales[config.parentLocale]._config, config);
parentConfig = locales[config.parentLocale]._config;
} else {
// treat as if there is no base config
deprecateSimple('parentLocaleUndefined',
'specified parentLocale is not defined yet. See http://momentjs.com/guides/#/warnings/parent-locale/');
}
}
locales[name] = new Locale(config);
locales[name] = new Locale(mergeConfigs(parentConfig, config));

// backwards compat for now: also set the locale
getSetGlobalLocale(name);
Expand All @@ -113,10 +125,12 @@ export function defineLocale (name, config) {

export function updateLocale(name, config) {
if (config != null) {
var locale;
var locale, parentConfig = baseConfig;
// MERGE
if (locales[name] != null) {
config = mergeConfigs(locales[name]._config, config);
parentConfig = locales[name]._config;
}
config = mergeConfigs(parentConfig, config);
locale = new Locale(config);
locale.parentLocale = locales[name];
locales[name] = locale;
Expand Down
52 changes: 17 additions & 35 deletions src/lib/locale/prototype.js
Expand Up @@ -2,86 +2,68 @@ import { Locale } from './constructor';

var proto = Locale.prototype;

import { defaultCalendar, calendar } from './calendar';
import { defaultLongDateFormat, longDateFormat } from './formats';
import { defaultInvalidDate, invalidDate } from './invalid';
import { defaultOrdinal, ordinal, defaultOrdinalParse } from './ordinal';
import { calendar } from './calendar';
import { longDateFormat } from './formats';
import { invalidDate } from './invalid';
import { ordinal } from './ordinal';
import { preParsePostFormat } from './pre-post-format';
import { defaultRelativeTime, relativeTime, pastFuture } from './relative';
import { relativeTime, pastFuture } from './relative';
import { set } from './set';

proto._calendar = defaultCalendar;
proto.calendar = calendar;
proto._longDateFormat = defaultLongDateFormat;
proto.longDateFormat = longDateFormat;
proto._invalidDate = defaultInvalidDate;
proto.invalidDate = invalidDate;
proto._ordinal = defaultOrdinal;
proto.ordinal = ordinal;
proto._ordinalParse = defaultOrdinalParse;
proto.preparse = preParsePostFormat;
proto.postformat = preParsePostFormat;
proto._relativeTime = defaultRelativeTime;
proto.relativeTime = relativeTime;
proto.pastFuture = pastFuture;
proto.set = set;

// Month
import {
localeMonthsParse,
defaultLocaleMonths, localeMonths,
defaultLocaleMonthsShort, localeMonthsShort,
defaultMonthsRegex, monthsRegex,
defaultMonthsShortRegex, monthsShortRegex
localeMonths,
localeMonthsShort,
monthsRegex,
monthsShortRegex
} from '../units/month';

proto.months = localeMonths;
proto._months = defaultLocaleMonths;
proto.monthsShort = localeMonthsShort;
proto._monthsShort = defaultLocaleMonthsShort;
proto.monthsParse = localeMonthsParse;
proto._monthsRegex = defaultMonthsRegex;
proto.monthsRegex = monthsRegex;
proto._monthsShortRegex = defaultMonthsShortRegex;
proto.monthsShortRegex = monthsShortRegex;

// Week
import { localeWeek, defaultLocaleWeek, localeFirstDayOfYear, localeFirstDayOfWeek } from '../units/week';
import { localeWeek, localeFirstDayOfYear, localeFirstDayOfWeek } from '../units/week';
proto.week = localeWeek;
proto._week = defaultLocaleWeek;
proto.firstDayOfYear = localeFirstDayOfYear;
proto.firstDayOfWeek = localeFirstDayOfWeek;

// Day of Week
import {
localeWeekdaysParse,
defaultLocaleWeekdays, localeWeekdays,
defaultLocaleWeekdaysMin, localeWeekdaysMin,
defaultLocaleWeekdaysShort, localeWeekdaysShort,
localeWeekdays,
localeWeekdaysMin,
localeWeekdaysShort,

defaultWeekdaysRegex, weekdaysRegex,
defaultWeekdaysShortRegex, weekdaysShortRegex,
defaultWeekdaysMinRegex, weekdaysMinRegex
weekdaysRegex,
weekdaysShortRegex,
weekdaysMinRegex
} from '../units/day-of-week';

proto.weekdays = localeWeekdays;
proto._weekdays = defaultLocaleWeekdays;
proto.weekdaysMin = localeWeekdaysMin;
proto._weekdaysMin = defaultLocaleWeekdaysMin;
proto.weekdaysShort = localeWeekdaysShort;
proto._weekdaysShort = defaultLocaleWeekdaysShort;
proto.weekdaysParse = localeWeekdaysParse;

proto._weekdaysRegex = defaultWeekdaysRegex;
proto.weekdaysRegex = weekdaysRegex;
proto._weekdaysShortRegex = defaultWeekdaysShortRegex;
proto.weekdaysShortRegex = weekdaysShortRegex;
proto._weekdaysMinRegex = defaultWeekdaysMinRegex;
proto.weekdaysMinRegex = weekdaysMinRegex;

// Hours
import { localeIsPM, defaultLocaleMeridiemParse, localeMeridiem } from '../units/hour';
import { localeIsPM, localeMeridiem } from '../units/hour';

proto.isPM = localeIsPM;
proto._meridiemParse = defaultLocaleMeridiemParse;
proto.meridiem = localeMeridiem;
3 changes: 2 additions & 1 deletion src/lib/units/day-of-week.js
Expand Up @@ -294,7 +294,8 @@ export function weekdaysShortRegex (isStrict) {
export var defaultWeekdaysMinRegex = matchWord;
export function weekdaysMinRegex (isStrict) {
if (this._weekdaysParseExact) {
if (!hasOwnProp(this, '_weekdaysRegex')) {
if (!hasOwnProp(this, '_weekdaysRegex') ||
this._weekdaysRegex === defaultWeekdaysRegex) {
computeWeekdaysParse.call(this);
}
if (isStrict) {
Expand Down
8 changes: 5 additions & 3 deletions src/lib/units/month.js
Expand Up @@ -199,10 +199,12 @@ export function getDaysInMonth () {
return daysInMonth(this.year(), this.month());
}

export var defaultMonthsRegex = matchWord;
export var defaultMonthsShortRegex = matchWord;
export function monthsShortRegex (isStrict) {
if (this._monthsParseExact) {
if (!hasOwnProp(this, '_monthsRegex')) {
if (!hasOwnProp(this, '_monthsRegex') ||
this._monthsRegex === defaultMonthsRegex) {
computeMonthsParse.call(this);
}
if (isStrict) {
Expand All @@ -216,10 +218,10 @@ export function monthsShortRegex (isStrict) {
}
}

export var defaultMonthsRegex = matchWord;
export function monthsRegex (isStrict) {
if (this._monthsParseExact) {
if (!hasOwnProp(this, '_monthsRegex')) {
if (!hasOwnProp(this, '_monthsRegex') ||
this._monthsRegex === defaultMonthsRegex) {
computeMonthsParse.call(this);
}
if (isStrict) {
Expand Down
4 changes: 2 additions & 2 deletions src/test/helpers/common-locale.js
Expand Up @@ -113,7 +113,7 @@ export function defineCommonLocaleTests(locale, options) {
return;
}
function tester(format) {
var r, baseMsg = 'weekday ' + m.weekday() + ' fmt ' + format;
var r, baseMsg = 'weekday ' + m.weekday() + ' fmt ' + format + ' ' + m.toISOString();
r = moment(m.format(format), format);
assert.equal(r.weekday(), m.weekday(), baseMsg);
r = moment(m.format(format).toLocaleUpperCase(), format);
Expand All @@ -130,7 +130,7 @@ export function defineCommonLocaleTests(locale, options) {
}

for (i = 0; i < 7; ++i) {
m = moment.utc([2015, i, 15, 18]);
m = moment.utc([2015, 0, i + 1, 18]);
tester('dd');
tester('ddd');
tester('dddd');
Expand Down
18 changes: 9 additions & 9 deletions src/test/moment/locale_inheritance.js
Expand Up @@ -142,15 +142,15 @@ test('ordinal parse', function (assert) {

assert.ok(moment.utc('2015-01-1y', 'YYYY-MM-Do', true).isValid(), 'ordinal parse uses child');

moment.defineLocale('base-ordinal-parse-2', {
ordinalParse : /\d{1,2}x/
});
moment.defineLocale('child-ordinal-parse-2', {
parentLocale: 'base-ordinal-parse-2',
ordinalParse : null
});

assert.ok(moment.utc('2015-01-1', 'YYYY-MM-Do', true).isValid(), 'ordinal parse uses child (default)');
// moment.defineLocale('base-ordinal-parse-2', {
// ordinalParse : /\d{1,2}x/
// });
// moment.defineLocale('child-ordinal-parse-2', {
// parentLocale: 'base-ordinal-parse-2',
// ordinalParse : null
// });

// assert.ok(moment.utc('2015-01-1', 'YYYY-MM-Do', true).isValid(), 'ordinal parse uses child (default)');
});

test('months', function (assert) {
Expand Down
18 changes: 9 additions & 9 deletions src/test/moment/locale_update.js
Expand Up @@ -142,15 +142,15 @@ test('ordinal parse', function (assert) {

assert.ok(moment.utc('2015-01-1y', 'YYYY-MM-Do', true).isValid(), 'ordinal parse uses child');

moment.defineLocale('ordinal-parse-2', null);
moment.defineLocale('ordinal-parse-2', {
ordinalParse : /\d{1,2}x/
});
moment.updateLocale('ordinal-parse-2', {
ordinalParse : null
});

assert.ok(moment.utc('2015-01-1', 'YYYY-MM-Do', true).isValid(), 'ordinal parse uses child (default)');
// moment.defineLocale('ordinal-parse-2', null);
// moment.defineLocale('ordinal-parse-2', {
// ordinalParse : /\d{1,2}x/
// });
// moment.updateLocale('ordinal-parse-2', {
// ordinalParse : null
// });

// assert.ok(moment.utc('2015-01-1', 'YYYY-MM-Do', true).isValid(), 'ordinal parse uses child (default)');
});

test('months', function (assert) {
Expand Down

0 comments on commit 4c2342c

Please sign in to comment.