/* global SCS, SCSRenderAPI */ export default class Localization { constructor(args) { this.SiteUtils = args.SiteUtils; this.isCompilation = !!args.SCSCompileAPI; this.SCSCompileAPI = args.SCSCompileAPI; if (this.isCompilation) { this.SCSCompileAPI.getContentClient().then((contentClient) => { this.contentClient = contentClient; }); } else { this.contentClient = window.SCSRenderAPI.getContentClient(); } this.POLICY = { LANGUAGE: 'LANGUAGE', PARENT: 'PARENT', DOMAIN: 'DOMAIN', LOCALE: 'LOCALE', }; } getSiteUtils() { if (this.isCompilation) { return this.SiteUtils; } else { return window.SiteUtils; } } /** * Returns contentClient. Sets `this.contentClient` if undefined/not initialized * * @returns ContentClient */ getContentClient() { if (this.contentClient) return this.contentClient; if (this.isCompilation) { return new Promise(function (resolve, reject) { this.SCSCompileAPI.getContentClient() .then((contentClient) => { resolve(contentClient); }) .catch(function (err) { reject(err); }); }) .then((contentClient) => { this.contentClient = contentClient; return this.contentClient; }) .catch(function (err) { console.log('ERROR:FATAL:GET:CONTENT:CLIENT', err); throw err; }); } else { this.contentClient = window.SCSRenderAPI.getContentClient(); return this.contentClient; } } getLanguageFromLocale(locale) { let languageCode = locale ? locale : ''; const languageCodeSplit = languageCode.split('-'); languageCode = languageCodeSplit[0]; return languageCode; } getCountryCodeFromLocale(locale) { let countryCode = ''; const localeSplit = locale.split('-'); if (localeSplit.length > 1) { countryCode = localeSplit[localeSplit.length - 1].toLowerCase(); } else { countryCode = ''; } return countryCode; } /** * Returns fallback language - the param raw converts to OCM system language * * @param {any} languageCode * @param {true | false} raw * @returns */ getLanguageFallback(languageCode, raw) { let languageFallback = undefined; if (this.isCompilation) { languageFallback = this.SCSCompileAPI.siteInfo.properties.localeFallbacks && this.SCSCompileAPI.siteInfo.properties.localeFallbacks[languageCode]; } else { languageFallback = window.SCSRenderAPI.siteInfo.properties.localeFallbacks && window.SCSRenderAPI.siteInfo.properties.localeFallbacks[languageCode]; } if (raw) { // languageFallback can arrive as en-IT but we need to recode as en-x-IT //below code transforms where needed en-IT into en-x-IT if (this.isCompilation) { languageFallback = this.SCSCompileAPI.siteInfo.properties.localeAliases[languageFallback] || languageFallback; } else { languageFallback = window.SCS.siteInfo.properties.localeAliases[languageFallback] || languageFallback; } } return languageFallback || 'en'; } /** * @param {IR | RAW | ISO} mode * @returns IR: lg-rg, RAW: lg-x-RG|lg-RG, ISO: lg-RG */ getPageLanguageCode(mode = 'ND') { let localCode = 'en'; if (this.isCompilation) { localCode = this.SCSCompileAPI.pageLocale || localCode; } else { localCode = (window.SCSRenderAPI && window.SCSRenderAPI.getPageLocaleAlias()) || window.SCS.localeAlias || window.SCS.pageLanguageCode || localCode; } mode = mode.toUpperCase(); if (mode == 'IR') { localCode = localCode.toLowerCase(); } if (mode == 'RAW') { if (this.isCompilation) { localCode = this.SCSCompileAPI.siteInfo.properties.localeAliases[localCode] || localCode; } else { localCode = window.SCS.siteInfo.properties.localeAliases[localCode] || localCode; } } if (mode == 'ISO') { if (this.isCompilation) { localCode = this.SCSCompileAPI.siteInfo.properties.localeAliases[localCode] || localCode; } else { localCode = window.SCS.siteInfo.properties.localeAliases[localCode] || localCode; } if (localCode.indexOf('-x-') > -1) { const ls = localCode.split('-x-'); if (ls.length > 0) { localCode = ls[0] + '-' + ls[ls.length - 1].toUpperCase(); } } } console.log('LOCALIZE:MODE:PAGELANG', mode, localCode); return localCode; } /** * Queries the correct language version of an asset for a given page. * * @param {content Object} contentItemData * @returns */ getLanguageAsset(contentItemData) { console.log('GET:LANGUAGE:ASSET'); const self = this; if (contentItemData === undefined || contentItemData == null || contentItemData.length <= 0) { console.log('CHECKFALLBACKS:EMPTY:OBJECT'); return contentItemData; } const contentLg = contentItemData.language; //en-x-IT||en-US||fr-FR||etc.. const _pageLang = this.getPageLanguageCode('RAW'); //en-x-IT||en-US||fr-FR||etc.. const _fallLang = this.getLanguageFallback(_pageLang, true); return new Promise(function (resolve, reject) { if (contentLg != _pageLang) { if (contentLg != _fallLang) { const contentClient = self.getContentClient(); return contentClient .getItem({ id: contentItemData.id, language: _fallLang, }) .then((contentItemResp) => { contentItemData = contentItemResp; console.log('RESOLVING:CONTENTLANG:NE:FALLBACKLANG', contentItemData.language); resolve(contentItemData); }) .catch(function (err) { console.log('ERROR:FATAL:GET:ITEM:', err); reject(err); }); } else { console.log('RESOLVING:CONTENTLANG:EQ:FALLBACKLANG'); resolve(contentItemData); } } else { console.log('RESOLVING:CONTENTLANG:EQ:PAGELANG'); resolve(contentItemData); } }).catch(function (err) { console.log('ERROR:FATAL:GET:CONTENT:ITEM:', err); throw err; }); } checkFallback(contentItemData) { console.log('CHECKFALLBACKS'); const self = this; const _pageLang = this.getPageLanguageCode('RAW'); return this.getLanguageAsset(contentItemData) .then(function (result) { let hideItem = false; contentItemData = result; console.log('CHECKREGIONALIZE', contentItemData?.fields?.flag_regionalize); if (contentItemData?.fields?.flag_regionalize) { //Checking regionalization based on Sales Channel hideItem = self.getSiteUtils().regionalize(contentItemData); } return hideItem; }) .then((result) => { console.log('RESOLVEDREGIONALIZE:HIDE:', result); if (result) { // This is regionalization based on sales channel which redirect to parent contentItemData.redirect = { flag: true, policy: this.POLICY.PARENT }; } else { if (contentItemData.language == 'en' && !_pageLang.startsWith('en')) { contentItemData.redirect = { flag: true, policy: this.POLICY.LANGUAGE, language: contentItemData.language, }; } } return contentItemData; }) .catch(function (err) { //this is same as (err) => {} console.log('CHECKINGFALLBACK:ERROR', err); return contentItemData; }); } /** * - Correct language format: en-x-IT, en-GB. * - Incorrect language format: en-it, en-gb. * - The method valids against localeAliases in site settings. * - Input (en-x-IT, en-GB) -> Output (en-it, en-gb) Input (en-it, en-gb) -> Output (undefined, undefined) * * @param {string} value - Should be OCM system language * @returns */ getAliasLanguage(value) { const object = SCS.siteInfo.properties.localeAliases; return Object.keys(object).find((key) => object[key] === value); } /** * The method redirects to a URL (200 JS redirect) * * @param {string} url * @returns */ executeRedirectUrl(url) { console.log('REDIRECT:', url); if (url) { const currentSearchStr = Localization.getQueryStringFromCurrentLocation(); const urlWithParams = Localization.addSearchStringToUrl(url, currentSearchStr); window.location.replace(urlWithParams); return 1; } return 0; } /** * Gets the locale from the url. Checks for a locale at the start of the url, like /en/ or /en-us/. * * @param {string} url * @returns {string} */ getLocaleFromUrl(url) { // Create a regular expression to match a locale, like /en/ or /en-us/, at the start of the url. const localeRegex = /^\/([a-z]{2}(-[a-z]{2})?)\//; const match = url.match(localeRegex); return match ? match[1] : ''; } /** * Redirects to a given locale, example will redirect from * * - Www.doamin.com/lg-rg/page to www.doamin.com/newlg-newrg/page * - Www.doamin.com/page to www.doamin.com/newlg-newrg/page * * @param {string} localeTarget - Eg. en-us etc * @returns */ redirectToLocale(localeTarget) { console.log('LOCALE:REDIRECT:START:', localeTarget); //validate the locale if in format lg-rg against the localAliases of site settings. if (localeTarget && localeTarget.indexOf('-') > -1) { localeTarget = SCS.siteInfo.properties.localeAliases[localeTarget] ? localeTarget : ''; } if (localeTarget) { console.log('LOCALE:REDIRECT:VALID:', localeTarget); const pageLanguage = this.getPageLanguageCode('ir'); const localeFromUrl = this.getLocaleFromUrl(window.location.pathname); if (localeFromUrl.toLowerCase().includes(pageLanguage.toLowerCase())) { const urlSplitted = window.location.href.split('/' + pageLanguage); const newLocation = urlSplitted[0] + '/' + localeTarget + urlSplitted[1]; return this.executeRedirectUrl(newLocation); } else { if ( SCSRenderAPI.sitePrefix && SCSRenderAPI.sitePrefix != '/' && SCSRenderAPI.sitePrefix.indexOf('site') > -1 ) { const urlSplitted = window.location.pathname.split(SCSRenderAPI.sitePrefix); const newLocation = SCSRenderAPI.sitePrefix + localeTarget + '/' + urlSplitted[1]; return this.executeRedirectUrl(newLocation); } else { const urlSplitted = window.location.pathname.split(SCSRenderAPI.sitePrefix); let newLocation = SCSRenderAPI.sitePrefix + localeTarget; for (let u = 0; u < urlSplitted.length; u++) { if (urlSplitted[u]) { newLocation = newLocation + '/' + urlSplitted[u]; } } return this.executeRedirectUrl(newLocation); } } } return 0; } /** * Redirects to a given language code replacing the existing language in the page The region is picked from the * existing language URL of the page. * * @param {string} langCodeTarget - Eg. en, it etc * @returns */ redirectToLanguageVersion(langCodeTarget) { console.log('LANGUAGE:REDIRECT:START:', langCodeTarget); if (langCodeTarget && ['view', 'preview'].indexOf(this.view) > -1) { const pageLanguage = this.getPageLanguageCode('ir'); let countryCode; if (langCodeTarget && langCodeTarget.indexOf('-') > -1) { countryCode = this.getCountryCodeFromLocale(langCodeTarget) || ''; langCodeTarget = this.getLanguageFromLocale(langCodeTarget); } else { countryCode = this.getCountryCodeFromLocale(pageLanguage) || ''; langCodeTarget = this.getLanguageFromLocale(langCodeTarget); } countryCode = countryCode ? countryCode.toLowerCase() : ''; if (countryCode && SCS.siteInfo.properties.localeAliases[langCodeTarget + '-' + countryCode]) { langCodeTarget = langCodeTarget + '-' + countryCode; } langCodeTarget = langCodeTarget || 'en'; console.log('LANGUAGE:REDIRECT:FINAL:', langCodeTarget); return this.redirectToLocale(langCodeTarget); } return 0; } /** * Retrieves the parent page from the structure MAP of the site. * * @returns PageId */ getParentPageId() { const HOMEPAGEID = 12; if (this.scsData) { const currentPageId = SCSRenderAPI.getPageId(); const node = SCS.structureMap[currentPageId]; return node.parentId; } else { return HOMEPAGEID; } } redirectToParentPage() { if (['view', 'preview'].indexOf(this.view) > -1) { console.log('PRODUCTPAGE:RIDIRECT:PARENTPAGE'); const HOMEPAGEID = 12; const currentPageId = SCSRenderAPI.getPageId(); const _parentPageId = this.getParentPageId(); if (currentPageId != HOMEPAGEID && currentPageId != _parentPageId) { const _pageLinkData = SCSRenderAPI.getPageLinkData(_parentPageId); return this.executeRedirectUrl(_pageLinkData.href); } return 0; } } /** * Redirects to the HOME page of the site. * * @returns 1/0 */ redirectToHomePage() { if (['view', 'preview'].indexOf(this.view) > -1) { console.log('PRODUCTPAGE:RIDIRECT:HOME'); const HOMEPAGEID = 12; const currentPageId = SCSRenderAPI.getPageId(); if (currentPageId != HOMEPAGEID) { const _pageLinkData = SCSRenderAPI.getPageLinkData(HOMEPAGEID); return this.executeRedirectUrl(_pageLinkData.href); } } return 0; } redirectToLastNavigation() { if (['view', 'preview'].indexOf(this.view) > -1) { console.log('PRODUCTPAGE:RIDIRECT:LASTNAVIGATION'); return this.executeRedirectUrl(document.referrer); } return 0; } /** @param {array [Boolean redirect, String location, String language]} redirect */ redirect(model) { let outcome = 0; this.view = SCSRenderAPI.getRenderMode(); if (['view', 'preview'].indexOf(this.view) > -1) { const redirect = model && model.redirect; if (redirect && redirect.flag == true && redirect.policy) { const policy = redirect.policy; if (policy == this.POLICY.LANGUAGE && (redirect.language || model.language)) { const language = redirect.language || model.language; outcome = this.redirectToLanguageVersion(language); if (outcome == 0) { outcome = this.redirectToParentPage(); } if (outcome == 0) { outcome = this.redirectToHomePage(); } } else if (policy == this.POLICY.PARENT) { outcome = this.redirectToParentPage(); if (outcome == 0) { outcome = this.redirectToHomePage(); } } else if (policy == this.POLICY.DOMAIN && redirect.url) { if (['view'].indexOf(this.view) > -1) { outcome = 1; return this.executeRedirectUrl(redirect.url); } } else if (policy == this.POLICY.LOCALE && redirect.locale) { const locale = redirect.locale || 'en'; outcome = this.redirectToLocale(locale); if (outcome == 0) { outcome = this.redirectToParentPage(); } if (outcome == 0) { outcome = this.redirectToHomePage(); } } else { console.log('UNKNOWN:POLICY'); } } else { //backward compatibility which always redirects to parent page outcome = this.redirectToParentPage(); if (outcome == 0) { outcome = this.redirectToHomePage(); } } } return outcome; } getPolicy(policy) { if (this.POLICY[policy]) { return this.POLICY[policy]; } else { return 'UNKNOWN'; } } /** @returns {string} Query string */ static getQueryStringFromCurrentLocation() { return window.location.search; } /** * Returns URL with query params. Returns original URL if no query params are present or if URL already contains * query params. * * @param {string} url * @param {string | undefined} searchStr * @returns */ static addSearchStringToUrl(url, searchStr) { if (!searchStr) { return url; } if (url.includes('?')) { return url; } if (searchStr.startsWith('?')) { return url + searchStr; } return url + '?' + searchStr; } }