Files
SnapOtter/scripts/i18n/lib/slugify.mjs
T
SnapOtterandGitHub 00b651c9f8 feat(i18n): 21-language pipeline, landing/docs/API wiring, landing+API translations
Shared Claude Code translation pipeline (scripts/i18n, no API key) plus Astro/VitePress/Scalar i18n wiring. Landing and API reference translated into all 20 languages; docs i18n wiring + English source anchors. The translated docs markdown (apps/docs/<locale>/**, 3,620 files) follows in a companion PR because it exceeds GitHub's per-PR CI file limit.
2026-07-11 13:01:55 +08:00

28 lines
1.0 KiB
JavaScript

// scripts/i18n/lib/slugify.mjs
// Exact port of the slugify VitePress uses (mdit-vue @mdit-vue/shared). Keeping
// this identical means the {#anchor} we inject equals the auto-slug VitePress
// would produce, so pre-existing #deep-links keep resolving after we add
// explicit anchors. Regexes copied verbatim from vitepress/dist/node, with
// explicit unicode escapes for the control and combining ranges.
// biome-ignore lint/suspicious/noControlCharactersInRegex: byte-exact port of mdit-vue slugify; the control-char range is required for VitePress anchor parity.
const rControl = /[\u0000-\u001f]/g;
const rSpecial = /[\s~`!@#$%^&*()\-_+=[\]{}|\\;:"'“”‘’<>,.?/]+/g;
const rCombining = /[\u0300-\u036f]/g;
/**
* @param {string} str
* @returns {string}
*/
export function slugify(str) {
return String(str)
.normalize("NFKD")
.replace(rCombining, "")
.replace(rControl, "")
.replace(rSpecial, "-")
.replace(/-{2,}/g, "-")
.replace(/^-+|-+$/g, "")
.replace(/^(\d)/, "_$1")
.toLowerCase();
}