UNPKG

@intlayer/core

Version:

Includes core Intlayer functions like translation, dictionary, and utility functions shared across multiple packages.

92 lines (90 loc) 5.26 kB
import { checkIsURLAbsolute } from "../utils/checkIsURLAbsolute.mjs"; import { getPathWithoutLocale } from "./getPathWithoutLocale.mjs"; import { getPrefix, resolveRoutingConfig } from "./getPrefix.mjs"; import { getCanonicalPath, getLocalizedPath, getRewriteRules } from "./rewriteUtils.mjs"; import { internationalization } from "@intlayer/config/built"; //#region src/localization/getLocalizedUrl.ts /** Strips the protocol and returns the bare hostname of a domain string. */ const extractHostname = (domain) => { try { return /^https?:\/\//.test(domain) ? new URL(domain).hostname : domain; } catch { return domain; } }; /** * Generate URL by prefixing the given URL with the referenced locale or adding search parameters * based on the routing mode. Handles both absolute and relative URLs appropriately. * * This function gets the locales, default locale, and routing mode from the configuration if not provided. * * Example: * * ```ts * // prefix-no-default mode * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-no-default' }); * // Returns '/fr/about' for the French locale * // Returns '/about' for the English locale (default) * * // prefix-all mode * getLocalizedUrl('/about', 'en', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'prefix-all' }); * // Returns '/en/about' for the English locale * // Returns '/fr/about' for the French locale * * // search-params mode * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'search-params' }); * // Returns '/about?locale=fr' for the French locale * * // no-prefix mode * getLocalizedUrl('/about', 'fr', { locales: ['en', 'fr'], defaultLocale: 'en', mode: 'no-prefix' }); * // Returns '/about' for any locale * ``` * * @param url - The original URL string to be processed. * @param currentLocale - The current locale. * @param options - Configuration options * @param options.locales - Optional array of supported locales. Defaults to configured locales. * @param options.defaultLocale - The default locale. Defaults to configured default locale. * @param options.mode - URL routing mode for locale handling. Defaults to configured mode. * @param options.currentDomain - Hostname of the page being rendered. Used to decide * whether to emit a relative URL (same domain) or an absolute URL (cross-domain). * Auto-detected from the input URL or `window.location` when omitted. * @returns The localized URL for the current locale. */ /** * The return type is narrowed to a template-literal type when both `url` and * `currentLocale` are string literals and the routing mode / defaultLocale are * not overridden via `options`. */ const getLocalizedUrl = (url, currentLocale = internationalization?.defaultLocale, options = {}) => { const { defaultLocale, mode, locales, rewrite, domains, currentDomain } = resolveRoutingConfig(options); const urlWithoutLocale = getPathWithoutLocale(url, locales); const rewriteRules = getRewriteRules(rewrite, "url"); if (!(process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "no-prefix") && mode === "no-prefix") return getLocalizedPath(getCanonicalPath(urlWithoutLocale, void 0, rewriteRules), currentLocale, rewriteRules).path; const isAbsoluteUrl = checkIsURLAbsolute(urlWithoutLocale); const parsedUrl = isAbsoluteUrl ? new URL(urlWithoutLocale) : new URL(urlWithoutLocale, "http://example.com"); const translatedPathname = getLocalizedPath(getCanonicalPath(parsedUrl.pathname, void 0, rewriteRules), currentLocale, rewriteRules).path; const detectedCurrentHostname = process.env["INTLAYER_ROUTING_DOMAINS"] !== "false" ? extractHostname(currentDomain ?? (isAbsoluteUrl ? parsedUrl.hostname : void 0) ?? (typeof window !== "undefined" ? window?.location?.hostname : void 0) ?? "") || null : null; const localeDomain = process.env["INTLAYER_ROUTING_DOMAINS"] !== "false" ? domains?.[currentLocale] : void 0; const localeDomainHostname = localeDomain ? extractHostname(localeDomain) : null; const normalizedDomain = localeDomainHostname !== null && detectedCurrentHostname !== null && localeDomainHostname !== detectedCurrentHostname && localeDomain ? /^https?:\/\//.test(localeDomain) ? localeDomain : `https://${localeDomain}` : null; const baseUrl = normalizedDomain ? normalizedDomain : isAbsoluteUrl ? `${parsedUrl.protocol}//${parsedUrl.host}` : ""; if (!(process.env["INTLAYER_ROUTING_MODE"] && process.env["INTLAYER_ROUTING_MODE"] !== "search-params") && mode === "search-params") { const searchParams = new URLSearchParams(parsedUrl.search); searchParams.set("locale", currentLocale.toString()); const queryParams = searchParams.toString(); return `${baseUrl}${queryParams ? `${translatedPathname}?${queryParams}` : translatedPathname}${parsedUrl.hash}`; } const { prefix } = getPrefix(currentLocale, { defaultLocale, mode, locales, domains }); let localizedPath = `/${prefix}${translatedPathname}`.replace(/\/+/g, "/"); if (localizedPath.length > 1 && localizedPath.endsWith("/")) localizedPath = localizedPath.slice(0, -1); return `${baseUrl}${localizedPath}${parsedUrl.search}${parsedUrl.hash}`; }; //#endregion export { getLocalizedUrl }; //# sourceMappingURL=getLocalizedUrl.mjs.map