1
This commit is contained in:
@@ -0,0 +1,248 @@
|
||||
import isArray from '../utils/is-array';
|
||||
import isUndefined from '../utils/is-undefined';
|
||||
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 = {},
|
||||
localeFamilies = {},
|
||||
globalLocale;
|
||||
|
||||
function commonPrefix(arr1, arr2) {
|
||||
var i,
|
||||
minl = Math.min(arr1.length, arr2.length);
|
||||
for (i = 0; i < minl; i += 1) {
|
||||
if (arr1[i] !== arr2[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return minl;
|
||||
}
|
||||
|
||||
function normalizeLocale(key) {
|
||||
return key ? key.toLowerCase().replace('_', '-') : key;
|
||||
}
|
||||
|
||||
// pick the locale from the array
|
||||
// try ['en-au', 'en-gb'] as 'en-au', 'en-gb', 'en', as in move through the list trying each
|
||||
// substring from most specific to least, but move to the next array item if it's a more specific variant than the current root
|
||||
function chooseLocale(names) {
|
||||
var i = 0,
|
||||
j,
|
||||
next,
|
||||
locale,
|
||||
split;
|
||||
|
||||
while (i < names.length) {
|
||||
split = normalizeLocale(names[i]).split('-');
|
||||
j = split.length;
|
||||
next = normalizeLocale(names[i + 1]);
|
||||
next = next ? next.split('-') : null;
|
||||
while (j > 0) {
|
||||
locale = loadLocale(split.slice(0, j).join('-'));
|
||||
if (locale) {
|
||||
return locale;
|
||||
}
|
||||
if (
|
||||
next &&
|
||||
next.length >= j &&
|
||||
commonPrefix(split, next) >= j - 1
|
||||
) {
|
||||
//the next array item is better than a shallower substring of this one
|
||||
break;
|
||||
}
|
||||
j--;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
return globalLocale;
|
||||
}
|
||||
|
||||
function isLocaleNameSane(name) {
|
||||
// Prevent names that look like filesystem paths, i.e contain '/' or '\'
|
||||
return name.match('^[^/\\\\]*$') != null;
|
||||
}
|
||||
|
||||
function loadLocale(name) {
|
||||
var oldLocale = null,
|
||||
aliasedRequire;
|
||||
// TODO: Find a better way to register and load all the locales in Node
|
||||
if (
|
||||
locales[name] === undefined &&
|
||||
typeof module !== 'undefined' &&
|
||||
module &&
|
||||
module.exports &&
|
||||
isLocaleNameSane(name)
|
||||
) {
|
||||
try {
|
||||
oldLocale = globalLocale._abbr;
|
||||
aliasedRequire = require;
|
||||
aliasedRequire('./locale/' + name);
|
||||
getSetGlobalLocale(oldLocale);
|
||||
} catch (e) {
|
||||
// mark as not found to avoid repeating expensive file require call causing high CPU
|
||||
// when trying to find en-US, en_US, en-us for every format call
|
||||
locales[name] = null; // null means not found
|
||||
}
|
||||
}
|
||||
return locales[name];
|
||||
}
|
||||
|
||||
// This function will load locale and then set the global locale. If
|
||||
// no arguments are passed in, it will simply return the current global
|
||||
// locale key.
|
||||
export function getSetGlobalLocale(key, values) {
|
||||
var data;
|
||||
if (key) {
|
||||
if (isUndefined(values)) {
|
||||
data = getLocale(key);
|
||||
} else {
|
||||
data = defineLocale(key, values);
|
||||
}
|
||||
|
||||
if (data) {
|
||||
// moment.duration._locale = moment._locale = data;
|
||||
globalLocale = data;
|
||||
} else {
|
||||
if (typeof console !== 'undefined' && console.warn) {
|
||||
//warn user if arguments are passed but the locale could not be set
|
||||
console.warn(
|
||||
'Locale ' + key + ' not found. Did you forget to load it?'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return globalLocale._abbr;
|
||||
}
|
||||
|
||||
export function defineLocale(name, config) {
|
||||
if (config !== null) {
|
||||
var locale,
|
||||
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.'
|
||||
);
|
||||
parentConfig = locales[name]._config;
|
||||
} else if (config.parentLocale != null) {
|
||||
if (locales[config.parentLocale] != null) {
|
||||
parentConfig = locales[config.parentLocale]._config;
|
||||
} else {
|
||||
locale = loadLocale(config.parentLocale);
|
||||
if (locale != null) {
|
||||
parentConfig = locale._config;
|
||||
} else {
|
||||
if (!localeFamilies[config.parentLocale]) {
|
||||
localeFamilies[config.parentLocale] = [];
|
||||
}
|
||||
localeFamilies[config.parentLocale].push({
|
||||
name: name,
|
||||
config: config,
|
||||
});
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
locales[name] = new Locale(mergeConfigs(parentConfig, config));
|
||||
|
||||
if (localeFamilies[name]) {
|
||||
localeFamilies[name].forEach(function (x) {
|
||||
defineLocale(x.name, x.config);
|
||||
});
|
||||
}
|
||||
|
||||
// backwards compat for now: also set the locale
|
||||
// make sure we set the locale AFTER all child locales have been
|
||||
// created, so we won't end up with the child locale set.
|
||||
getSetGlobalLocale(name);
|
||||
|
||||
return locales[name];
|
||||
} else {
|
||||
// useful for testing
|
||||
delete locales[name];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export function updateLocale(name, config) {
|
||||
if (config != null) {
|
||||
var locale,
|
||||
tmpLocale,
|
||||
parentConfig = baseConfig;
|
||||
|
||||
if (locales[name] != null && locales[name].parentLocale != null) {
|
||||
// Update existing child locale in-place to avoid memory-leaks
|
||||
locales[name].set(mergeConfigs(locales[name]._config, config));
|
||||
} else {
|
||||
// MERGE
|
||||
tmpLocale = loadLocale(name);
|
||||
if (tmpLocale != null) {
|
||||
parentConfig = tmpLocale._config;
|
||||
}
|
||||
config = mergeConfigs(parentConfig, config);
|
||||
if (tmpLocale == null) {
|
||||
// updateLocale is called for creating a new locale
|
||||
// Set abbr so it will have a name (getters return
|
||||
// undefined otherwise).
|
||||
config.abbr = name;
|
||||
}
|
||||
locale = new Locale(config);
|
||||
locale.parentLocale = locales[name];
|
||||
locales[name] = locale;
|
||||
}
|
||||
|
||||
// backwards compat for now: also set the locale
|
||||
getSetGlobalLocale(name);
|
||||
} else {
|
||||
// pass null for config to unupdate, useful for tests
|
||||
if (locales[name] != null) {
|
||||
if (locales[name].parentLocale != null) {
|
||||
locales[name] = locales[name].parentLocale;
|
||||
if (name === getSetGlobalLocale()) {
|
||||
getSetGlobalLocale(name);
|
||||
}
|
||||
} else if (locales[name] != null) {
|
||||
delete locales[name];
|
||||
}
|
||||
}
|
||||
}
|
||||
return locales[name];
|
||||
}
|
||||
|
||||
// returns locale data
|
||||
export function getLocale(key) {
|
||||
var locale;
|
||||
|
||||
if (key && key._locale && key._locale._abbr) {
|
||||
key = key._locale._abbr;
|
||||
}
|
||||
|
||||
if (!key) {
|
||||
return globalLocale;
|
||||
}
|
||||
|
||||
if (!isArray(key)) {
|
||||
//short-circuit everything else
|
||||
locale = loadLocale(key);
|
||||
if (locale) {
|
||||
return locale;
|
||||
}
|
||||
key = [key];
|
||||
}
|
||||
|
||||
return chooseLocale(key);
|
||||
}
|
||||
|
||||
export function listLocales() {
|
||||
return keys(locales);
|
||||
}
|
||||
Reference in New Issue
Block a user