diff --git a/assets/js/language-redirect.js b/assets/js/language-redirect.js index 767ce8fe..0391a65f 100644 --- a/assets/js/language-redirect.js +++ b/assets/js/language-redirect.js @@ -24,19 +24,62 @@ return ""; } - return value.trim().toLowerCase(); + return value.trim().toLowerCase().replace(/_/g, "-"); } - function normalizeLanguage(value) { - return normalizeLanguageTag(value).split("-")[0]; - } + function getBaseLanguage(value) { + var languageTag = normalizeLanguageTag(value); - function getTranslationLanguage(translation) { - if (!translation) { + if (!languageTag) { return ""; } - return normalizeLanguageTag(translation.lang || translation.languageCode); + return languageTag.split("-")[0]; + } + + function getTranslationTags(translation) { + if (!translation) { + return []; + } + + var tags = []; + var values = [translation.lang, translation.languageCode]; + + for (var i = 0; i < values.length; i += 1) { + var languageTag = normalizeLanguageTag(values[i]); + + if (languageTag && tags.indexOf(languageTag) === -1) { + tags.push(languageTag); + } + } + + return tags; + } + + function getCanonicalTranslationTag(translation) { + var tags = getTranslationTags(translation); + + if (!tags.length) { + return ""; + } + + return tags.reduce(function (bestTag, languageTag) { + if (languageTag.split("-").length > bestTag.split("-").length) { + return languageTag; + } + + return bestTag; + }, tags[0]); + } + + function translationHasTag(translation, languageTag) { + var normalizedTag = normalizeLanguageTag(languageTag); + + if (!normalizedTag) { + return false; + } + + return getTranslationTags(translation).indexOf(normalizedTag) !== -1; } function getAvailableTranslations() { @@ -45,45 +88,74 @@ } return config.translations.filter(function (translation) { - return translation && translation.url && normalizeLanguage(translation.lang || translation.languageCode); + return translation && translation.url && getTranslationTags(translation).length > 0; }); } var translations = getAvailableTranslations(); - function findTranslation(language) { - var languageTag = normalizeLanguageTag(language); - var baseLanguage = normalizeLanguage(language); + function findExactTranslation(languageTag) { + var normalizedTag = normalizeLanguageTag(languageTag); + + if (!normalizedTag) { + return null; + } + + for (var i = 0; i < translations.length; i += 1) { + if (translationHasTag(translations[i], normalizedTag)) { + return translations[i]; + } + } + + return null; + } + + function findBaseTranslation(languageTag) { + var baseLanguage = getBaseLanguage(languageTag); if (!baseLanguage) { return null; } for (var i = 0; i < translations.length; i += 1) { - var translation = translations[i]; + var tags = getTranslationTags(translations[i]); - if ( - normalizeLanguageTag(translation.lang) === languageTag || - normalizeLanguageTag(translation.languageCode) === languageTag - ) { - return translation; - } - } - - for (var j = 0; j < translations.length; j += 1) { - var baseTranslation = translations[j]; - - if ( - normalizeLanguage(baseTranslation.lang) === baseLanguage || - normalizeLanguage(baseTranslation.languageCode) === baseLanguage - ) { - return baseTranslation; + for (var j = 0; j < tags.length; j += 1) { + if (getBaseLanguage(tags[j]) === baseLanguage) { + return translations[i]; + } } } return null; } + function findBestTranslation(languageTag) { + var normalizedTag = normalizeLanguageTag(languageTag); + + if (!normalizedTag) { + return null; + } + + while (normalizedTag) { + var translation = findExactTranslation(normalizedTag); + + if (translation) { + return translation; + } + + var lastSubtagIndex = normalizedTag.lastIndexOf("-"); + + if (lastSubtagIndex === -1) { + break; + } + + normalizedTag = normalizedTag.slice(0, lastSubtagIndex); + } + + return findBaseTranslation(languageTag); + } + function getStoredLanguage() { if (!storage || config.storedLanguageRedirect !== true) { return null; @@ -114,7 +186,7 @@ } } - function getBrowserLanguage() { + function getBrowserTranslation() { var languages = []; if (Array.isArray(navigator.languages)) { @@ -126,15 +198,15 @@ } for (var i = 0; i < languages.length; i += 1) { - var baseLanguage = normalizeLanguage(languages[i]); + var translation = findBestTranslation(languages[i]); - if (findTranslation(baseLanguage)) { - return baseLanguage; + if (translation) { + return translation; } } - if (config.fallbackLanguage && findTranslation(config.fallbackLanguage)) { - return config.fallbackLanguage; + if (config.fallbackLanguage) { + return findBestTranslation(config.fallbackLanguage); } return null; @@ -156,15 +228,16 @@ } } - function redirectToLanguage(language) { - var translation = findTranslation(language); - + function redirectToTranslation(translation) { if (!translation || !translation.url) { return false; } - var currentLanguage = normalizeLanguageTag(config.currentLanguage || config.currentLanguageCode); - var targetLanguage = getTranslationLanguage(translation); + var currentLanguage = getCanonicalTranslationTag({ + lang: config.currentLanguage, + languageCode: config.currentLanguageCode + }); + var targetLanguage = getCanonicalTranslationTag(translation); if (currentLanguage && targetLanguage && currentLanguage === targetLanguage) { return false; @@ -180,6 +253,10 @@ return true; } + function redirectToLanguage(language) { + return redirectToTranslation(findBestTranslation(language)); + } + function findTranslationByUrl(url) { var linkUrl = getUrl(url); @@ -213,7 +290,7 @@ var translation = findTranslationByUrl(link.href); if (translation) { - setStoredLanguage(getTranslationLanguage(translation)); + setStoredLanguage(getCanonicalTranslationTag(translation)); } }); } @@ -230,10 +307,10 @@ return; } - var browserLanguage = getBrowserLanguage(); + var browserTranslation = getBrowserTranslation(); - if (browserLanguage) { - redirectToLanguage(browserLanguage); + if (browserTranslation) { + redirectToTranslation(browserTranslation); } }