@wix/headless-localization-utils 1.0.12 → 1.0.13

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
@@ -23,7 +23,8 @@ __export(index_exports, {
23
23
  MULTILINGUAL_COOKIE_HEADER_KEY: () => MULTILINGUAL_COOKIE_HEADER_KEY,
24
24
  applyLanguageToUrl: () => applyLanguageToUrl,
25
25
  clearLanguageFromUrl: () => clearLanguageFromUrl,
26
- getLocalizationData: () => getLocalizationData
26
+ getLocalizationData: () => getLocalizationData,
27
+ toNamespaceDictionary: () => toNamespaceDictionary
27
28
  });
28
29
  module.exports = __toCommonJS(index_exports);
29
30
 
@@ -196,11 +197,31 @@ function getLocalizationData(url, header, siteProperties) {
196
197
  };
197
198
  return { cleanUrl, essentials };
198
199
  }
200
+
201
+ // src/dictionaryHelpers.ts
202
+ function isFlatDictionary(obj) {
203
+ const values = Object.values(obj);
204
+ if (values.length === 0) {
205
+ return true;
206
+ }
207
+ return values.some(
208
+ (value) => typeof value !== "object" || value == null || Array.isArray(value)
209
+ );
210
+ }
211
+ function toNamespaceDictionary(parsed, defaultNamespace = "translation") {
212
+ if (isFlatDictionary(parsed)) {
213
+ return {
214
+ [defaultNamespace]: parsed
215
+ };
216
+ }
217
+ return parsed;
218
+ }
199
219
  // Annotate the CommonJS export names for ESM import in node:
200
220
  0 && (module.exports = {
201
221
  MULTILINGUAL_COOKIE_HEADER_KEY,
202
222
  applyLanguageToUrl,
203
223
  clearLanguageFromUrl,
204
- getLocalizationData
224
+ getLocalizationData,
225
+ toNamespaceDictionary
205
226
  });
206
227
  //# 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\nexport { applyLanguageToUrl, clearLanguageFromUrl } 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 if (!urlString?.length) {\n return urlString;\n }\n\n let urlObject: URL;\n\n try {\n urlObject = new URL(urlString);\n } catch {\n return urlString;\n }\n\n urlObject.searchParams.delete('lang');\n\n const subfolderLanguage = urlObject.pathname.split('/')[1]?.toLowerCase();\n if (languageCodes.includes(subfolderLanguage ?? '')) {\n const segments = urlObject.pathname.split('/'); // ['', 'en', 'docs', 'api']\n segments.splice(1, 1); // Remove index 1\n urlObject.pathname = segments.join('/');\n }\n\n const subdirectoryLanguage = urlObject.hostname.split('.')[0]?.toLowerCase();\n if (languageCodes.includes(subdirectoryLanguage ?? '')) {\n const parts = urlObject.hostname.split('.'); // ['fr', 'example', 'com']\n parts.shift(); // ['example', 'com']\n urlObject.hostname = parts.join('.');\n }\n\n return urlObject.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 cookieLocale = calculateLocaleFromMultilingualCookie(\n header,\n availableLocales,\n );\n const visitorPrimaryLanguage =\n siteProperties?.multilingual?.supportedLanguages?.find(\n ({ isVisitorPrimary }) => isVisitorPrimary,\n );\n\n const primaryLanguage =\n siteProperties?.multilingual?.supportedLanguages?.find(\n ({ isPrimary }) => isPrimary,\n );\n\n const language =\n explicitRequestedLocale?.languageCode ??\n cookieLocale?.languageCode ??\n visitorPrimaryLanguage?.languageCode ??\n primaryLanguage?.languageCode ??\n siteProperties?.language ??\n undefined;\n\n const resolvedLocale =\n explicitRequestedLocale?.locale ??\n cookieLocale?.locale ??\n visitorPrimaryLanguage?.locale ??\n primaryLanguage?.locale ??\n siteProperties?.locale ??\n undefined;\n\n const locale = buildLocaleString(resolvedLocale);\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","../src/dictionaryHelpers.ts"],"sourcesContent":["export {\n getLocalizationData,\n type LocalizationData,\n MULTILINGUAL_COOKIE_HEADER_KEY,\n} from './localizationUtils.js';\n\nexport { applyLanguageToUrl, clearLanguageFromUrl } from './urlUtils.js';\n\nexport { toNamespaceDictionary } from './dictionaryHelpers.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 if (!urlString?.length) {\n return urlString;\n }\n\n let urlObject: URL;\n\n try {\n urlObject = new URL(urlString);\n } catch {\n return urlString;\n }\n\n urlObject.searchParams.delete('lang');\n\n const subfolderLanguage = urlObject.pathname.split('/')[1]?.toLowerCase();\n if (languageCodes.includes(subfolderLanguage ?? '')) {\n const segments = urlObject.pathname.split('/'); // ['', 'en', 'docs', 'api']\n segments.splice(1, 1); // Remove index 1\n urlObject.pathname = segments.join('/');\n }\n\n const subdirectoryLanguage = urlObject.hostname.split('.')[0]?.toLowerCase();\n if (languageCodes.includes(subdirectoryLanguage ?? '')) {\n const parts = urlObject.hostname.split('.'); // ['fr', 'example', 'com']\n parts.shift(); // ['example', 'com']\n urlObject.hostname = parts.join('.');\n }\n\n return urlObject.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 cookieLocale = calculateLocaleFromMultilingualCookie(\n header,\n availableLocales,\n );\n const visitorPrimaryLanguage =\n siteProperties?.multilingual?.supportedLanguages?.find(\n ({ isVisitorPrimary }) => isVisitorPrimary,\n );\n\n const primaryLanguage =\n siteProperties?.multilingual?.supportedLanguages?.find(\n ({ isPrimary }) => isPrimary,\n );\n\n const language =\n explicitRequestedLocale?.languageCode ??\n cookieLocale?.languageCode ??\n visitorPrimaryLanguage?.languageCode ??\n primaryLanguage?.languageCode ??\n siteProperties?.language ??\n undefined;\n\n const resolvedLocale =\n explicitRequestedLocale?.locale ??\n cookieLocale?.locale ??\n visitorPrimaryLanguage?.locale ??\n primaryLanguage?.locale ??\n siteProperties?.locale ??\n undefined;\n\n const locale = buildLocaleString(resolvedLocale);\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","// Language -> (Namespace -> (Key -> Value))\ntype Translations = Record<string, Record<string, Record<string, string>>>;\n\n/**\n * Check if a translation object is flat (key-value pairs) or namespaced (nested objects)\n *\n * A flat dictionary contains at least one primitive value (string, number, etc.)\n * A namespaced dictionary contains only objects as values\n *\n * @example\n * // Flat dictionary (returns true)\n * { \"hello\": \"Hello\", \"goodbye\": \"Goodbye\" }\n *\n * @example\n * // Namespaced dictionary (returns false)\n * { \"common\": { \"hello\": \"Hello\" }, \"errors\": { \"notFound\": \"Not Found\" } }\n */\nfunction isFlatDictionary(obj: Record<string, unknown>): boolean {\n const values = Object.values(obj);\n if (values.length === 0) {\n return true;\n }\n\n return values.some(\n (value) =>\n typeof value !== 'object' || value == null || Array.isArray(value),\n );\n}\n\n/**\n * Normalizes a parsed translation dictionary.\n * Flat dictionaries are wrapped in the default namespace.\n * Namespaced dictionaries are returned as-is.\n */\nexport function toNamespaceDictionary(\n parsed: Record<string, unknown>,\n defaultNamespace: string = 'translation',\n): Translations[string] {\n if (isFlatDictionary(parsed)) {\n return {\n [defaultNamespace]: parsed as Record<string, string>,\n };\n }\n\n return parsed as Translations[string];\n}\n"],"mappings":"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","names":["locale"]}
package/build/index.d.cts CHANGED
@@ -14,4 +14,12 @@ type AvailableLocale = SupportedLanguage;
14
14
  declare const applyLanguageToUrl: (url: string, language: AvailableLocale) => string;
15
15
  declare const clearLanguageFromUrl: (urlString: string, languageCodes: string[]) => string;
16
16
 
17
- export { type LocalizationData, MULTILINGUAL_COOKIE_HEADER_KEY, applyLanguageToUrl, clearLanguageFromUrl, getLocalizationData };
17
+ type Translations = Record<string, Record<string, Record<string, string>>>;
18
+ /**
19
+ * Normalizes a parsed translation dictionary.
20
+ * Flat dictionaries are wrapped in the default namespace.
21
+ * Namespaced dictionaries are returned as-is.
22
+ */
23
+ declare function toNamespaceDictionary(parsed: Record<string, unknown>, defaultNamespace?: string): Translations[string];
24
+
25
+ export { type LocalizationData, MULTILINGUAL_COOKIE_HEADER_KEY, applyLanguageToUrl, clearLanguageFromUrl, getLocalizationData, toNamespaceDictionary };
package/build/index.d.ts CHANGED
@@ -14,4 +14,12 @@ type AvailableLocale = SupportedLanguage;
14
14
  declare const applyLanguageToUrl: (url: string, language: AvailableLocale) => string;
15
15
  declare const clearLanguageFromUrl: (urlString: string, languageCodes: string[]) => string;
16
16
 
17
- export { type LocalizationData, MULTILINGUAL_COOKIE_HEADER_KEY, applyLanguageToUrl, clearLanguageFromUrl, getLocalizationData };
17
+ type Translations = Record<string, Record<string, Record<string, string>>>;
18
+ /**
19
+ * Normalizes a parsed translation dictionary.
20
+ * Flat dictionaries are wrapped in the default namespace.
21
+ * Namespaced dictionaries are returned as-is.
22
+ */
23
+ declare function toNamespaceDictionary(parsed: Record<string, unknown>, defaultNamespace?: string): Translations[string];
24
+
25
+ export { type LocalizationData, MULTILINGUAL_COOKIE_HEADER_KEY, applyLanguageToUrl, clearLanguageFromUrl, getLocalizationData, toNamespaceDictionary };
package/build/index.js CHANGED
@@ -167,10 +167,30 @@ function getLocalizationData(url, header, siteProperties) {
167
167
  };
168
168
  return { cleanUrl, essentials };
169
169
  }
170
+
171
+ // src/dictionaryHelpers.ts
172
+ function isFlatDictionary(obj) {
173
+ const values = Object.values(obj);
174
+ if (values.length === 0) {
175
+ return true;
176
+ }
177
+ return values.some(
178
+ (value) => typeof value !== "object" || value == null || Array.isArray(value)
179
+ );
180
+ }
181
+ function toNamespaceDictionary(parsed, defaultNamespace = "translation") {
182
+ if (isFlatDictionary(parsed)) {
183
+ return {
184
+ [defaultNamespace]: parsed
185
+ };
186
+ }
187
+ return parsed;
188
+ }
170
189
  export {
171
190
  MULTILINGUAL_COOKIE_HEADER_KEY,
172
191
  applyLanguageToUrl,
173
192
  clearLanguageFromUrl,
174
- getLocalizationData
193
+ getLocalizationData,
194
+ toNamespaceDictionary
175
195
  };
176
196
  //# 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\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 if (!urlString?.length) {\n return urlString;\n }\n\n let urlObject: URL;\n\n try {\n urlObject = new URL(urlString);\n } catch {\n return urlString;\n }\n\n urlObject.searchParams.delete('lang');\n\n const subfolderLanguage = urlObject.pathname.split('/')[1]?.toLowerCase();\n if (languageCodes.includes(subfolderLanguage ?? '')) {\n const segments = urlObject.pathname.split('/'); // ['', 'en', 'docs', 'api']\n segments.splice(1, 1); // Remove index 1\n urlObject.pathname = segments.join('/');\n }\n\n const subdirectoryLanguage = urlObject.hostname.split('.')[0]?.toLowerCase();\n if (languageCodes.includes(subdirectoryLanguage ?? '')) {\n const parts = urlObject.hostname.split('.'); // ['fr', 'example', 'com']\n parts.shift(); // ['example', 'com']\n urlObject.hostname = parts.join('.');\n }\n\n return urlObject.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 cookieLocale = calculateLocaleFromMultilingualCookie(\n header,\n availableLocales,\n );\n const visitorPrimaryLanguage =\n siteProperties?.multilingual?.supportedLanguages?.find(\n ({ isVisitorPrimary }) => isVisitorPrimary,\n );\n\n const primaryLanguage =\n siteProperties?.multilingual?.supportedLanguages?.find(\n ({ isPrimary }) => isPrimary,\n );\n\n const language =\n explicitRequestedLocale?.languageCode ??\n cookieLocale?.languageCode ??\n visitorPrimaryLanguage?.languageCode ??\n primaryLanguage?.languageCode ??\n siteProperties?.language ??\n undefined;\n\n const resolvedLocale =\n explicitRequestedLocale?.locale ??\n cookieLocale?.locale ??\n visitorPrimaryLanguage?.locale ??\n primaryLanguage?.locale ??\n siteProperties?.locale ??\n undefined;\n\n const locale = buildLocaleString(resolvedLocale);\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","../src/dictionaryHelpers.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 if (!urlString?.length) {\n return urlString;\n }\n\n let urlObject: URL;\n\n try {\n urlObject = new URL(urlString);\n } catch {\n return urlString;\n }\n\n urlObject.searchParams.delete('lang');\n\n const subfolderLanguage = urlObject.pathname.split('/')[1]?.toLowerCase();\n if (languageCodes.includes(subfolderLanguage ?? '')) {\n const segments = urlObject.pathname.split('/'); // ['', 'en', 'docs', 'api']\n segments.splice(1, 1); // Remove index 1\n urlObject.pathname = segments.join('/');\n }\n\n const subdirectoryLanguage = urlObject.hostname.split('.')[0]?.toLowerCase();\n if (languageCodes.includes(subdirectoryLanguage ?? '')) {\n const parts = urlObject.hostname.split('.'); // ['fr', 'example', 'com']\n parts.shift(); // ['example', 'com']\n urlObject.hostname = parts.join('.');\n }\n\n return urlObject.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 cookieLocale = calculateLocaleFromMultilingualCookie(\n header,\n availableLocales,\n );\n const visitorPrimaryLanguage =\n siteProperties?.multilingual?.supportedLanguages?.find(\n ({ isVisitorPrimary }) => isVisitorPrimary,\n );\n\n const primaryLanguage =\n siteProperties?.multilingual?.supportedLanguages?.find(\n ({ isPrimary }) => isPrimary,\n );\n\n const language =\n explicitRequestedLocale?.languageCode ??\n cookieLocale?.languageCode ??\n visitorPrimaryLanguage?.languageCode ??\n primaryLanguage?.languageCode ??\n siteProperties?.language ??\n undefined;\n\n const resolvedLocale =\n explicitRequestedLocale?.locale ??\n cookieLocale?.locale ??\n visitorPrimaryLanguage?.locale ??\n primaryLanguage?.locale ??\n siteProperties?.locale ??\n undefined;\n\n const locale = buildLocaleString(resolvedLocale);\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","// Language -> (Namespace -> (Key -> Value))\ntype Translations = Record<string, Record<string, Record<string, string>>>;\n\n/**\n * Check if a translation object is flat (key-value pairs) or namespaced (nested objects)\n *\n * A flat dictionary contains at least one primitive value (string, number, etc.)\n * A namespaced dictionary contains only objects as values\n *\n * @example\n * // Flat dictionary (returns true)\n * { \"hello\": \"Hello\", \"goodbye\": \"Goodbye\" }\n *\n * @example\n * // Namespaced dictionary (returns false)\n * { \"common\": { \"hello\": \"Hello\" }, \"errors\": { \"notFound\": \"Not Found\" } }\n */\nfunction isFlatDictionary(obj: Record<string, unknown>): boolean {\n const values = Object.values(obj);\n if (values.length === 0) {\n return true;\n }\n\n return values.some(\n (value) =>\n typeof value !== 'object' || value == null || Array.isArray(value),\n );\n}\n\n/**\n * Normalizes a parsed translation dictionary.\n * Flat dictionaries are wrapped in the default namespace.\n * Namespaced dictionaries are returned as-is.\n */\nexport function toNamespaceDictionary(\n parsed: Record<string, unknown>,\n defaultNamespace: string = 'translation',\n): Translations[string] {\n if (isFlatDictionary(parsed)) {\n return {\n [defaultNamespace]: parsed as Record<string, string>,\n };\n }\n\n return parsed as Translations[string];\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.12",
3
+ "version": "1.0.13",
4
4
  "unpkg": true,
5
5
  "license": "MIT",
6
6
  "author": {
@@ -74,5 +74,5 @@
74
74
  ]
75
75
  }
76
76
  },
77
- "falconPackageHash": "0abf2466015deb01e8315e3c118aa03699327e653b03c7633e4dbd9c"
77
+ "falconPackageHash": "cba6c0bb96a2e3b11ae81b0349d06d4acba6a090a5fc8c5da0cacd59"
78
78
  }