Development notes
Why a three-language site takes its language from the URL
How Traditional Chinese, English, and Japanese routes let the URL determine page language, copy, metadata, and the next destination when switching languages.
- Multilingual websites
- Astro
- Routing
- Information architecture
This translation describes the routing contract recorded in the original article on October 2, 2026. The English and Japanese notes lists’ empty state below refers to the situation recorded then, not a claim that those languages still have no articles. Unprefixed route examples are Traditional Chinese routes; labels in the original code example are retained unchanged.
A multilingual site does not have to begin by checking browser preferences, nor does it have to hide the language in global state. For the site described here, the URL itself is the source of the language: Traditional Chinese uses /, English uses /en, and Japanese uses /ja.
What looks like a routing convention also determines which copy a page reads, what it outputs for html lang, which language its metadata uses, and whether the next link in a language switch actually exists. The central judgment is this: if language is part of the public URL, derive both the build and the links from the same locale source instead of overriding it with a separate browser state.
Distinguish the default language from the others
The recorded language set has three values: zh-TW, en, and ja. Traditional Chinese is the default, so fixed pages use their existing paths directly. English and Japanese add a language prefix:
The original route example retains its Chinese labels: 繁中 means Traditional Chinese, 英文 means English, and 日文 means Japanese. The unprefixed /about is the Traditional Chinese route.
繁中:/about
英文:/en/about
日文:/ja/about
The code’s localizedPath() does only this: it receives a fixed page and a language, then returns the corresponding URL. It does not detect the browser’s language, read cookies, or decide which language a user prefers. This is a small responsibility, but it keeps URL generation rules in one place.
The URL generator also preserves the exception for the default language. zh-TW does not need /zh-TW, so paths such as /, /notes, and /about are the Traditional Chinese versions; only English and Japanese receive prefixes. Prefixing all three languages would change the existing Traditional Chinese URLs and add another migration problem for old links and canonical rules.
Fixed pages get their language from route props
Fixed pages are not empty shells that the browser switches into another language after loading. The dynamic English and Japanese routes enumerate the set of fixed pages at build time, then pass lang and the page’s role to the same Astro components.
Although /en/about and /ja/about share AboutPage, they are two actual output pages. The component’s lang determines:
- Which language dictionary supplies titles and paragraphs.
- Which set of fixed pages the navigation links to.
- What value the
htmlelement’slangattribute outputs. - Which language the page description, Open Graph copy, and structured data use.
Sharing a component does not mean sharing one page state. It means sharing the page structure. The actual language still comes through route props and is already determined at build time.
Links need the same language source
Main navigation links are not made by slicing a section out of the current URL string and joining it back together. They pass the current page and target language to the same path function. For example, switching from the English Notes page to Japanese should lead to /ja/notes; switching from the Traditional Chinese product page to English should lead to /en/products/daily-order.
This keeps the language switcher as native links:
- Readers can open them in a new browser tab.
- Switching still works if JavaScript fails.
- Crawlers and assistive tools can understand the links themselves.
- Each language page can have its own canonical URL and
hreflang.
There is no need for a separate client store holding the current language. The page already knows its language from the URL; switching languages only needs to produce another real URL.
Fixed pages and content pages have different translation problems
For fixed pages, the site can know in advance that corresponding pages exist in all three languages because it controls both the routes and copy dictionaries. Note articles are different: a Chinese article may not yet have an English or Japanese version.
Article language links therefore cannot simply follow the global language list. The article template uses the same stableId to find translations that actually exist and meet the public publication conditions, then generates the corresponding links. A language without a translation is not forced into an article URL that merely looks real.
The two cases can be considered separately:
| Content type | How language URLs are generated | What happens without a translation |
|---|---|---|
| Fixed pages | Built from fixed routes and the language set | Every supported language has a corresponding page |
| Note articles | Built from existing articles and stableId |
No fake translated article page is generated |
That is why “the multilingual site has English pages” and “every article has an English translation” cannot be treated as the same statement. The former is a fixed-page routing contract; the latter describes content availability.
A URL determines language, not translation completeness
At the time recorded in the original article, the English and Japanese notes lists existed normally even though they temporarily had no published articles. Each list displayed its own language’s empty state. It did not copy Traditional Chinese articles into that language or redirect readers to the Traditional Chinese homepage. This is a historical example of empty-state behavior, not a claim that the lists remain empty.
The empty state matters because it separates two things:
- An entry point to the site in that language exists.
- A certain number of articles in that language are available for public reading.
If there are no articles, the page says so. Article routes appear only when articles are available. A URL can establish an entry point to content, but it cannot supply a translation that does not exist.
What this approach deliberately leaves out
Using the URL as the language source does not mean every multilingual problem has been solved. The recorded approach deliberately does not:
- Automatically send readers to another locale based on browser language.
- Treat a nonexistent translation as an alternative to the original.
- Claim that a language’s content is complete just because a route contains
/enor/ja. - Turn language switching into buttons that work only with JavaScript.
- Replace each page’s own URL and metadata with global language state.
If automatic redirection, remembered language preferences, or more translated content are added in the future, they still need to be checked for conflicts with public URLs, canonical URLs, and historical links. The routing contract described here does not prove that those features exist.
Initial checks for multilingual pages
- Decide which language uses the default URLs rather than adding a prefix to every language.
- Have fixed-page routes, navigation links,
lang, and metadata share the same set of locales. - Model fixed-page translations separately from article translations.
- Create article language links only when both the translation file and its publication state qualify.
- Show a truthful empty state when there is no content, rather than filling the layout with fake articles.
- Check the actual URLs, canonical URLs, and language markers in the output, rather than only looking for a
langvariable in component files.
The recorded approach does not start with a language switcher and then force all content into it. It keeps public URLs, page data, and existing content consistent with one another. Fixed pages can share structure while articles wait individually for translation. Both begin with URLs, but they do not have to pretend their content availability is the same.
Scope of this record
This article documents the implementation contract for the three-language fixed pages, navigation links, and note article routes recorded in the original article. It explains how the URL supplies the language and how fixed pages differ from translated articles. It does not claim that automatic language detection, translation completeness, search traffic, or readers’ preferences have been measured.