{"version":3,"file":"resolve-DxUpTMmE.mjs","names":[],"sources":["../src/i18n/resolve.ts"],"sourcesContent":["/**\n * Shared locale-resolution helpers.\n *\n * Matches the pattern used by `query.ts` for content: an explicit locale wins,\n * otherwise we fall back to the request-context locale, otherwise to\n * `defaultLocale` when i18n is enabled, otherwise to `undefined` (meaning \"do\n * not filter by locale\" — legacy single-locale behaviour).\n */\n\nimport { getRequestContext } from \"../request-context.js\";\nimport { getFallbackChain, getI18nConfig, isI18nEnabled } from \"./config.js\";\n\n/**\n * Resolve the locale to use for a query given an optional explicit value.\n * Returns `undefined` when no locale information is available; callers should\n * treat that as \"do not filter by locale\".\n */\nexport function resolveLocale(explicit?: string): string | undefined {\n\tif (explicit !== undefined) return explicit;\n\tconst ctxLocale = getRequestContext()?.locale;\n\tif (ctxLocale !== undefined) return ctxLocale;\n\tconst cfg = getI18nConfig();\n\tif (cfg && isI18nEnabled()) return cfg.defaultLocale;\n\treturn undefined;\n}\n\n/**\n * Fallback chain to try when looking up a single item. When i18n is disabled\n * or the locale is unspecified, returns a single-element array (or empty when\n * no locale resolves) so callers can iterate uniformly.\n */\nexport function resolveLocaleChain(explicit?: string): string[] {\n\tconst locale = resolveLocale(explicit);\n\tif (locale === undefined) return [];\n\tif (!isI18nEnabled()) return [locale];\n\treturn getFallbackChain(locale);\n}\n\nconst REPEATED_SLASHES = /\\/{2,}/g;\n\n/**\n * Interpolate a collection `url_pattern` with a row's slug and id.\n *\n * Falls back to `/{collection}/{slug}` when no pattern is configured.\n * Does NOT apply any locale prefix — pass the result through\n * Astro's `getRelativeLocaleUrl` / `getAbsoluteLocaleUrl` (or the\n * `localizePath` helper below) to add the locale segment.\n */\nexport function interpolateUrlPattern(options: {\n\tpattern: string | null;\n\tcollection: string;\n\tslug: string;\n\tid: string;\n}): string {\n\tconst { pattern, collection, slug, id } = options;\n\tconst basePattern = pattern ?? `/${encodeURIComponent(collection)}/{slug}`;\n\tlet path = basePattern\n\t\t.replace(\"{slug}\", encodeURIComponent(slug))\n\t\t.replace(\"{id}\", encodeURIComponent(id));\n\tpath = path.replace(REPEATED_SLASHES, \"/\");\n\tif (path.length > 1 && path.endsWith(\"/\")) path = path.slice(0, -1);\n\tif (!path.startsWith(\"/\")) path = `/${path}`;\n\treturn path;\n}\n\n/**\n * Apply a locale prefix to a path, honouring the user's Astro `i18n`\n * routing config (`prefixDefaultLocale`, custom `path`/`codes` mappings).\n *\n * Reads the resolved config from `astro:config/server`, which is always\n * available regardless of whether i18n is enabled -- so this function\n * works in both i18n and non-i18n builds without tripping Astro's\n * `i18nNotEnabled` resolver (the case with importing `astro:i18n`).\n *\n * Returns:\n *   - The original `path` when i18n is not configured.\n *   - The original `path` for the default locale when\n *     `prefixDefaultLocale` is false.\n *   - `/{segment}{path}` for any other configured locale, where\n *     `{segment}` is the locale's custom `path` if one is set,\n *     otherwise the locale code.\n *   - `null` when the row's locale isn't in the configured list.\n *     Callers should drop the entry: a sitemap link to a route the\n *     site can't serve is worse than no link at all (search engines\n *     get a 404 / soft-404 and downrank the page).\n *\n * Falls back to `getI18nConfig()` (EmDash's mirror of the same config,\n * populated at runtime startup) when `astro:config/server` is\n * unavailable -- e.g. running outside an Astro build context, such as\n * in vitest.\n */\nexport async function localizePath(path: string, locale: string): Promise<string | null> {\n\tconst segment = await resolveLocaleSegment(locale);\n\tif (segment === undefined) return null;\n\tif (segment === null || segment === \"\") return normalizePath(path);\n\treturn normalizePath(`/${segment}${path}`);\n}\n\n/**\n * Resolve the URL segment to use for a locale.\n *\n * Returns:\n *   - `null` when i18n isn't configured (caller should not prefix).\n *   - `\"\"` when the locale is the default locale and\n *     `prefixDefaultLocale` is false (caller should not prefix).\n *   - The locale's custom `path` value, or the locale string itself.\n *   - `undefined` when the locale isn't in the configured list --\n *     the row points at a route the site can't serve.\n */\nasync function resolveLocaleSegment(locale: string): Promise<string | null | undefined> {\n\tconst i18n = await readAstroI18nConfig();\n\tif (!i18n || !i18n.locales || i18n.locales.length <= 1) return null;\n\n\tconst isDefault = locale === i18n.defaultLocale;\n\tif (isDefault && !i18n.prefixDefaultLocale) return \"\";\n\n\t// When the locale has a custom `path`/`codes` mapping, use the path\n\t// for the URL segment. Otherwise use the locale code directly.\n\tfor (const entry of i18n.locales) {\n\t\tif (typeof entry === \"string\") {\n\t\t\tif (entry === locale) return entry;\n\t\t} else if (entry.codes.includes(locale)) {\n\t\t\treturn entry.path;\n\t\t}\n\t}\n\n\treturn undefined;\n}\n\ninterface AstroI18nConfig {\n\tdefaultLocale: string;\n\tlocales: Array<string | { codes: readonly string[]; path: string }>;\n\tprefixDefaultLocale?: boolean;\n}\n\nlet astroI18nCache: AstroI18nConfig | null | undefined;\n\nasync function readAstroI18nConfig(): Promise<AstroI18nConfig | null> {\n\tif (astroI18nCache !== undefined) return astroI18nCache;\n\n\ttry {\n\t\tconst mod = (await import(\"astro:config/server\")) as {\n\t\t\ti18n?: {\n\t\t\t\tdefaultLocale: string;\n\t\t\t\tlocales: Array<string | { codes: readonly string[]; path: string }>;\n\t\t\t\trouting?: { prefixDefaultLocale?: boolean } | string;\n\t\t\t};\n\t\t};\n\t\tif (!mod.i18n) {\n\t\t\tastroI18nCache = null;\n\t\t\treturn null;\n\t\t}\n\t\tconst routing = mod.i18n.routing;\n\t\tastroI18nCache = {\n\t\t\tdefaultLocale: mod.i18n.defaultLocale,\n\t\t\tlocales: mod.i18n.locales,\n\t\t\tprefixDefaultLocale:\n\t\t\t\ttypeof routing === \"object\" ? (routing.prefixDefaultLocale ?? false) : false,\n\t\t};\n\t\treturn astroI18nCache;\n\t} catch {\n\t\t// `astro:config/server` isn't resolvable (e.g. running under vitest\n\t\t// outside an Astro build). Fall back to EmDash's runtime config,\n\t\t// which is populated at startup via the same astroConfig object.\n\t\tconst cfg = getI18nConfig();\n\t\tif (!cfg || !isI18nEnabled()) {\n\t\t\tastroI18nCache = null;\n\t\t\treturn null;\n\t\t}\n\t\tastroI18nCache = {\n\t\t\tdefaultLocale: cfg.defaultLocale,\n\t\t\tlocales: cfg.locales,\n\t\t\tprefixDefaultLocale: cfg.prefixDefaultLocale,\n\t\t};\n\t\treturn astroI18nCache;\n\t}\n}\n\n/** @internal -- exposed for tests to reset the module-level cache. */\nexport function _resetAstroI18nCacheForTests(): void {\n\tastroI18nCache = undefined;\n}\n\nfunction normalizePath(path: string): string {\n\tlet p = path.replace(REPEATED_SLASHES, \"/\");\n\tif (p.length > 1 && p.endsWith(\"/\")) p = p.slice(0, -1);\n\tif (!p.startsWith(\"/\")) p = `/${p}`;\n\treturn p;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAiBA,SAAgB,cAAc,UAAuC;AACpE,KAAI,aAAa,OAAW,QAAO;CACnC,MAAM,YAAY,mBAAmB,EAAE;AACvC,KAAI,cAAc,OAAW,QAAO;CACpC,MAAM,MAAM,eAAe;AAC3B,KAAI,OAAO,eAAe,CAAE,QAAO,IAAI;;;;;;;AASxC,SAAgB,mBAAmB,UAA6B;CAC/D,MAAM,SAAS,cAAc,SAAS;AACtC,KAAI,WAAW,OAAW,QAAO,EAAE;AACnC,KAAI,CAAC,eAAe,CAAE,QAAO,CAAC,OAAO;AACrC,QAAO,iBAAiB,OAAO;;AAGhC,MAAM,mBAAmB;;;;;;;;;AAUzB,SAAgB,sBAAsB,SAK3B;CACV,MAAM,EAAE,SAAS,YAAY,MAAM,OAAO;CAE1C,IAAI,QADgB,WAAW,IAAI,mBAAmB,WAAW,CAAC,UAEhE,QAAQ,UAAU,mBAAmB,KAAK,CAAC,CAC3C,QAAQ,QAAQ,mBAAmB,GAAG,CAAC;AACzC,QAAO,KAAK,QAAQ,kBAAkB,IAAI;AAC1C,KAAI,KAAK,SAAS,KAAK,KAAK,SAAS,IAAI,CAAE,QAAO,KAAK,MAAM,GAAG,GAAG;AACnE,KAAI,CAAC,KAAK,WAAW,IAAI,CAAE,QAAO,IAAI;AACtC,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA6BR,eAAsB,aAAa,MAAc,QAAwC;CACxF,MAAM,UAAU,MAAM,qBAAqB,OAAO;AAClD,KAAI,YAAY,OAAW,QAAO;AAClC,KAAI,YAAY,QAAQ,YAAY,GAAI,QAAO,cAAc,KAAK;AAClE,QAAO,cAAc,IAAI,UAAU,OAAO;;;;;;;;;;;;;AAc3C,eAAe,qBAAqB,QAAoD;CACvF,MAAM,OAAO,MAAM,qBAAqB;AACxC,KAAI,CAAC,QAAQ,CAAC,KAAK,WAAW,KAAK,QAAQ,UAAU,EAAG,QAAO;AAG/D,KADkB,WAAW,KAAK,iBACjB,CAAC,KAAK,oBAAqB,QAAO;AAInD,MAAK,MAAM,SAAS,KAAK,QACxB,KAAI,OAAO,UAAU,UACpB;MAAI,UAAU,OAAQ,QAAO;YACnB,MAAM,MAAM,SAAS,OAAO,CACtC,QAAO,MAAM;;AAahB,IAAI;AAEJ,eAAe,sBAAuD;AACrE,KAAI,mBAAmB,OAAW,QAAO;AAEzC,KAAI;EACH,MAAM,MAAO,MAAM,OAAO;AAO1B,MAAI,CAAC,IAAI,MAAM;AACd,oBAAiB;AACjB,UAAO;;EAER,MAAM,UAAU,IAAI,KAAK;AACzB,mBAAiB;GAChB,eAAe,IAAI,KAAK;GACxB,SAAS,IAAI,KAAK;GAClB,qBACC,OAAO,YAAY,WAAY,QAAQ,uBAAuB,QAAS;GACxE;AACD,SAAO;SACA;EAIP,MAAM,MAAM,eAAe;AAC3B,MAAI,CAAC,OAAO,CAAC,eAAe,EAAE;AAC7B,oBAAiB;AACjB,UAAO;;AAER,mBAAiB;GAChB,eAAe,IAAI;GACnB,SAAS,IAAI;GACb,qBAAqB,IAAI;GACzB;AACD,SAAO;;;AAST,SAAS,cAAc,MAAsB;CAC5C,IAAI,IAAI,KAAK,QAAQ,kBAAkB,IAAI;AAC3C,KAAI,EAAE,SAAS,KAAK,EAAE,SAAS,IAAI,CAAE,KAAI,EAAE,MAAM,GAAG,GAAG;AACvD,KAAI,CAAC,EAAE,WAAW,IAAI,CAAE,KAAI,IAAI;AAChC,QAAO"}