
Separate three different decisions
Multilingual projects often combine the first language a visitor sees, the permanent URL for each language, and what a CDN can cache. This rebuild compared several approaches and settled on a simple rule: the root chooses a language, while real content lives at stable language URLs.
This is one tested design, not the only valid architecture. It fits a new corporate site with explicit language versions and CDN delivery.
Give content stable language URLs
Chinese pages live under /zh/; English pages live under /en/. Once a visitor opens one of those URLs, the server does not redirect them again based on browser language.
Each page uses a self-referencing canonical. When a complete counterpart exists, hreflang connects the language pair. A visible language link lets people switch without changing browser settings.
This gives search systems separate URLs to crawl and gives visitors a link that will not change language the next time it opens. Google likewise recommends separate URLs for language versions.
Use the root only for language selection
At /, the server first reads a language the visitor previously selected, then considers the browser's language. A clear signal receives a temporary 302 to /zh/ or /en/. Without a reliable signal, the root returns a bilingual selector.
That selector is x-default: the default destination when the site cannot choose a language. It is not a third language version.
The redirect is temporary because language preference can change. Unprefixed deep URLs do not duplicate the content, so every article or service retains one official URL per language.
Negotiation cannot be the only discovery path
Google warns against relying only on inferred-language redirects because people and crawlers may miss another version. Stable language URLs, reciprocal page links, hreflang, and visible switching remain necessary. The root is an entry, not the only route to content.

Why the root cannot use normal page caching
The root can return different results for different visitors. If a CDN stores the first response, later visitors may all receive the same language. The root therefore returns:
Cache-Control: private, no-store
Vary: Accept-Language, Cookieprivate, no-store means the negotiated result must not be stored. Vary records the request signals used to select it. Both origin and CDN must respect this boundary so one visitor's language choice is not reused for everyone else.
How regular pages are cached
Explicit language pages, CSS, JavaScript, and images do not vary by visitor. The tested cache policy returns:
Cache-Control: public, max-age=3600, s-maxage=2592000This verified setup gives browsers a one-hour copy and the CDN a thirty-day shared copy. Visitors open stable pages faster and origins avoid repeated transfers; APIs, private lead results, 404s, and server errors remain outside the shared cache. After the hour, ETag or Last-Modified can revalidate an unchanged browser copy.
These durations are project choices, not universal defaults. News, frequently changing prices, and a different release process need their own policy.
What implementation testing found
Automated tests cover four root visits: a prior Chinese choice, a prior English choice, a first visit with a browser language, and no reliable signal. They also confirm that explicit /zh/ and /en/ pages never negotiate again.
One test caught a small real defect: a redirect with no query parameters could still end with a question mark. The page worked, but the URL was untidy. Automated checks now cover both preservation of real parameters and removal of the empty marker.
Long shared caching requires release invalidation
A thirty-day shared cache cannot rely on natural expiry for publishing. The safe sequence is to deploy and verify the origins, submit an exact-URL invalidation, wait for completion, then confirm that new public pages produce CDN hits while the root and APIs remain uncached.
An invalidation failure must block release completion; otherwise origins may be current while customers still see old pages. Cache keys must also preserve functional query parameters instead of merging them merely to improve hit rate.
Browser and CDN caches are separate. A CDN purge does not remove the one-hour copy already stored in a visitor's browser. An urgent asset replacement may need a new fingerprinted filename or a different browser-cache policy.
Pre-release checklist
/zh/and/en/return content without another language redirect./behaves correctly for saved choices, Chinese and English browsers, and no signal.- Every page identifies itself as canonical and references only complete counterparts.
- The root, APIs, private results, and errors are not cached.
- HTTP and host redirects happen once while preserving paths and real query parameters.
- Verify origins, invalidate exact URLs, then confirm public-page CDN hits and private-route misses.
Sources and boundaries
- Google: Localized versions of your pages
- Google: Managing multi-regional and multilingual sites
- Alibaba Cloud CDN: Cache expiration
- Alibaba Cloud CDN: Refresh and prefetch
The official sources establish URL and CDN behavior. The directory structure, durations, negotiation order, test cases, and redirect defect come from this implementation.