Localized Routes
By default, every page in ReeWeb has the same URL path in every locale - /about/ is /about/ in English, Slovenian, and German. Localized routes let you translate the path itself: /about/ in English becomes /o-nas/ in Slovenian and /ueber-uns/ in German. The translation files declare a route_name key, and the script generates the appropriate per-locale URLs automatically.
Setting a Route Name
Add a route_name key to any section's translation object. The key name is the canonical URL segment, and the value is the translated path segment:
route_name is a top-level key in the route directory's own {locale}.json, not
a nested entry in the site-wide root file. /about/ takes its route name from
src/public/about/{locale}.json:
// src/public/about/en-us.json
{
"route_name": "about",
"ui": { "title": "About us" }
}
// src/public/about/sl-si.json
{
"route_name": "o nas",
"ui": { "title": "O nas" }
}
// src/public/contact/sl-si.json
{
"route_name": "kontakt"
}
Putting { "about": { "route_name": "o nas" } } in the root src/public/sl-si.json
does not work and reports no error - the root file loads into the routes
namespace, while the route map looks for the segment's own namespace. The build
just keeps the untranslated /sl-si/about/ path. This is why each localized route
needs a {locale}.json inside its own directory.
With these in place, the SSG script generates:
/about/(English)/o-nas/(Slovenian)/contact/(English)/kontakt/(Slovenian)
The route_name value is processed through slugify() in lib/route_aliases.ts, which transliterates Unicode characters to ASCII and normalises the result to a URL-safe slug:
slugify("o nas"); // → "o-nas"
slugify("übersetzen"); // → "ubersetzen" (combining diacritic stripped)
slugify("straße"); // → "strasse" (ß → ss)
slugify("Łódź"); // → "lodz" (ł → l, NFKD cannot decompose it)
slugify("Ærø"); // → "aero" (æ → ae, ø → o)
Letters NFKD decomposes lose their accent. Letters it cannot decompose have an
explicit mapping - ß, æ, œ, ø, ł, đ, ð, þ, ħ, ı, ŋ, ŧ,
ƶ - because without one they are removed outright rather than simplified.
Anything still outside [a-z0-9_] becomes a hyphen.
Route Name Isolation
A critical rule: route_name is never inherited across locales. If English defines about.route_name but Slovenian doesn't, the Slovenian URL stays as /about/ - it does not inherit the English "about". This is enforced in lib/i18n.ts:
// Never inherit route_name from other locales.
if (key === "route_name") continue;
This means you must define a route_name in every locale where you want a localized path. This is intentional - a Slovenian URL like /about/ using an English word is fine, but a Slovenian URL like /ueber-uns/ with a German word would be confusing. Each locale controls its own paths.
Nested Localized Routes
Route names work at any nesting depth. For a blog post at blog/my-post-slug:
// sl-si.json
{
"blog": {
"route_name": "novice"
}
}
This produces /novice/my-post-slug/ in Slovenian while staying at /blog/my-post-slug/ in English. The route map in lib/static_site.ts (build_static_route_map()) walks the translation tree segment by segment, substituting route_name where present and keeping the canonical segment where not.
How It Affects Links
When you link between pages, always use the canonical path - not the localized URL. The localized_path() helper resolves the correct URL for the active locale at render time:
<!-- Correct: use canonical path, helper resolves the right URL -->
<a href="{~ localized_path('/about') }">About</a>
<!-- Wrong: hard-coding a localized path breaks in other locales -->
<a href="/o-nas/">About</a>
For links to the same page in a different locale, use the localized_path_for_locale() helper:
{#each props.active_locales as l}
<a href="{~ localized_path_for_locale(l, props.canonical_path) }"> {= props.locale_names[l] } </a>
{/each}
This resolves /about/ to the correct URL in any locale - /about/ for English, /o-nas/ for Slovenian.
Hreflang Alternate Links
When --site-url is provided to the SSG script, every page gets <link rel="alternate" hreflang="..."> tags pointing to each locale variant - including an x-default entry pointing to the default locale. These are required by Google for multi-locale SEO.
<link rel="alternate" hreflang="en-US" href="https://example.com/about/" />
<link rel="alternate" hreflang="sl-SI" href="https://example.com/o-nas/" />
<link rel="alternate" hreflang="x-default" href="https://example.com/o-nas/" />
The x-default points to the default locale (Slovenian in the example above), which is what unauthenticated users see when they land on the root URL.