diff --git a/src/components/Bi.astro b/src/components/Bi.astro
new file mode 100644
index 0000000..50b6877
--- /dev/null
+++ b/src/components/Bi.astro
@@ -0,0 +1,20 @@
+---
+// A piece of text in the page's language. On a page that picks its language in
+// the browser (the 404 page: GitHub Pages serves one for every language), both
+// are rendered and the page's script shows the visitor's.
+import { getLang } from "~/i18n";
+
+interface Props {
+ en: string;
+ zh: string;
+ /** Render both languages for the page's script to choose from */
+ both?: boolean;
+}
+
+const { en, zh, both = false } = Astro.props;
+const lang = getLang(Astro);
+---
+
+{both ? (
+ {en}{zh}
+) : lang === "zh-CN" ? zh : en}
diff --git a/src/components/SearchModal.astro b/src/components/SearchModal.astro
index 684836d..b323630 100644
--- a/src/components/SearchModal.astro
+++ b/src/components/SearchModal.astro
@@ -1,16 +1,34 @@
---
import { getLang } from "~/i18n";
+import Bi from "./Bi.astro";
+interface Props {
+ /** Render the text in both languages for the page's script to choose from (the 404 page; see Bi.astro) */
+ bilingual?: boolean;
+}
+
+const { bilingual = false } = Astro.props;
const lang = getLang(Astro);
-const placeholder = lang === "zh-CN" ? "搜索文档…" : "Search docs…";
-const buttonLabel = lang === "zh-CN" ? "搜索" : "Search";
-const emptyHint = lang === "zh-CN" ? "开始输入以搜索文档。" : "Start typing to search the docs.";
-const noResults = lang === "zh-CN" ? "未找到结果" : "No results";
-// Used when the page is a product's docs page (DocsLayout sets data-docs-product).
-const scopedPlaceholder = lang === "zh-CN" ? "搜索 {product} 文档…" : "Search {product} docs…";
-const scopeLabel = lang === "zh-CN" ? "范围" : "Scope";
-const scopeAll = lang === "zh-CN" ? "全部文档" : "All docs";
-const scopeProduct = lang === "zh-CN" ? "{product} 文档" : "{product} docs";
+const text = {
+ placeholder: { en: "Search docs…", zh: "搜索文档…" },
+ button: { en: "Search", zh: "搜索" },
+ emptyHint: { en: "Start typing to search the docs.", zh: "开始输入以搜索文档。" },
+ noResults: { en: "No results", zh: "未找到结果" },
+ // Used when the page is a product's docs page (DocsLayout sets data-docs-product).
+ scopedPlaceholder: { en: "Search {product} docs…", zh: "搜索 {product} 文档…" },
+ scopeLabel: { en: "Scope", zh: "范围" },
+ scopeAll: { en: "All docs", zh: "全部文档" },
+ scopeProduct: { en: "{product} docs", zh: "{product} 文档" },
+};
+const pick = (k: keyof typeof text) => (lang === "zh-CN" ? text[k].zh : text[k].en);
+const placeholder = pick("placeholder");
+const buttonLabel = pick("button");
+const emptyHint = pick("emptyHint");
+const noResults = pick("noResults");
+const scopedPlaceholder = pick("scopedPlaceholder");
+const scopeProduct = pick("scopeProduct");
+/** On a bilingual page, attributes the page's script swaps in for Chinese visitors */
+const zhAttrs = (attrs: Record) => (bilingual ? JSON.stringify(attrs) : undefined);
---
-
+