Fixed support for multi-langual slugs

This commit is contained in:
2026-09-09 09:56:47 +02:00
parent db2ac80a1e
commit 2ecfc2e12d
41 changed files with 646 additions and 212 deletions
+19 -13
View File
@@ -8,14 +8,22 @@ import type { I18nConfig } from './types.js';
*/
export type LocalizedSlugs = Record<string, string>;
type BuildPathArgs = {
config: I18nConfig;
/**
* Slug that represents the site root (served at /{locale} with no trailing
* segment). Defaults to 'home'. Matched against the slug in the target locale.
*/
homeSlug?: string;
/** slug per locale, e.g. { pl: 'strona-glowna', en: 'home' } */
slugs: LocalizedSlugs;
/** Target locale to build the path for */
locale: string;
config: I18nConfig;
/**
* Slug(s) representing the site root (served at /{locale} with no trailing
* segment). Defaults to 'home'. Matched against the slug in the target locale.
*
* Can be a single string (same home slug in every locale) OR a per-locale map
* (`{ pl: 'strona-glowna', de: 'startseite', en: 'home' }`). The map form is
* REQUIRED for multilingual homepages whose slug differs per language —
* otherwise the home page collapses to '/pl' but '/de/startseite' stays
* un-collapsed, breaking hreflang return tags (a real GSC error).
*/
homeSlug?: string | Record<string, string>;
/**
* Localized segment the document lives under, e.g.
* `{ pl: 'artykuly', en: 'articles' }` → /pl/artykuly/moj-post.
@@ -25,8 +33,6 @@ type BuildPathArgs = {
* A document under a prefix is never the home page, so homeSlug is ignored.
*/
prefix?: LocalizedSlugs;
/** slug per locale, e.g. { pl: 'strona-glowna', en: 'home' } */
slugs: LocalizedSlugs;
};
/**
* Builds a locale-prefixed path for a document in a target locale.
@@ -50,13 +56,13 @@ type BuildPathArgs = {
* })
* // → '/en/articles/my-post'
*/
export declare function buildLocalizedPath({ config, homeSlug, locale, prefix, slugs, }: BuildPathArgs): string | undefined;
export declare function buildLocalizedPath({ slugs, locale, config, homeSlug, prefix, }: BuildPathArgs): string | undefined;
type SwitchLocaleArgs = {
config: I18nConfig;
homeSlug?: string;
prefix?: LocalizedSlugs;
slugs: LocalizedSlugs;
targetLocale: string;
config: I18nConfig;
homeSlug?: string | Record<string, string>;
prefix?: LocalizedSlugs;
};
/**
* Resolves the equivalent path for the same document in a different locale —
@@ -66,5 +72,5 @@ type SwitchLocaleArgs = {
* falls back to the archive it belongs to (/en/articles) if there is one, and
* to the locale root otherwise — the closest place the visitor would want.
*/
export declare function switchLocalePath({ config, homeSlug, prefix, slugs, targetLocale, }: SwitchLocaleArgs): string;
export declare function switchLocalePath({ slugs, targetLocale, config, homeSlug, prefix, }: SwitchLocaleArgs): string;
export {};
+13 -12
View File
@@ -20,7 +20,7 @@ import { isValidLocale } from './helpers.js';
* config,
* })
* // → '/en/articles/my-post'
*/ export function buildLocalizedPath({ config, homeSlug = 'home', locale, prefix, slugs }) {
*/ export function buildLocalizedPath({ slugs, locale, config, homeSlug = 'home', prefix }) {
if (!isValidLocale(locale, config)) {
return undefined;
}
@@ -44,7 +44,12 @@ import { isValidLocale } from './helpers.js';
}
return `${localeSegment}/${segment}/${slug}`;
}
if (slug === homeSlug) {
// Resolve the home slug for THIS locale. With a per-locale map, each language
// has its own home slug (pl: 'strona-glowna', de: 'startseite'), so the check
// below correctly collapses each language's home to its root — instead of only
// the current-language slug matching and the others staying un-collapsed.
const targetHomeSlug = typeof homeSlug === 'object' ? homeSlug[locale] : homeSlug;
if (slug === targetHomeSlug) {
// Home collapses to the root: '/' for single-locale, '/pl' otherwise.
return localeSegment || '/';
}
@@ -57,21 +62,17 @@ import { isValidLocale } from './helpers.js';
* Never dead-ends on a 404. When the document has no slug in the target locale,
* falls back to the archive it belongs to (/en/articles) if there is one, and
* to the locale root otherwise — the closest place the visitor would want.
*/ export function switchLocalePath({ config, homeSlug = 'home', prefix, slugs, targetLocale }) {
*/ export function switchLocalePath({ slugs, targetLocale, config, homeSlug = 'home', prefix }) {
const path = buildLocalizedPath({
slugs,
locale: targetLocale,
config,
homeSlug,
locale: targetLocale,
prefix,
slugs
prefix
});
if (path) {
return path;
}
if (path) return path;
const archiveSegment = prefix?.[targetLocale];
if (archiveSegment) {
return `/${targetLocale}/${archiveSegment}`;
}
if (archiveSegment) return `/${targetLocale}/${archiveSegment}`;
return `/${targetLocale}`;
}
File diff suppressed because one or more lines are too long