From a Theme to a Production-Grade Bilingual Blog on EdgeOne Pages
Once a blog reaches production, the important questions quickly go beyond whether the homepage loads. Language switching must remain reliable, search and RSS must exclude drafts, builds should be reproducible, caches must not preserve broken responses, and the deployment platform should use a controlled runtime.
EdgeOne Page was created to turn a regular Hexo theme into a production-oriented bilingual static blog for Tencent Cloud EdgeOne Pages. This article explains the architecture, the build pipeline, and the engineering decisions that made the site maintainable.
Why the site does not translate pages in the browser
The first design decision was how to represent Chinese and English content. Runtime translation looks convenient, but it can show the wrong language during first paint, produce unstable search indexing, break article-to-article language mapping, and make offline behavior depend on client-side code.
The project therefore stores each language independently:
1 | source/zh-CN/_posts/ |
Both versions of an article use the same file name and translation_key. The production build generates two standalone sites:
1 | /zh-CN/ |
A language switch opens the corresponding article instead of translating the current DOM. Canonical URLs, hreflang links, feeds, sitemaps, and offline caches can all remain language-specific.
Bilingual content is validated before the build
A directory convention alone does not prevent missing translations, mismatched keys, invalid dates, or placeholder text from reaching production.
The content validator now requires every published article to provide:
- both Simplified Chinese and English files;
- a
translation_keymatching the file slug; - valid publication and update dates;
- a useful search and sharing description;
- at least one category and two tags;
- enough body content to be a real article;
- the same publication state in both languages.
The article scaffolder creates both files as published: false drafts. A draft cannot enter the public search index, feed, or sitemap, and production checks reject placeholder content after publication is enabled.
One command builds both sites
The production entrypoint is:
1 | npm run build:production |
It generates the Chinese site, generates the English site, creates the root language entry, and then writes the static production features expected from a professional blog:
- local search indexes;
- Chinese and English RSS feeds;
- language sitemaps and a root sitemap index;
robots.txt;- root and localized 404 pages;
- bilingual hreflang links;
- PWA manifests;
- offline pages;
- a service worker;
- Schema.org structured data.
Everything is generated by repository scripts. The deployment does not require a database or a long-running application server.
Search, RSS, and sitemaps only contain published content
A subtle static-site failure occurs when Hexo excludes a draft from HTML output but a custom generator scans every Markdown file and exposes the same draft through search or RSS.
EdgeOne Page uses one shared content-record model. Search, feeds, sitemaps, validation, and production audits all apply the same publication filter. Records marked with either of the following are excluded:
1 | published: false |
1 | draft: true |
This prevents unpublished work from leaking through a secondary output channel.
Search and recommendations avoid native dependencies
Local search uses a generated JSON index and performs title, description, and content matching in the browser. Article recommendations combine shared tags, shared categories, keyword similarity, and publication recency.
The project considered nodejieba for more accurate Chinese tokenization. However, its native component can depend on a compatible Node ABI and build toolchain. A pure JavaScript tokenizer based on English terms and Chinese character pairs provides slightly less linguistic precision but much more predictable EdgeOne builds.
PWA quality depends on cache correctness
Each language receives its own manifest, while a single service worker manages the origin. Navigation uses a network-first strategy. Styles, scripts, images, and fonts use cached responses with background refresh.
The cache version is not based on the current time. It is derived from the paths and bytes in the final public directory. Identical source and content therefore produce the same cache version, while a real output change automatically creates a new version.
The worker ignores range requests, opaque third-party responses, unsuccessful responses, and its own script. When the network is unavailable, it opens the Chinese or English offline page according to the requested path.
EdgeOne deployment behavior is versioned with the code
The repository includes an edgeone.json file that fixes the deployment contract:
1 | { |
It also defines legacy language redirects, cache rules for the service worker, manifest content types, and baseline security headers. Deployment expectations live beside the source code instead of depending only on manually configured dashboard values.
CI audits the generated site, not only the source
GitHub Actions uses the same Node.js version as EdgeOne and installs dependencies from the lock file. It then runs:
1 | npm run check |
The command validates bilingual source content, builds the complete production output, and audits every published article. The audit confirms that each article has:
- a generated HTML page;
BlogPostingstructured data;- a canonical URL;
- Chinese and English hreflang links;
- a manifest link;
- service worker registration;
- exactly one robots meta tag.
It also compares the number of search records and RSS items with the number of published source articles, and verifies that service-worker versioning remains deterministic.
Engineering lessons from the project
First, bilingual publishing should begin with the content model, not with a translation button added at the end.
Second, static sites still need an explicit publication state. Every generator that reads source files must apply the same visibility rules as the main site build.
Third, the difficult part of a PWA is not creating a manifest. It is defining predictable update, caching, and failure behavior.
Fourth, production confidence should come from executable checks rather than visual inspection. Build scripts should verify files, metadata, and content counts before deployment.
Finally, deployment configuration, content rules, and audit rules should all be version-controlled. That is what makes a site reproducible, portable, and maintainable.
The current publishing workflow
The daily workflow is now:
1 | npm run new:post -- article-slug |
After the changes are pushed, GitHub Actions runs the same production checks and EdgeOne Pages rebuilds the repository using the committed deployment configuration.
EdgeOne Page will continue to improve responsive images, performance budgets, accessibility, and theme branding. It has already evolved from a working Hexo page into a bilingual publishing system with a content contract, a deployment contract, deterministic caching, and automated quality gates.
- Title: From a Theme to a Production-Grade Bilingual Blog on EdgeOne Pages
- Author: FukunHennan
- Created at : 2026-07-18 01:30:00
- Updated at : 2026-07-18 01:30:00
- Link: https://edgeone.chenfukun.space/en/posts/building-a-professional-bilingual-hexo-site-on-edgeone-pages/
- License : This work is licensed under CC BY-NC-SA 4.0.