@wix/headless-localization-utils 1.0.5 → 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/index.cjs CHANGED
@@ -21,6 +21,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
23
  MULTILINGUAL_COOKIE_HEADER_KEY: () => MULTILINGUAL_COOKIE_HEADER_KEY,
24
+ applyLanguageToUrl: () => applyLanguageToUrl,
24
25
  getLocalizationData: () => getLocalizationData
25
26
  });
26
27
  module.exports = __toCommonJS(index_exports);
@@ -44,6 +45,29 @@ var buildLocaleString = (locale) => {
44
45
  var getLanguageFromQueryParam = (url) => url.searchParams.get("lang") ?? void 0;
45
46
  var getLanguageFromSubfolder = (url) => url.pathname.split("/")[1];
46
47
  var getLanguageFromSubdomain = (url) => url.hostname.split(".")[0];
48
+ var applyQueryParamLanguage = (url, languageCode) => {
49
+ url.searchParams.set("lang", languageCode);
50
+ };
51
+ var applySubdomainLanguage = (url, languageCode) => {
52
+ let hostnameParts = url.hostname.split(".");
53
+ if (hostnameParts[0] === "www") {
54
+ hostnameParts = hostnameParts.slice(1);
55
+ }
56
+ hostnameParts = [languageCode, ...hostnameParts];
57
+ url.hostname = hostnameParts.join(".");
58
+ };
59
+ var applySubfolderLanguage = (url, languageCode) => {
60
+ url.pathname = `/${languageCode}${url.pathname}`;
61
+ };
62
+ var applyLanguageToUrl = (url, language) => {
63
+ if (!language.languageCode || !language?.resolutionMethod) {
64
+ return url;
65
+ }
66
+ const urlObj = new URL(url);
67
+ const applyFunc = language?.resolutionMethod === "QUERY_PARAM" ? applyQueryParamLanguage : language?.resolutionMethod === "SUBDOMAIN" ? applySubdomainLanguage : applySubfolderLanguage;
68
+ applyFunc(urlObj, language.languageCode);
69
+ return urlObj.href;
70
+ };
47
71
  var extractLanguageFromUrlAndValidate = (url, availableLocales) => {
48
72
  const localeFromQueryParams = extractFromQueryParamsAndValidate(
49
73
  url,
@@ -157,6 +181,7 @@ function getLocalizationData(url, header, siteProperties) {
157
181
  // Annotate the CommonJS export names for ESM import in node:
158
182
  0 && (module.exports = {
159
183
  MULTILINGUAL_COOKIE_HEADER_KEY,
184
+ applyLanguageToUrl,
160
185
  getLocalizationData
161
186
  });
162
187
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/localeUtils.ts","../src/urlUtils.ts","../src/languageHeaderUtils.ts","../src/localizationUtils.ts"],"sourcesContent":["export {\n getLocalizationData,\n type LocalizationData,\n MULTILINGUAL_COOKIE_HEADER_KEY,\n} from './localizationUtils.js';\n","import type { scripts } from '@wix/headless-site-assets';\n\n// Type for locale object\nexport type Locale = scripts.Locale;\n\n// Type for locale string building\nexport const buildLocaleString = (\n locale?: null | Locale,\n): string | undefined => {\n if (!locale) {\n return;\n }\n\n // in case of dialects, language code will be in the form of\n // en-au and not just en\n if (locale.languageCode?.includes('-')) {\n return locale.languageCode;\n }\n\n const localeParts = [locale.languageCode, locale.country].filter(Boolean);\n\n if (localeParts.length === 0) {\n return;\n }\n\n return localeParts.join('-');\n};\n","import type { scripts } from '@wix/headless-site-assets';\n\nexport type SupportedLanguage = scripts.SupportedLanguage;\n\ntype AvailableLocale = SupportedLanguage;\n\nconst getLanguageFromQueryParam = (url: URL) =>\n url.searchParams.get('lang') ?? undefined;\nconst getLanguageFromSubfolder = (url: URL) => url.pathname.split('/')[1];\nconst getLanguageFromSubdomain = (url: URL) => url.hostname.split('.')[0];\n\nexport const extractLanguageFromUrlAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n const localeFromQueryParams = extractFromQueryParamsAndValidate(\n url,\n availableLocales,\n );\n if (localeFromQueryParams?.resolutionMethod === 'QUERY_PARAM') {\n return localeFromQueryParams;\n }\n\n const localeFromSubfolder = extractFromSubfolderAndValidate(\n url,\n availableLocales,\n );\n if (localeFromSubfolder?.resolutionMethod === 'SUBDIRECTORY') {\n return localeFromSubfolder;\n }\n\n const localeFromSubdomain = extractFromSubdomainAndValidate(\n url,\n availableLocales,\n );\n if (localeFromSubdomain?.resolutionMethod === 'SUBDOMAIN') {\n return localeFromSubdomain;\n }\n\n // Fallback if a locale is available but doesn't have the correct resolution method\n return localeFromQueryParams ?? localeFromSubfolder ?? localeFromSubdomain;\n};\n\nexport const clearLanguageFromUrl = (\n urlString: string,\n languageCodes: string[],\n): string => {\n const url = new URL(urlString);\n url.searchParams.delete('lang');\n\n const subfolderLanguage = url.pathname.split('/')[1]?.toLowerCase();\n if (languageCodes.includes(subfolderLanguage ?? '')) {\n const segments = url.pathname.split('/'); // ['', 'en', 'docs', 'api']\n segments.splice(1, 1); // Remove index 1\n url.pathname = segments.join('/');\n }\n\n const subdirectoryLanguage = url.hostname.split('.')[0]?.toLowerCase();\n if (languageCodes.includes(subdirectoryLanguage ?? '')) {\n const parts = url.hostname.split('.'); // ['fr', 'example', 'com']\n parts.shift(); // ['example', 'com']\n url.hostname = parts.join('.');\n }\n\n return url.href;\n};\n\n// https://somesite.com/hello?lang:XX\nconst extractFromQueryParamsAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromQueryParam(url), availableLocales);\n};\n\n// https://somesite.com/XX/hello\nconst extractFromSubfolderAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromSubfolder(url), availableLocales);\n};\n\n// https://XX.somesite.com/hello\nconst extractFromSubdomainAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromSubdomain(url), availableLocales);\n};\n\nconst getLanguageIfExists = (\n languageCode: string | undefined,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n if (languageCode == null) {\n return undefined;\n }\n const lowerCasedCode = languageCode.toLowerCase();\n return availableLocales.find(\n (locale) => locale.locale?.languageCode?.toLowerCase() === lowerCasedCode,\n );\n};\n","import type { scripts } from '@wix/headless-site-assets';\nimport {\n MULTILINGUAL_COOKIE_HEADER_KEY,\n WixLanguage,\n} from './localizationUtils.js';\n\nexport const calculateLocaleFromMultilingualCookie = (\n headers: Headers,\n supportedLanguages: scripts.SupportedLanguage[],\n) => {\n if (!supportedLanguages.length) {\n return undefined;\n }\n\n const languageCode = getWixLanguageFromCookie(headers)?.languageCode;\n if (!languageCode) {\n return undefined;\n }\n return supportedLanguages.find(\n (supportedLanguage) => supportedLanguage.languageCode === languageCode,\n );\n};\n\nconst getWixLanguageFromCookie = (\n headers: Headers,\n): WixLanguage | undefined => {\n try {\n const cookies = headers.get('cookie') ?? undefined;\n\n const languageCookie = cookies\n ?.split(';')\n .find((keyValue) =>\n keyValue.trim().startsWith(`${MULTILINGUAL_COOKIE_HEADER_KEY}=`),\n );\n\n return languageCookie\n ? { languageCode: languageCookie.split('=')[1] }\n : undefined;\n } catch {\n return undefined;\n }\n};\n","import type { Essentials, Multilingual } from '@wix/headless-node';\nimport type { scripts } from '@wix/headless-site-assets';\nimport { buildLocaleString } from './localeUtils.js';\nimport {\n clearLanguageFromUrl,\n extractLanguageFromUrlAndValidate,\n} from './urlUtils.js';\nimport { calculateLocaleFromMultilingualCookie } from './languageHeaderUtils.js';\n\nexport type EssentialProperties = scripts.EssentialProperties;\nexport const MULTILINGUAL_COOKIE_HEADER_KEY = `wixLanguage`;\nexport interface WixLanguage {\n languageCode?: string;\n}\n\nexport type LocalizationData = {\n cleanUrl: string;\n essentials: Essentials;\n};\n\nexport function getLocalizationData(\n url: URL,\n header: Headers,\n siteProperties: EssentialProperties,\n): LocalizationData {\n const availableLocales =\n siteProperties?.multilingual?.supportedLanguages ?? [];\n const explicitRequestedLocale = extractLanguageFromUrlAndValidate(\n url,\n availableLocales,\n );\n\n const languageCodes = [\n ...availableLocales.map((locale) => locale.locale?.languageCode),\n siteProperties?.locale?.languageCode,\n ].filter((languageCode) => Boolean(languageCode)) as string[];\n\n const locale =\n buildLocaleString(\n explicitRequestedLocale?.locale ??\n calculateLocaleFromMultilingualCookie(header, availableLocales)\n ?.locale ??\n siteProperties?.locale,\n ) ?? undefined;\n\n const language =\n explicitRequestedLocale?.languageCode ??\n calculateLocaleFromMultilingualCookie(header, availableLocales)\n ?.languageCode ??\n siteProperties?.language ??\n undefined;\n\n const cleanUrl = clearLanguageFromUrl(url.href, languageCodes);\n\n const essentials: Essentials = {\n language,\n locale,\n multilingual: siteProperties?.multilingual as Multilingual | undefined,\n timezone: siteProperties?.timeZone ?? undefined,\n };\n\n return { cleanUrl, essentials };\n}\n"],"mappings":"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","names":["locale"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/localeUtils.ts","../src/urlUtils.ts","../src/languageHeaderUtils.ts","../src/localizationUtils.ts"],"sourcesContent":["export {\n getLocalizationData,\n type LocalizationData,\n MULTILINGUAL_COOKIE_HEADER_KEY,\n} from './localizationUtils.js';\n\nexport { applyLanguageToUrl } from './urlUtils.js';\n","import type { scripts } from '@wix/headless-site-assets';\n\n// Type for locale object\nexport type Locale = scripts.Locale;\n\n// Type for locale string building\nexport const buildLocaleString = (\n locale?: null | Locale,\n): string | undefined => {\n if (!locale) {\n return;\n }\n\n // in case of dialects, language code will be in the form of\n // en-au and not just en\n if (locale.languageCode?.includes('-')) {\n return locale.languageCode;\n }\n\n const localeParts = [locale.languageCode, locale.country].filter(Boolean);\n\n if (localeParts.length === 0) {\n return;\n }\n\n return localeParts.join('-');\n};\n","import type { scripts } from '@wix/headless-site-assets';\n\nexport type SupportedLanguage = scripts.SupportedLanguage;\n\ntype AvailableLocale = SupportedLanguage;\n\nconst getLanguageFromQueryParam = (url: URL) =>\n url.searchParams.get('lang') ?? undefined;\nconst getLanguageFromSubfolder = (url: URL) => url.pathname.split('/')[1];\nconst getLanguageFromSubdomain = (url: URL) => url.hostname.split('.')[0];\n\nconst applyQueryParamLanguage = (url: URL, languageCode: string) => {\n url.searchParams.set('lang', languageCode);\n};\n\nconst applySubdomainLanguage = (url: URL, languageCode: string) => {\n let hostnameParts = url.hostname.split('.');\n if (hostnameParts[0] === 'www') {\n hostnameParts = hostnameParts.slice(1);\n }\n hostnameParts = [languageCode, ...hostnameParts];\n url.hostname = hostnameParts.join('.');\n};\n\nconst applySubfolderLanguage = (url: URL, languageCode: string) => {\n url.pathname = `/${languageCode}${url.pathname}`;\n};\n\nexport const applyLanguageToUrl = (\n url: string,\n language: AvailableLocale,\n): string => {\n if (!language.languageCode || !language?.resolutionMethod) {\n return url;\n }\n\n const urlObj = new URL(url);\n const applyFunc =\n language?.resolutionMethod === 'QUERY_PARAM'\n ? applyQueryParamLanguage\n : language?.resolutionMethod === 'SUBDOMAIN'\n ? applySubdomainLanguage\n : applySubfolderLanguage;\n\n applyFunc(urlObj, language.languageCode);\n return urlObj.href;\n};\n\nexport const extractLanguageFromUrlAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n const localeFromQueryParams = extractFromQueryParamsAndValidate(\n url,\n availableLocales,\n );\n if (localeFromQueryParams?.resolutionMethod === 'QUERY_PARAM') {\n return localeFromQueryParams;\n }\n\n const localeFromSubfolder = extractFromSubfolderAndValidate(\n url,\n availableLocales,\n );\n if (localeFromSubfolder?.resolutionMethod === 'SUBDIRECTORY') {\n return localeFromSubfolder;\n }\n\n const localeFromSubdomain = extractFromSubdomainAndValidate(\n url,\n availableLocales,\n );\n if (localeFromSubdomain?.resolutionMethod === 'SUBDOMAIN') {\n return localeFromSubdomain;\n }\n\n // Fallback if a locale is available but doesn't have the correct resolution method\n return localeFromQueryParams ?? localeFromSubfolder ?? localeFromSubdomain;\n};\n\nexport const clearLanguageFromUrl = (\n urlString: string,\n languageCodes: string[],\n): string => {\n const url = new URL(urlString);\n url.searchParams.delete('lang');\n\n const subfolderLanguage = url.pathname.split('/')[1]?.toLowerCase();\n if (languageCodes.includes(subfolderLanguage ?? '')) {\n const segments = url.pathname.split('/'); // ['', 'en', 'docs', 'api']\n segments.splice(1, 1); // Remove index 1\n url.pathname = segments.join('/');\n }\n\n const subdirectoryLanguage = url.hostname.split('.')[0]?.toLowerCase();\n if (languageCodes.includes(subdirectoryLanguage ?? '')) {\n const parts = url.hostname.split('.'); // ['fr', 'example', 'com']\n parts.shift(); // ['example', 'com']\n url.hostname = parts.join('.');\n }\n\n return url.href;\n};\n\n// https://somesite.com/hello?lang:XX\nconst extractFromQueryParamsAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromQueryParam(url), availableLocales);\n};\n\n// https://somesite.com/XX/hello\nconst extractFromSubfolderAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromSubfolder(url), availableLocales);\n};\n\n// https://XX.somesite.com/hello\nconst extractFromSubdomainAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromSubdomain(url), availableLocales);\n};\n\nconst getLanguageIfExists = (\n languageCode: string | undefined,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n if (languageCode == null) {\n return undefined;\n }\n const lowerCasedCode = languageCode.toLowerCase();\n return availableLocales.find(\n (locale) => locale.locale?.languageCode?.toLowerCase() === lowerCasedCode,\n );\n};\n","import type { scripts } from '@wix/headless-site-assets';\nimport {\n MULTILINGUAL_COOKIE_HEADER_KEY,\n WixLanguage,\n} from './localizationUtils.js';\n\nexport const calculateLocaleFromMultilingualCookie = (\n headers: Headers,\n supportedLanguages: scripts.SupportedLanguage[],\n) => {\n if (!supportedLanguages.length) {\n return undefined;\n }\n\n const languageCode = getWixLanguageFromCookie(headers)?.languageCode;\n if (!languageCode) {\n return undefined;\n }\n return supportedLanguages.find(\n (supportedLanguage) => supportedLanguage.languageCode === languageCode,\n );\n};\n\nconst getWixLanguageFromCookie = (\n headers: Headers,\n): WixLanguage | undefined => {\n try {\n const cookies = headers.get('cookie') ?? undefined;\n\n const languageCookie = cookies\n ?.split(';')\n .find((keyValue) =>\n keyValue.trim().startsWith(`${MULTILINGUAL_COOKIE_HEADER_KEY}=`),\n );\n\n return languageCookie\n ? { languageCode: languageCookie.split('=')[1] }\n : undefined;\n } catch {\n return undefined;\n }\n};\n","import type { Essentials, Multilingual } from '@wix/headless-node';\nimport type { scripts } from '@wix/headless-site-assets';\nimport { buildLocaleString } from './localeUtils.js';\nimport {\n clearLanguageFromUrl,\n extractLanguageFromUrlAndValidate,\n} from './urlUtils.js';\nimport { calculateLocaleFromMultilingualCookie } from './languageHeaderUtils.js';\n\nexport type EssentialProperties = scripts.EssentialProperties;\nexport const MULTILINGUAL_COOKIE_HEADER_KEY = `wixLanguage`;\nexport interface WixLanguage {\n languageCode?: string;\n}\n\nexport type LocalizationData = {\n cleanUrl: string;\n essentials: Essentials;\n};\n\nexport function getLocalizationData(\n url: URL,\n header: Headers,\n siteProperties: EssentialProperties,\n): LocalizationData {\n const availableLocales =\n siteProperties?.multilingual?.supportedLanguages ?? [];\n const explicitRequestedLocale = extractLanguageFromUrlAndValidate(\n url,\n availableLocales,\n );\n\n const languageCodes = [\n ...availableLocales.map((locale) => locale.locale?.languageCode),\n siteProperties?.locale?.languageCode,\n ].filter((languageCode) => Boolean(languageCode)) as string[];\n\n const locale =\n buildLocaleString(\n explicitRequestedLocale?.locale ??\n calculateLocaleFromMultilingualCookie(header, availableLocales)\n ?.locale ??\n siteProperties?.locale,\n ) ?? undefined;\n\n const language =\n explicitRequestedLocale?.languageCode ??\n calculateLocaleFromMultilingualCookie(header, availableLocales)\n ?.languageCode ??\n siteProperties?.language ??\n undefined;\n\n const cleanUrl = clearLanguageFromUrl(url.href, languageCodes);\n\n const essentials: Essentials = {\n language,\n locale,\n multilingual: siteProperties?.multilingual as Multilingual | undefined,\n timezone: siteProperties?.timeZone ?? undefined,\n };\n\n return { cleanUrl, essentials };\n}\n"],"mappings":"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","names":["locale"]}
package/build/index.d.cts CHANGED
@@ -9,4 +9,8 @@ type LocalizationData = {
9
9
  };
10
10
  declare function getLocalizationData(url: URL, header: Headers, siteProperties: EssentialProperties): LocalizationData;
11
11
 
12
- export { type LocalizationData, MULTILINGUAL_COOKIE_HEADER_KEY, getLocalizationData };
12
+ type SupportedLanguage = scripts.SupportedLanguage;
13
+ type AvailableLocale = SupportedLanguage;
14
+ declare const applyLanguageToUrl: (url: string, language: AvailableLocale) => string;
15
+
16
+ export { type LocalizationData, MULTILINGUAL_COOKIE_HEADER_KEY, applyLanguageToUrl, getLocalizationData };
package/build/index.d.ts CHANGED
@@ -9,4 +9,8 @@ type LocalizationData = {
9
9
  };
10
10
  declare function getLocalizationData(url: URL, header: Headers, siteProperties: EssentialProperties): LocalizationData;
11
11
 
12
- export { type LocalizationData, MULTILINGUAL_COOKIE_HEADER_KEY, getLocalizationData };
12
+ type SupportedLanguage = scripts.SupportedLanguage;
13
+ type AvailableLocale = SupportedLanguage;
14
+ declare const applyLanguageToUrl: (url: string, language: AvailableLocale) => string;
15
+
16
+ export { type LocalizationData, MULTILINGUAL_COOKIE_HEADER_KEY, applyLanguageToUrl, getLocalizationData };
package/build/index.js CHANGED
@@ -17,6 +17,29 @@ var buildLocaleString = (locale) => {
17
17
  var getLanguageFromQueryParam = (url) => url.searchParams.get("lang") ?? void 0;
18
18
  var getLanguageFromSubfolder = (url) => url.pathname.split("/")[1];
19
19
  var getLanguageFromSubdomain = (url) => url.hostname.split(".")[0];
20
+ var applyQueryParamLanguage = (url, languageCode) => {
21
+ url.searchParams.set("lang", languageCode);
22
+ };
23
+ var applySubdomainLanguage = (url, languageCode) => {
24
+ let hostnameParts = url.hostname.split(".");
25
+ if (hostnameParts[0] === "www") {
26
+ hostnameParts = hostnameParts.slice(1);
27
+ }
28
+ hostnameParts = [languageCode, ...hostnameParts];
29
+ url.hostname = hostnameParts.join(".");
30
+ };
31
+ var applySubfolderLanguage = (url, languageCode) => {
32
+ url.pathname = `/${languageCode}${url.pathname}`;
33
+ };
34
+ var applyLanguageToUrl = (url, language) => {
35
+ if (!language.languageCode || !language?.resolutionMethod) {
36
+ return url;
37
+ }
38
+ const urlObj = new URL(url);
39
+ const applyFunc = language?.resolutionMethod === "QUERY_PARAM" ? applyQueryParamLanguage : language?.resolutionMethod === "SUBDOMAIN" ? applySubdomainLanguage : applySubfolderLanguage;
40
+ applyFunc(urlObj, language.languageCode);
41
+ return urlObj.href;
42
+ };
20
43
  var extractLanguageFromUrlAndValidate = (url, availableLocales) => {
21
44
  const localeFromQueryParams = extractFromQueryParamsAndValidate(
22
45
  url,
@@ -129,6 +152,7 @@ function getLocalizationData(url, header, siteProperties) {
129
152
  }
130
153
  export {
131
154
  MULTILINGUAL_COOKIE_HEADER_KEY,
155
+ applyLanguageToUrl,
132
156
  getLocalizationData
133
157
  };
134
158
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/localeUtils.ts","../src/urlUtils.ts","../src/languageHeaderUtils.ts","../src/localizationUtils.ts"],"sourcesContent":["import type { scripts } from '@wix/headless-site-assets';\n\n// Type for locale object\nexport type Locale = scripts.Locale;\n\n// Type for locale string building\nexport const buildLocaleString = (\n locale?: null | Locale,\n): string | undefined => {\n if (!locale) {\n return;\n }\n\n // in case of dialects, language code will be in the form of\n // en-au and not just en\n if (locale.languageCode?.includes('-')) {\n return locale.languageCode;\n }\n\n const localeParts = [locale.languageCode, locale.country].filter(Boolean);\n\n if (localeParts.length === 0) {\n return;\n }\n\n return localeParts.join('-');\n};\n","import type { scripts } from '@wix/headless-site-assets';\n\nexport type SupportedLanguage = scripts.SupportedLanguage;\n\ntype AvailableLocale = SupportedLanguage;\n\nconst getLanguageFromQueryParam = (url: URL) =>\n url.searchParams.get('lang') ?? undefined;\nconst getLanguageFromSubfolder = (url: URL) => url.pathname.split('/')[1];\nconst getLanguageFromSubdomain = (url: URL) => url.hostname.split('.')[0];\n\nexport const extractLanguageFromUrlAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n const localeFromQueryParams = extractFromQueryParamsAndValidate(\n url,\n availableLocales,\n );\n if (localeFromQueryParams?.resolutionMethod === 'QUERY_PARAM') {\n return localeFromQueryParams;\n }\n\n const localeFromSubfolder = extractFromSubfolderAndValidate(\n url,\n availableLocales,\n );\n if (localeFromSubfolder?.resolutionMethod === 'SUBDIRECTORY') {\n return localeFromSubfolder;\n }\n\n const localeFromSubdomain = extractFromSubdomainAndValidate(\n url,\n availableLocales,\n );\n if (localeFromSubdomain?.resolutionMethod === 'SUBDOMAIN') {\n return localeFromSubdomain;\n }\n\n // Fallback if a locale is available but doesn't have the correct resolution method\n return localeFromQueryParams ?? localeFromSubfolder ?? localeFromSubdomain;\n};\n\nexport const clearLanguageFromUrl = (\n urlString: string,\n languageCodes: string[],\n): string => {\n const url = new URL(urlString);\n url.searchParams.delete('lang');\n\n const subfolderLanguage = url.pathname.split('/')[1]?.toLowerCase();\n if (languageCodes.includes(subfolderLanguage ?? '')) {\n const segments = url.pathname.split('/'); // ['', 'en', 'docs', 'api']\n segments.splice(1, 1); // Remove index 1\n url.pathname = segments.join('/');\n }\n\n const subdirectoryLanguage = url.hostname.split('.')[0]?.toLowerCase();\n if (languageCodes.includes(subdirectoryLanguage ?? '')) {\n const parts = url.hostname.split('.'); // ['fr', 'example', 'com']\n parts.shift(); // ['example', 'com']\n url.hostname = parts.join('.');\n }\n\n return url.href;\n};\n\n// https://somesite.com/hello?lang:XX\nconst extractFromQueryParamsAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromQueryParam(url), availableLocales);\n};\n\n// https://somesite.com/XX/hello\nconst extractFromSubfolderAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromSubfolder(url), availableLocales);\n};\n\n// https://XX.somesite.com/hello\nconst extractFromSubdomainAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromSubdomain(url), availableLocales);\n};\n\nconst getLanguageIfExists = (\n languageCode: string | undefined,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n if (languageCode == null) {\n return undefined;\n }\n const lowerCasedCode = languageCode.toLowerCase();\n return availableLocales.find(\n (locale) => locale.locale?.languageCode?.toLowerCase() === lowerCasedCode,\n );\n};\n","import type { scripts } from '@wix/headless-site-assets';\nimport {\n MULTILINGUAL_COOKIE_HEADER_KEY,\n WixLanguage,\n} from './localizationUtils.js';\n\nexport const calculateLocaleFromMultilingualCookie = (\n headers: Headers,\n supportedLanguages: scripts.SupportedLanguage[],\n) => {\n if (!supportedLanguages.length) {\n return undefined;\n }\n\n const languageCode = getWixLanguageFromCookie(headers)?.languageCode;\n if (!languageCode) {\n return undefined;\n }\n return supportedLanguages.find(\n (supportedLanguage) => supportedLanguage.languageCode === languageCode,\n );\n};\n\nconst getWixLanguageFromCookie = (\n headers: Headers,\n): WixLanguage | undefined => {\n try {\n const cookies = headers.get('cookie') ?? undefined;\n\n const languageCookie = cookies\n ?.split(';')\n .find((keyValue) =>\n keyValue.trim().startsWith(`${MULTILINGUAL_COOKIE_HEADER_KEY}=`),\n );\n\n return languageCookie\n ? { languageCode: languageCookie.split('=')[1] }\n : undefined;\n } catch {\n return undefined;\n }\n};\n","import type { Essentials, Multilingual } from '@wix/headless-node';\nimport type { scripts } from '@wix/headless-site-assets';\nimport { buildLocaleString } from './localeUtils.js';\nimport {\n clearLanguageFromUrl,\n extractLanguageFromUrlAndValidate,\n} from './urlUtils.js';\nimport { calculateLocaleFromMultilingualCookie } from './languageHeaderUtils.js';\n\nexport type EssentialProperties = scripts.EssentialProperties;\nexport const MULTILINGUAL_COOKIE_HEADER_KEY = `wixLanguage`;\nexport interface WixLanguage {\n languageCode?: string;\n}\n\nexport type LocalizationData = {\n cleanUrl: string;\n essentials: Essentials;\n};\n\nexport function getLocalizationData(\n url: URL,\n header: Headers,\n siteProperties: EssentialProperties,\n): LocalizationData {\n const availableLocales =\n siteProperties?.multilingual?.supportedLanguages ?? [];\n const explicitRequestedLocale = extractLanguageFromUrlAndValidate(\n url,\n availableLocales,\n );\n\n const languageCodes = [\n ...availableLocales.map((locale) => locale.locale?.languageCode),\n siteProperties?.locale?.languageCode,\n ].filter((languageCode) => Boolean(languageCode)) as string[];\n\n const locale =\n buildLocaleString(\n explicitRequestedLocale?.locale ??\n calculateLocaleFromMultilingualCookie(header, availableLocales)\n ?.locale ??\n siteProperties?.locale,\n ) ?? undefined;\n\n const language =\n explicitRequestedLocale?.languageCode ??\n calculateLocaleFromMultilingualCookie(header, availableLocales)\n ?.languageCode ??\n siteProperties?.language ??\n undefined;\n\n const cleanUrl = clearLanguageFromUrl(url.href, languageCodes);\n\n const essentials: Essentials = {\n language,\n locale,\n multilingual: siteProperties?.multilingual as Multilingual | undefined,\n timezone: siteProperties?.timeZone ?? undefined,\n };\n\n return { cleanUrl, essentials };\n}\n"],"mappings":"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","names":["locale"]}
1
+ {"version":3,"sources":["../src/localeUtils.ts","../src/urlUtils.ts","../src/languageHeaderUtils.ts","../src/localizationUtils.ts"],"sourcesContent":["import type { scripts } from '@wix/headless-site-assets';\n\n// Type for locale object\nexport type Locale = scripts.Locale;\n\n// Type for locale string building\nexport const buildLocaleString = (\n locale?: null | Locale,\n): string | undefined => {\n if (!locale) {\n return;\n }\n\n // in case of dialects, language code will be in the form of\n // en-au and not just en\n if (locale.languageCode?.includes('-')) {\n return locale.languageCode;\n }\n\n const localeParts = [locale.languageCode, locale.country].filter(Boolean);\n\n if (localeParts.length === 0) {\n return;\n }\n\n return localeParts.join('-');\n};\n","import type { scripts } from '@wix/headless-site-assets';\n\nexport type SupportedLanguage = scripts.SupportedLanguage;\n\ntype AvailableLocale = SupportedLanguage;\n\nconst getLanguageFromQueryParam = (url: URL) =>\n url.searchParams.get('lang') ?? undefined;\nconst getLanguageFromSubfolder = (url: URL) => url.pathname.split('/')[1];\nconst getLanguageFromSubdomain = (url: URL) => url.hostname.split('.')[0];\n\nconst applyQueryParamLanguage = (url: URL, languageCode: string) => {\n url.searchParams.set('lang', languageCode);\n};\n\nconst applySubdomainLanguage = (url: URL, languageCode: string) => {\n let hostnameParts = url.hostname.split('.');\n if (hostnameParts[0] === 'www') {\n hostnameParts = hostnameParts.slice(1);\n }\n hostnameParts = [languageCode, ...hostnameParts];\n url.hostname = hostnameParts.join('.');\n};\n\nconst applySubfolderLanguage = (url: URL, languageCode: string) => {\n url.pathname = `/${languageCode}${url.pathname}`;\n};\n\nexport const applyLanguageToUrl = (\n url: string,\n language: AvailableLocale,\n): string => {\n if (!language.languageCode || !language?.resolutionMethod) {\n return url;\n }\n\n const urlObj = new URL(url);\n const applyFunc =\n language?.resolutionMethod === 'QUERY_PARAM'\n ? applyQueryParamLanguage\n : language?.resolutionMethod === 'SUBDOMAIN'\n ? applySubdomainLanguage\n : applySubfolderLanguage;\n\n applyFunc(urlObj, language.languageCode);\n return urlObj.href;\n};\n\nexport const extractLanguageFromUrlAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n const localeFromQueryParams = extractFromQueryParamsAndValidate(\n url,\n availableLocales,\n );\n if (localeFromQueryParams?.resolutionMethod === 'QUERY_PARAM') {\n return localeFromQueryParams;\n }\n\n const localeFromSubfolder = extractFromSubfolderAndValidate(\n url,\n availableLocales,\n );\n if (localeFromSubfolder?.resolutionMethod === 'SUBDIRECTORY') {\n return localeFromSubfolder;\n }\n\n const localeFromSubdomain = extractFromSubdomainAndValidate(\n url,\n availableLocales,\n );\n if (localeFromSubdomain?.resolutionMethod === 'SUBDOMAIN') {\n return localeFromSubdomain;\n }\n\n // Fallback if a locale is available but doesn't have the correct resolution method\n return localeFromQueryParams ?? localeFromSubfolder ?? localeFromSubdomain;\n};\n\nexport const clearLanguageFromUrl = (\n urlString: string,\n languageCodes: string[],\n): string => {\n const url = new URL(urlString);\n url.searchParams.delete('lang');\n\n const subfolderLanguage = url.pathname.split('/')[1]?.toLowerCase();\n if (languageCodes.includes(subfolderLanguage ?? '')) {\n const segments = url.pathname.split('/'); // ['', 'en', 'docs', 'api']\n segments.splice(1, 1); // Remove index 1\n url.pathname = segments.join('/');\n }\n\n const subdirectoryLanguage = url.hostname.split('.')[0]?.toLowerCase();\n if (languageCodes.includes(subdirectoryLanguage ?? '')) {\n const parts = url.hostname.split('.'); // ['fr', 'example', 'com']\n parts.shift(); // ['example', 'com']\n url.hostname = parts.join('.');\n }\n\n return url.href;\n};\n\n// https://somesite.com/hello?lang:XX\nconst extractFromQueryParamsAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromQueryParam(url), availableLocales);\n};\n\n// https://somesite.com/XX/hello\nconst extractFromSubfolderAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromSubfolder(url), availableLocales);\n};\n\n// https://XX.somesite.com/hello\nconst extractFromSubdomainAndValidate = (\n url: URL,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n return getLanguageIfExists(getLanguageFromSubdomain(url), availableLocales);\n};\n\nconst getLanguageIfExists = (\n languageCode: string | undefined,\n availableLocales: AvailableLocale[],\n): AvailableLocale | undefined => {\n if (languageCode == null) {\n return undefined;\n }\n const lowerCasedCode = languageCode.toLowerCase();\n return availableLocales.find(\n (locale) => locale.locale?.languageCode?.toLowerCase() === lowerCasedCode,\n );\n};\n","import type { scripts } from '@wix/headless-site-assets';\nimport {\n MULTILINGUAL_COOKIE_HEADER_KEY,\n WixLanguage,\n} from './localizationUtils.js';\n\nexport const calculateLocaleFromMultilingualCookie = (\n headers: Headers,\n supportedLanguages: scripts.SupportedLanguage[],\n) => {\n if (!supportedLanguages.length) {\n return undefined;\n }\n\n const languageCode = getWixLanguageFromCookie(headers)?.languageCode;\n if (!languageCode) {\n return undefined;\n }\n return supportedLanguages.find(\n (supportedLanguage) => supportedLanguage.languageCode === languageCode,\n );\n};\n\nconst getWixLanguageFromCookie = (\n headers: Headers,\n): WixLanguage | undefined => {\n try {\n const cookies = headers.get('cookie') ?? undefined;\n\n const languageCookie = cookies\n ?.split(';')\n .find((keyValue) =>\n keyValue.trim().startsWith(`${MULTILINGUAL_COOKIE_HEADER_KEY}=`),\n );\n\n return languageCookie\n ? { languageCode: languageCookie.split('=')[1] }\n : undefined;\n } catch {\n return undefined;\n }\n};\n","import type { Essentials, Multilingual } from '@wix/headless-node';\nimport type { scripts } from '@wix/headless-site-assets';\nimport { buildLocaleString } from './localeUtils.js';\nimport {\n clearLanguageFromUrl,\n extractLanguageFromUrlAndValidate,\n} from './urlUtils.js';\nimport { calculateLocaleFromMultilingualCookie } from './languageHeaderUtils.js';\n\nexport type EssentialProperties = scripts.EssentialProperties;\nexport const MULTILINGUAL_COOKIE_HEADER_KEY = `wixLanguage`;\nexport interface WixLanguage {\n languageCode?: string;\n}\n\nexport type LocalizationData = {\n cleanUrl: string;\n essentials: Essentials;\n};\n\nexport function getLocalizationData(\n url: URL,\n header: Headers,\n siteProperties: EssentialProperties,\n): LocalizationData {\n const availableLocales =\n siteProperties?.multilingual?.supportedLanguages ?? [];\n const explicitRequestedLocale = extractLanguageFromUrlAndValidate(\n url,\n availableLocales,\n );\n\n const languageCodes = [\n ...availableLocales.map((locale) => locale.locale?.languageCode),\n siteProperties?.locale?.languageCode,\n ].filter((languageCode) => Boolean(languageCode)) as string[];\n\n const locale =\n buildLocaleString(\n explicitRequestedLocale?.locale ??\n calculateLocaleFromMultilingualCookie(header, availableLocales)\n ?.locale ??\n siteProperties?.locale,\n ) ?? undefined;\n\n const language =\n explicitRequestedLocale?.languageCode ??\n calculateLocaleFromMultilingualCookie(header, availableLocales)\n ?.languageCode ??\n siteProperties?.language ??\n undefined;\n\n const cleanUrl = clearLanguageFromUrl(url.href, languageCodes);\n\n const essentials: Essentials = {\n language,\n locale,\n multilingual: siteProperties?.multilingual as Multilingual | undefined,\n timezone: siteProperties?.timeZone ?? undefined,\n };\n\n return { cleanUrl, essentials };\n}\n"],"mappings":"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","names":["locale"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wix/headless-localization-utils",
3
- "version": "1.0.5",
3
+ "version": "1.0.6",
4
4
  "unpkg": true,
5
5
  "license": "MIT",
6
6
  "author": {
@@ -74,5 +74,5 @@
74
74
  ]
75
75
  }
76
76
  },
77
- "falconPackageHash": "76200673b1b08a31a5de9535da00d02c23750899a9ab0988ed757887"
77
+ "falconPackageHash": "32b3b4b52b71e70ed353e0479d15042006aeacc1850dcfd806d6e541"
78
78
  }