Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The language option now has a clearly defined fallback chain #5602

Merged
merged 8 commits into from Aug 14, 2019
168 changes: 114 additions & 54 deletions src/js/select2/defaults.js
Expand Up @@ -232,66 +232,29 @@ define([
);
}

if (typeof options.language === 'string') {
// Check if the language is specified with a region
if (options.language.indexOf('-') > 0) {
// Extract the region information if it is included
var languageParts = options.language.split('-');
var baseLanguage = languageParts[0];

options.language = [options.language, baseLanguage];
} else {
options.language = [options.language];
}
}

if ($.isArray(options.language)) {
var languages = new Translation();
options.language.push('en');

var languageNames = options.language;
// If the defaults were not previously applied from an element, it is
// possible for the language option to have not been resolved
options.language = this._resolveLanguage(options.language);

for (var l = 0; l < languageNames.length; l++) {
var name = languageNames[l];
var language = {};
// Always fall back to English since it will always be complete
options.language.push('en');

try {
// Try to load it with the original name
language = Translation.loadPath(name);
} catch (e) {
try {
// If we couldn't load it, check if it wasn't the full path
name = this.defaults.amdLanguageBase + name;
language = Translation.loadPath(name);
} catch (ex) {
// The translation could not be loaded at all. Sometimes this is
// because of a configuration problem, other times this can be
// because of how Select2 helps load all possible translation files.
if (options.debug && window.console && console.warn) {
console.warn(
'Select2: The language file for "' + name + '" could not be ' +
'automatically loaded. A fallback will be used instead.'
);
}
var uniqueLanguages = [];

continue;
}
}
for (var l = 0; l < options.language.length; l++) {
var language = options.language[l];

languages.extend(language);
if (uniqueLanguages.indexOf(language) === -1) {
uniqueLanguages.push(language);
}
}

options.translations = languages;
} else {
var baseTranslation = Translation.loadPath(
this.defaults.amdLanguageBase + 'en'
);
var customTranslation = new Translation(options.language);

customTranslation.extend(baseTranslation);
options.language = uniqueLanguages;

options.translations = customTranslation;
}
options.translations = this._processTranslations(
options.language,
options.debug
);

return options;
};
Expand Down Expand Up @@ -358,7 +321,7 @@ define([
debug: false,
dropdownAutoWidth: false,
escapeMarkup: Utils.escapeMarkup,
language: EnglishTranslation,
language: {},
matcher: matcher,
minimumInputLength: 0,
maximumInputLength: 0,
Expand All @@ -380,6 +343,103 @@ define([
};
};

Defaults.prototype.applyFromElement = function (options, $element) {
var optionLanguage = options.language;
var defaultLanguage = this.defaults.language;
var elementLanguage = $element.prop('lang');
var parentLanguage = $element.closest('[lang]').prop('lang');

var languages = Array.prototype.concat.call(
this._resolveLanguage(elementLanguage),
this._resolveLanguage(optionLanguage),
this._resolveLanguage(defaultLanguage),
this._resolveLanguage(parentLanguage)
);

options.language = languages;

return options;
};

Defaults.prototype._resolveLanguage = function (language) {
if (!language) {
return [];
}

if ($.isEmptyObject(language)) {
return [];
}

if ($.isPlainObject(language)) {
return [language];
}

var languages;

if (!$.isArray(language)) {
languages = [language];
} else {
languages = language;
}

var resolvedLanguages = [];

for (var l = 0; l < languages.length; l++) {
resolvedLanguages.push(languages[l]);

if (typeof languages[l] === 'string' && languages[l].indexOf('-') > 0) {
// Extract the region information if it is included
var languageParts = languages[l].split('-');
var baseLanguage = languageParts[0];

resolvedLanguages.push(baseLanguage);
}
}

return resolvedLanguages;
};

Defaults.prototype._processTranslations = function (languages, debug) {
var translations = new Translation();

for (var l = 0; l < languages.length; l++) {
var languageData = new Translation();

var language = languages[l];

if (typeof language === 'string') {
try {
// Try to load it with the original name
languageData = Translation.loadPath(language);
} catch (e) {
try {
// If we couldn't load it, check if it wasn't the full path
language = this.defaults.amdLanguageBase + language;
languageData = Translation.loadPath(language);
} catch (ex) {
// The translation could not be loaded at all. Sometimes this is
// because of a configuration problem, other times this can be
// because of how Select2 helps load all possible translation files
if (debug && window.console && console.warn) {
console.warn(
'Select2: The language file for "' + language + '" could ' +
'not be automatically loaded. A fallback will be used instead.'
);
}
}
}
} else if ($.isPlainObject(language)) {
languageData = new Translation(language);
} else {
languageData = language;
}

translations.extend(languageData);
}

return translations;
};

Defaults.prototype.set = function (key, value) {
var camelKey = $.camelCase(key);

Expand Down
12 changes: 4 additions & 8 deletions src/js/select2/options.js
Expand Up @@ -11,6 +11,10 @@ define([
this.fromElement($element);
}

if ($element != null) {
this.options = Defaults.applyFromElement(this.options, $element);
}

this.options = Defaults.apply(this.options);

if ($element && $element.is('input')) {
Expand All @@ -34,14 +38,6 @@ define([
this.options.disabled = $e.prop('disabled');
}

if (this.options.language == null) {
if ($e.prop('lang')) {
this.options.language = $e.prop('lang').toLowerCase();
} else if ($e.closest('[lang]').prop('lang')) {
this.options.language = $e.closest('[lang]').prop('lang');
}
}

if (this.options.dir == null) {
if ($e.prop('dir')) {
this.options.dir = $e.prop('dir');
Expand Down