Align slug transliteration with bDS2 (ä→a, not ä→ae) #65

Closed
opened 2026-07-20 19:43:56 +00:00 by hugo · 2 comments
Owner

Source: Spec-vs-code audit 2026-07-20, section 1.1 (high impact). Golden master: ../bDS2.

Current behaviour (RuDS): crates/bds-core/src/util/slug.rs pre-maps ä→ae, ö→oe, ü→ue, Ä→Ae, Ö→Oe, Ü→Ue before deunicode, so slugify("Über") == "ueber". Unit tests lock this in (german_umlaut_* tests). This matches the OLD TypeScript bDS, not bDS2.

bDS2 behaviour: ../bDS2/lib/bds/slug.ex maps only ß→ss, then NFD-normalizes and strips non-ASCII: slugify("Über") == "uber", slugify("ÄÖÜäöüß") == "aouaouss". Tests: ../bDS2/test/bds/posts_test.exs:320-336.

Spec: specs/post.allium (value Slug) and specs/bds.allium resolved question 1 only say "verify transliteration matches the established bDS behaviour" — ambiguous.

Task:

  1. Confirm with the maintainer which mapping is canonical (bDS2 uber is the golden master; existing RuDS-generated content may already use ueber slugs — check fixtures/compatibility-projects for umlaut slugs before switching).
  2. Change german_transliterate/slugify to match bDS2 exactly (ß→ss only, NFD strip), update the slug.rs tests to bDS2's expected values, and add the four bDS2 test cases verbatim as a corpus test.
  3. Update specs/post.allium value Slug to state the exact mapping so this can't regress; validate the spec with the allium CLI.
  4. slugify is also used for tag/category archive URLs and the Liquid slugify filter — grep for slugify( callers and confirm generated URL parity with bDS2.

Acceptance: cargo test --workspace green; slugify output byte-identical to bDS2 for the test corpus; spec updated and allium check passes.

**Source:** Spec-vs-code audit 2026-07-20, section 1.1 (high impact). Golden master: ../bDS2. **Current behaviour (RuDS):** `crates/bds-core/src/util/slug.rs` pre-maps ä→ae, ö→oe, ü→ue, Ä→Ae, Ö→Oe, Ü→Ue before `deunicode`, so `slugify("Über") == "ueber"`. Unit tests lock this in (german_umlaut_* tests). This matches the OLD TypeScript bDS, not bDS2. **bDS2 behaviour:** `../bDS2/lib/bds/slug.ex` maps only ß→ss, then NFD-normalizes and strips non-ASCII: `slugify("Über") == "uber"`, `slugify("ÄÖÜäöüß") == "aouaouss"`. Tests: `../bDS2/test/bds/posts_test.exs:320-336`. **Spec:** `specs/post.allium` (value Slug) and `specs/bds.allium` resolved question 1 only say "verify transliteration matches the established bDS behaviour" — ambiguous. **Task:** 1. Confirm with the maintainer which mapping is canonical (bDS2 `uber` is the golden master; existing RuDS-generated content may already use `ueber` slugs — check fixtures/compatibility-projects for umlaut slugs before switching). 2. Change `german_transliterate`/`slugify` to match bDS2 exactly (ß→ss only, NFD strip), update the slug.rs tests to bDS2's expected values, and add the four bDS2 test cases verbatim as a corpus test. 3. Update `specs/post.allium` value Slug to state the exact mapping so this can't regress; validate the spec with the `allium` CLI. 4. `slugify` is also used for tag/category archive URLs and the Liquid `slugify` filter — grep for `slugify(` callers and confirm generated URL parity with bDS2. **Acceptance:** `cargo test --workspace` green; slugify output byte-identical to bDS2 for the test corpus; spec updated and `allium check` passes.
hugo added the bug label 2026-07-20 19:43:56 +00:00
Author
Owner

Confirmation from maintainer: the bDS2 behaviour is canonical. Implement it as bDS2 does it.

Confirmation from maintainer: the bDS2 behaviour is canonical. Implement it as bDS2 does it.
Author
Owner

Implemented in ac993d8. Slug generation now follows bDS2 exactly: replace lowercase ß with ss, apply canonical Unicode NFD decomposition, discard every remaining non-ASCII code point, lowercase, collapse non-alphanumeric runs to hyphens, and trim edge hyphens. The general deunicode transliterator and its ae/oe/ue pre-map were removed in favor of unicode-normalization, so Über becomes uber and ÄÖÜäöüß becomes aouaouss. Added the complete bDS2 German corpus plus a regression proving non-ASCII text is stripped rather than broadly transliterated. Updated the shared spec-claim test, Liquid slugify filter test, tag archive pagination route, category menu archive routes in canonical and translated prefixes, README, and exact normative wording in post.allium and bds.allium. Audited every slugify caller: posts, projects, templates, scripts, WordPress fallback imports, scripting APIs, tag/category generation, menus, and Liquid all share this one helper. The compatibility fixture already records für as fur, and existing stored slugs are not rewritten. Neutral review against issue #65, ../bDS2/lib/bds/slug.ex and its posts_test corpus, and the updated Allium contract found no remaining gaps. Verified with cargo test --workspace (475 core tests plus all workspace suites), cargo build --workspace, strict workspace Clippy, cargo fmt check, allium check across every spec, and git diff check. The full test run completed without a keychain prompt.

Implemented in ac993d8. Slug generation now follows bDS2 exactly: replace lowercase ß with ss, apply canonical Unicode NFD decomposition, discard every remaining non-ASCII code point, lowercase, collapse non-alphanumeric runs to hyphens, and trim edge hyphens. The general deunicode transliterator and its ae/oe/ue pre-map were removed in favor of unicode-normalization, so Über becomes uber and ÄÖÜäöüß becomes aouaouss. Added the complete bDS2 German corpus plus a regression proving non-ASCII text is stripped rather than broadly transliterated. Updated the shared spec-claim test, Liquid slugify filter test, tag archive pagination route, category menu archive routes in canonical and translated prefixes, README, and exact normative wording in post.allium and bds.allium. Audited every slugify caller: posts, projects, templates, scripts, WordPress fallback imports, scripting APIs, tag/category generation, menus, and Liquid all share this one helper. The compatibility fixture already records für as fur, and existing stored slugs are not rewritten. Neutral review against issue #65, ../bDS2/lib/bds/slug.ex and its posts_test corpus, and the updated Allium contract found no remaining gaps. Verified with cargo test --workspace (475 core tests plus all workspace suites), cargo build --workspace, strict workspace Clippy, cargo fmt check, allium check across every spec, and git diff check. The full test run completed without a keychain prompt.
hugo closed this issue 2026-07-20 21:01:38 +00:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: hugo/RuDS#65