Development notes
What stable IDs, slugs, and translated articles each do
Using actual articles on this website in three languages, I distinguish collection entry IDs, shared article identity, and public URLs, and explain what to preserve when changing titles or slugs and adding translations.
- Content engineering
- Multilingual websites
- Astro
- Data contracts
An English title differs from its Traditional Chinese counterpart, while both URLs use the same English name. Neither titles nor URLs alone are enough to establish that the two articles are translations of one another.
This website uses three kinds of data to answer three questions: a collection entry ID identifies the file that was loaded, stableId connects language versions of the same article, and locale together with slug determines the URL a reader opens. Their values may look similar at present, but that does not make them interchangeable fields.
Start with an article that already exists in three languages
“Rebuilding a website with AI” already has Traditional Chinese, English, and Japanese versions. Each file has a natural title in its own language. The table shows the actual entry identities and public routes for all three versions:
| Language | collection entry ID | stableId |
Public route |
|---|---|---|---|
| Traditional Chinese | zh-TW/ai-collaboration-and-acceptance |
ai-collaboration-and-acceptance |
/notes/ai-collaboration-and-acceptance |
| English | en/ai-collaboration-and-acceptance |
ai-collaboration-and-acceptance |
/en/notes/ai-collaboration-and-acceptance |
| Japanese | ja/ai-collaboration-and-acceptance |
ai-collaboration-and-acceptance |
/ja/notes/ai-collaboration-and-acceptance |
All three versions here use ai-collaboration-and-acceptance as their slug. The table looks repetitive because the current names happen to match. The code still handles “which entry,” “which article,” and “which URL” separately.
Matching by title could lose the connection to the original as soon as a translated title is reworded. Matching by identical slug values would make URL naming a requirement for establishing a translation relationship. stableId lets these decisions remain separate.
Entry IDs let all three files be loaded
Astro’s glob() loader generates a unique ID for each content entry and also allows ID generation to be customized.[1] This website keeps the combination of locale and filename, removing the .md extension to produce the entry ID.
The Traditional Chinese and English files can therefore have the same filename and still be two distinct entries: zh-TW/ai-collaboration-and-acceptance and en/ai-collaboration-and-acceptance.
This layer identifies entries when they are loaded. It does not determine which version is the original or mean that an article is ready to be made public. Drafts also need unique IDs so they can be found during proofreading.
stableId is a field defined by this website, not a translation system that Astro automatically creates for every multilingual site. Using the same approach requires defining the schema, uniqueness rules, and matching queries yourself.
stableId connects versions; slug remains responsible for the URL
After retrieving the collection of articles eligible for public output, an article page finds versions with the same stableId. It then uses each version’s locale and slug to generate language links and hreflang.
Identity validation is scoped to each locale. Within one language, two articles cannot share a slug, nor can two versions share a stableId. Versions of the same article in different languages can share a stableId. This catches duplicate identities, but it does not prove that the two bodies are actually translations of one another. The content still needs proofreading.
The URL rule is simpler: Traditional Chinese uses /notes/{slug}, while English and Japanese add their language prefixes. The title and category do not enter the URL calculation. Rewriting a description or adjusting a title therefore does not produce a new article URL.
The three language versions currently use the same slug. That is a naming choice, not a requirement of the matching function. If a language needs a different slug in the future, matching can still use the original stableId. How to handle the new URL and existing links, however, becomes a separate task that needs an explicit decision.
Know which identity you are changing before renaming it
I treat these changes separately:
- Changing the title changes the name readers see. The
stableIdandslugusually stay the same. - Adding a translation creates content with a different
locale, shares the same article’sstableId, and records that language version’s own completion and publication times. - Changing
slugchanges the public URL. It requires checking the effects on internal links, canonical URLs, and existing external links. - Changing
stableIdchanges the basis for matching versions. It cannot be changed in just one language version.
This is not an automatic migration system. This website has no general-purpose tool for arbitrary slug renaming, redirects from old URLs, or identity migration. Keeping stableId does not automatically repair links that point to the old URL, either.
Sometimes an article changes so much that its main question is entirely different. Whether it still counts as the same article requires editorial judgment. Keeping the same file is not enough to establish that every existing translation remains valid.
Shared identity does not replace each version’s publication requirements
If the Traditional Chinese version is public while the English version is still a draft, they can share a stableId, but the public article page only pairs versions that meet the publication requirements. An English draft does not automatically become a clickable language link just because its Traditional Chinese original can be found.
This also means translation progress does not have to produce exactly the same number of articles in all three languages. Identity data records that the versions belong to the same article. Publication data answers whether this particular version can be read publicly now.
To check this contract, start with an actual article available in all three languages. Verify the entry ID, stableId, locale, and slug of each version, then open the generated article pages to check the language links. Matching filenames alone are not proof that the versions have been paired correctly.
Scope of this record
This article draws on this website’s existing articles in three languages, content loader, identity validation, and article routes. The scenario in which different languages use different slugs explains the rules; it is not a completed URL-change case. This article does not cover automatic redirects, detection of differences between content versions, or translation-quality scoring.
Further reading: No translation should mean no fake language page.
Sources
[1] https://docs.astro.build/en/guides/content-collections — Astro — Content collections