Make the first screen a language choice; Chinese gets the CJK console and zh_CN

The CJK console unpacks Noto Sans Mono CJK from the offline mirror instead
of shipping fonts in the live image, lists only US-keymap keyboards and
preselects Pinyin. The target's LANG comes through locale_config.
This commit is contained in:
ZacharyZhang-NY committed 2026-10-09 00:15:06 -04:00
1 parent e8715fc888
commit 25cebcf3fd
7 files changed
+107 -74

No files matched your search

+1 -1
View File
@@ -28,7 +28,7 @@ Despite the local folder name, the first argument is the Omarchy source checkout
A local-source install pins `omarchy-dev` and `omarchy-settings-dev`, since the published builds share their version number but lack the local changes. `IgnorePkg` in `/etc/pacman.conf` makes updates skip them, and a `pre-refresh-pacman` hook (in the user's `~/.config/omarchy/hooks` and in `/etc/skel`) puts that line back after `omarchy refresh pacman`. `/etc/pacman.d/hooks/00-omarchy-pin-local-builds.hook` aborts any transaction that would still replace them. Remove all three to take the published packages.
The configurator asks for the region on its first screen. China reruns the installer in cage + foot, a console that draws Chinese: it opens on a bilingual region screen, keeps a US keyboard, and every later screen and the install progress read in Chinese. Choosing Global there returns to the VT, which applies the chosen keymap; without a working display China continues in English on the VT. The Chinese text lives in `OMARCHY_ZH` tables beside the English it replaces.
The configurator asks for the language on its first screen: English or Simplified Chinese. Chinese reruns the installer in cage + foot, a console that draws Chinese, with Noto Sans Mono CJK unpacked from the offline mirror's `noto-fonts-cjk`. It opens on a bilingual language screen, offers only keyboards with a US keymap (cage keeps a US layout) and preselects Chinese (Simplified, Pinyin); every later screen and the install progress read in Chinese. Choosing English there returns to the VT, which applies the chosen keymap. Without a working display or the font, Chinese continues in English on the VT. Either way a Chinese install sets the target's `LANG` to `zh_CN.UTF-8` through archinstall's `locale_config`. The language never decides the region: that follows the timezone. The Chinese text lives in `OMARCHY_ZH` tables beside the English it replaces.
Use `--dev` or `--rc` to build against those package channels. Both `--dev` and `--edge` select the dev packages from the edge mirror.
+49 -37
View File
@@ -17,7 +17,8 @@
# or Chinese (Simplified, Pinyin)/(Traditional, Zhuyin).
# OMARCHY_PATH must be the source tree used to build the ISO.
# --encrypt Drive the encrypted install flow (default: unencrypted)
# --region REGION Pick global (default) or cn on the first screen
# --language LANG Pick en (default) or zh on the first screen; zh keeps the
# preselected Chinese (Simplified, Pinyin) keyboard
# --provision Drive the deferred-provisioning install flow: no user during install, the
# first boot runs omarchy-provision-owner and creates it there
# --reuse-base Skip the install phase if a base image already exists
@@ -43,7 +44,7 @@ MEMORY=8192
INSTALL_TIMEOUT=2400
BOOT_TIMEOUT=600
ENCRYPT=false
REGION=global
INSTALL_LANGUAGE=en
PROVISION=false
REUSE_BASE=false
INSTALL_ONLY=false
@@ -61,7 +62,7 @@ while (($#)); do
case "$1" in
--keyboard) KEYBOARD_LABEL="$2"; shift ;;
--encrypt) ENCRYPT=true ;;
--region) REGION="$2"; shift ;;
--language) INSTALL_LANGUAGE="$2"; shift ;;
--provision) PROVISION=true ;;
--reuse-base) REUSE_BASE=true ;;
--install-only) INSTALL_ONLY=true ;;
@@ -92,8 +93,12 @@ if [[ ! -f ${ISO:-} ]]; then
exit 1
fi
if [[ $REGION != "global" && $REGION != "cn" ]]; then
echo "--region must be global or cn, not $REGION" >&2
if [[ $INSTALL_LANGUAGE != "en" && $INSTALL_LANGUAGE != "zh" ]]; then
echo "--language must be en or zh, not $INSTALL_LANGUAGE" >&2
exit 1
fi
if [[ $INSTALL_LANGUAGE == "zh" && $KEYBOARD_LABEL != "English (US)" ]]; then
echo "--language zh takes the preselected Pinyin keyboard; drop --keyboard" >&2
exit 1
fi
case "$KEYBOARD_LABEL" in
@@ -103,12 +108,12 @@ esac
omarchy-pkg-add qemu-full edk2-ovmf socat imagemagick tesseract tesseract-data-eng tesseract-data-chi_sim
# After the region screen a China install reads in Chinese.
# After the language screen a Chinese install reads in Chinese.
OCR_LANGS=eng
[[ $REGION == "cn" ]] && OCR_LANGS=eng+chi_sim
# region_text <english> <chinese> picks the text a screen shows in this run.
region_text() {
if [[ $REGION == "cn" ]]; then
[[ $INSTALL_LANGUAGE == "zh" ]] && OCR_LANGS=eng+chi_sim
# lang_text <english> <chinese> picks the text a screen shows in this run.
lang_text() {
if [[ $INSTALL_LANGUAGE == "zh" ]]; then
printf '%s' "$2"
else
printf '%s' "$1"
@@ -123,7 +128,7 @@ if [[ $KEYBOARD_LABEL != "English (US)" ]]; then
BASE_NAME+="-$(printf '%s' "$KEYBOARD_LABEL" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g')"
fi
$ENCRYPT && BASE_NAME+="-encrypted"
[[ $REGION == "cn" ]] && BASE_NAME+="-cn"
[[ $INSTALL_LANGUAGE == "zh" ]] && BASE_NAME+="-zh"
$PROVISION && BASE_NAME+="-provision"
BASE_DIR="$REPO_DIR/test-runs/$BASE_NAME"
RUN_DIR="$BASE_DIR/runs/$(date +%Y%m%d-%H%M%S)"
@@ -273,8 +278,8 @@ ocr_screen() {
screendump "$shot"
[[ -s $shot ]] || return 0
magick "$shot" -colorspace gray -negate -resize 150% "$prepped" 2>/dev/null || return 0
# The logo and the black strip under foot throw tesseract off CJK, so China runs also read between them, without spaces.
if [[ $REGION == "cn" ]]; then
# The logo and the black strip under foot throw tesseract off CJK, so Chinese runs also read between them, without spaces.
if [[ $INSTALL_LANGUAGE == "zh" ]]; then
magick "$shot" -gravity north -chop 0x35% -gravity south -chop 0x4% -colorspace gray -negate -resize 150% "$prepped.text.png" 2>/dev/null || return 0
{ tesseract "$prepped" - --psm 6 -l "$OCR_LANGS"; tesseract "$prepped.text.png" - --psm 6 -l "$OCR_LANGS"; } 2>/dev/null | sed 'p; s/ //g' || true
else
@@ -686,28 +691,35 @@ drive_configurator() {
capture_console "success-installer-00-greeter"
press ret
# Region comes first: Global on top, China below, either one preselected.
wait_for_screen "Select region" 300
capture_console "success-installer-01-region"
if [[ $REGION == "cn" ]]; then press end; else press home; fi
# Language comes first: English on top, Chinese below.
wait_for_screen "Select language" 300
capture_console "success-installer-01-language"
if [[ $INSTALL_LANGUAGE == "zh" ]]; then press end; else press home; fi
press ret
# Global asks for the keyboard; China reruns in cage + foot on a bilingual region screen with a US keyboard. Ctrl+C on either defers provisioning.
wait_for_screen "$(region_text "keyboard layout" "选择区域")" 300
# Chinese reruns in cage + foot on a bilingual language screen, Chinese preselected.
if [[ $INSTALL_LANGUAGE == "zh" ]]; then
wait_for_screen "选择语言" 300
capture_console "success-installer-01-language-cjk"
press ret
fi
# The keyboard follows; Ctrl+C there defers provisioning.
wait_for_screen "$(lang_text "keyboard layout" "键盘布局")" 300
capture_console "success-installer-01-keyboard-layout"
if $PROVISION; then
press ctrl-c # arm "prepare for another owner"
wait_for_screen "$(region_text "another owner" "另一位")" 30
wait_for_screen "$(lang_text "another owner" "另一位")" 30
capture_console "success-installer-02-prepare-confirm"
press ret # "Yes, prepare for another owner" is the affirmative default
# Jumps straight to disk selection, then the overwrite confirm.
wait_for_screen "$(region_text "install disk" "安装磁盘")" 60
wait_for_screen "$(lang_text "install disk" "安装磁盘")" 60
capture_console "success-installer-03-prepare-install-disk"
press ret
wait_for_screen "$(region_text "recovery possible" "无法恢复")" 60
wait_for_screen "$(lang_text "recovery possible" "无法恢复")" 60
capture_console "success-installer-04-prepare-disk-warning-encrypted"
if ! $ENCRYPT; then
press ctrl-c
@@ -731,27 +743,27 @@ drive_configurator() {
press ret
# Normal flow: user step comes before disk selection.
wait_for_screen "$(region_text "Username" "用户名")" 120
wait_for_screen "$(lang_text "Username" "用户名")" 120
type_text "$GUEST_USER"
capture_console "success-installer-02-username"
press ret
wait_for_screen "$(region_text "Password" "密码")" 60
wait_for_screen "$(lang_text "Password" "密码")" 60
type_text "$GUEST_PASSWORD"
capture_console "success-installer-03-password"
press ret
wait_for_screen "$(region_text "Must match" "确认")" 60
wait_for_screen "$(lang_text "Must match" "确认")" 60
type_text "$GUEST_PASSWORD"
capture_console "success-installer-04-password-confirmation"
press ret
wait_for_screen "$(region_text "Full name" "姓名")" 60
wait_for_screen "$(lang_text "Full name" "姓名")" 60
type_text "Omarchy Test"
capture_console "success-installer-05-full-name"
press ret
wait_for_screen "$(region_text "Email address" "邮箱")" 60
wait_for_screen "$(lang_text "Email address" "邮箱")" 60
type_text "test"
if [[ $KEYBOARD_LABEL == "Japanese" ]]; then
press bracket_left
@@ -764,30 +776,30 @@ drive_configurator() {
capture_console "success-installer-06-email"
press ret
wait_for_screen "$(region_text "Hostname" "主机名")" 60
wait_for_screen "$(lang_text "Hostname" "主机名")" 60
type_text "$GUEST_HOSTNAME"
capture_console "success-installer-07-hostname"
press ret
wait_for_screen "$(region_text "Timezone" "时区")" 180 # tzupdate geo-guess can take a moment
wait_for_screen "$(lang_text "Timezone" "时区")" 180 # tzupdate geo-guess can take a moment
capture_console "success-installer-08-timezone"
press ret
wait_for_screen "$(region_text "look right" "正确")" 60
wait_for_screen "$(lang_text "look right" "正确")" 60
capture_console "success-installer-09-review"
press ret
wait_for_screen "$(region_text "install disk" "安装磁盘")" 60
wait_for_screen "$(lang_text "install disk" "安装磁盘")" 60
capture_console "success-installer-10-install-disk"
press ret # the single virtio disk
wait_for_screen "$(region_text "installation mode\|recovery possible" "安装方式\|无法恢复")" 60
if ocr_screen | grep -qi "$(region_text "installation mode" "安装方式")"; then
wait_for_screen "$(lang_text "installation mode\|recovery possible" "安装方式\|无法恢复")" 60
if ocr_screen | grep -qi "$(lang_text "installation mode" "安装方式")"; then
capture_console "success-installer-11-install-mode"
press ret # "Full disk install" is preselected
fi
wait_for_screen "$(region_text "recovery possible" "无法恢复")" 60
wait_for_screen "$(lang_text "recovery possible" "无法恢复")" 60
capture_console "success-installer-12-disk-warning-encrypted"
if ! $ENCRYPT; then
press ctrl-c # toggles the confirm to the unencrypted flow
@@ -891,8 +903,8 @@ wait_for_install() {
while true; do
text=$(ocr_screen)
# OCR cannot read the Chinese reboot button, so China matches the title above it.
if grep -qi "$(region_text "Reboot Now" "安装完成")" <<<"$text"; then
# OCR cannot read the Chinese reboot button, so Chinese runs match the title above it.
if grep -qi "$(lang_text "Reboot Now" "安装完成")" <<<"$text"; then
log "Install finished. Confirming the reboot prompt."
capture_console "success-installer-15-reboot"
press ret
@@ -908,7 +920,7 @@ wait_for_install() {
return 0
fi
if grep -qi "$(region_text "installation stopped" "安装已停止")" <<<"$text"; then
if grep -qi "$(lang_text "installation stopped" "安装已停止")" <<<"$text"; then
capture_console "failure-installer-installation-stopped"
echo "Install failed — screenshot saved to $RUN_DIR" >&2
return 1
+2 -2
View File
@@ -124,8 +124,8 @@ cp "/tmp/$NODE_FILENAME" "$build_cache_dir/airootfs/opt/packages/"
# The selected omarchy-settings package is needed here so its post_install hook
# drops Omarchy's plymouthd.conf into /etc/plymouth before mkarchiso builds the
# live initramfs.
# cage, foot and the two fonts give China installs a console that draws Chinese.
arch_packages=(linux-t2 git gum jq openssl plymouth ttfx tzupdate omarchy-keyring "$OMARCHY_SETTINGS_PACKAGE" lvm2 cryptsetup parted cage foot ttf-jetbrains-mono wqy-microhei)
# cage and foot give Chinese installs a console that draws Chinese.
arch_packages=(linux-t2 git gum jq openssl plymouth ttfx tzupdate omarchy-keyring "$OMARCHY_SETTINGS_PACKAGE" lvm2 cryptsetup parted cage foot)
printf '%s\n' "${arch_packages[@]}" >> "$build_cache_dir/packages.x86_64"
# The live ISO boots linux-t2 (see airootfs/etc/mkinitcpio.d/linux-t2.preset), so
+20 -4
View File
@@ -94,6 +94,16 @@ warm_offline_mirror &
warm_pid=$!
trap 'kill "$warm_pid" 2>/dev/null' EXIT
# The CJK console's font comes from the offline mirror's noto-fonts-cjk, not the live image.
unpack_cjk_font() {
local packages=(/var/cache/omarchy/mirror/offline/noto-fonts-cjk-*.pkg.tar.zst)
if ((${#packages[@]} != 1)) || [[ ! -f ${packages[0]} ]]; then
echo "Expected one noto-fonts-cjk package in the offline mirror, found: ${packages[*]}" >&2
return 1
fi
bsdtar -xf "${packages[0]}" -C / usr/share/fonts/noto-cjk/NotoSansCJK-Regular.ttc
}
cd /root
# Autoinstall: a cidata drive carrying the configurator's own output files
# stands in for the wizard. omarchy-cidata-load copies them into /root and
@@ -102,7 +112,7 @@ if /usr/local/bin/omarchy-cidata-load; then
echo "Autoinstall configuration found on cidata drive; skipping the configurator."
export OMARCHY_UI_INTERACTIVE=no
else
# China moves to cage + foot, which draw Chinese; Global moves back to the VT, which applies keymaps.
# Chinese moves to cage + foot, which draw Chinese; English moves back to the VT, which applies keymaps.
cjk_relaunch=10
vt_return=11
if [[ -n ${OMARCHY_CJK_CONSOLE:-} ]]; then
@@ -115,17 +125,23 @@ else
cjk_runtime=/run/omarchy-cjk-console
mkdir -p -m 700 "$cjk_runtime"
rm -f "$cjk_runtime/cjk-console-started" "$cjk_runtime/return-to-vt"
if ! unpack_cjk_font; then
echo "The Chinese font could not be unpacked from the offline mirror; continuing in English."
unset OMARCHY_CJK_RELAUNCH
OMARCHY_INSTALL_LANGUAGE=zh ./configurator && status=0 || status=$?
continue
fi
cage_status=0
env -u OMARCHY_CJK_RELAUNCH XDG_RUNTIME_DIR=$cjk_runtime OMARCHY_CJK_CONSOLE=1 OMARCHY_INSTALL_REGION=cn \
env -u OMARCHY_CJK_RELAUNCH XDG_RUNTIME_DIR=$cjk_runtime OMARCHY_CJK_CONSOLE=1 OMARCHY_INSTALL_LANGUAGE=zh \
LANG=C.UTF-8 WLR_RENDERER=pixman cage -- foot -c /usr/share/omarchy-iso/foot.ini "$0" || cage_status=$?
if [[ -f $cjk_runtime/return-to-vt ]]; then
OMARCHY_INSTALL_REGION=global ./configurator && status=0 || status=$?
OMARCHY_INSTALL_LANGUAGE=en ./configurator && status=0 || status=$?
elif [[ -f $cjk_runtime/cjk-console-started ]]; then
exit "$cage_status"
else
echo "The Chinese console could not start (cage exit $cage_status); continuing in English."
unset OMARCHY_CJK_RELAUNCH
OMARCHY_INSTALL_REGION=cn ./configurator && status=0 || status=$?
OMARCHY_INSTALL_LANGUAGE=zh ./configurator && status=0 || status=$?
fi
done
if [[ -n ${OMARCHY_CJK_CONSOLE:-} ]] && ((status == vt_return)); then
+31 -26
View File
@@ -45,8 +45,6 @@ OMARCHY_ZH+=(
["Hostname"]="主机名"
["Keyboard"]="键盘"
["Region"]="区域"
["Global"]="全球"
["China"]="中国"
["[Skipped]"]="[已跳过]"
["Yes"]="是"
["No, change it"]="否,去修改"
@@ -271,15 +269,24 @@ notice() {
# STEP 1: KEYBOARD LAYOUT
# .automated_script.sh moves China into the CJK console and Global back to the VT, which applies keymaps.
apply_region_language() {
if [[ $region == "cn" && -n ${OMARCHY_CJK_RELAUNCH:-} ]]; then
# The target's LANG follows the language picked on the first screen.
target_lang() {
if [[ $language == "zh" ]]; then
echo zh_CN.UTF-8
else
echo en_US.UTF-8
fi
}
# .automated_script.sh moves Chinese into the CJK console and English back to the VT, which applies keymaps.
apply_language() {
if [[ $language == "zh" && -n ${OMARCHY_CJK_RELAUNCH:-} ]]; then
exit "$OMARCHY_CJK_RELAUNCH"
fi
if [[ $region == "global" && -n ${OMARCHY_VT_RETURN:-} ]]; then
if [[ $language == "en" && -n ${OMARCHY_VT_RETURN:-} ]]; then
exit "$OMARCHY_VT_RETURN"
fi
if [[ $region == "cn" && -n ${OMARCHY_CJK_CONSOLE:-} ]]; then
if [[ $language == "zh" && -n ${OMARCHY_CJK_CONSOLE:-} ]]; then
export OMARCHY_INSTALL_LANG=zh
else
unset OMARCHY_INSTALL_LANG
@@ -299,16 +306,14 @@ keyboard_form() {
say --foreground 8 "$(omarchy_text "Press Ctrl+C to prepare this machine for another owner.")"
echo
omarchy_prompt_region && status=0 || status=$?
omarchy_prompt_language && status=0 || status=$?
if ((status == 0)); then
apply_region_language
# cage keeps its US layout, so the CJK console offers no other.
if [[ -n ${OMARCHY_CJK_CONSOLE:-} ]]; then
keyboard="us"
keyboard_label="English (US)"
else
omarchy_prompt_keyboard && status=0 || status=$?
fi
apply_language
local layouts=$OMARCHY_KEYBOARD_LAYOUTS selected="English (US)"
[[ $language == "zh" ]] && selected="Chinese (Simplified, Pinyin)"
# cage keeps its US layout, so the CJK console offers only US-keymap keyboards.
[[ -n ${OMARCHY_CJK_CONSOLE:-} ]] && layouts=$(awk -F'|' '$2 == "us"' <<<"$layouts")
OMARCHY_KEYBOARD_LAYOUTS=$layouts omarchy_prompt_keyboard "$selected" && status=0 || status=$?
fi
((status == 0)) && break
@@ -385,10 +390,10 @@ user_step() {
# The timezone selects the region (mirrors and repositories), using the
# same lookup as the orchestrator. Global installs get no extra row.
local summary_region region_row=""
summary_region=$(cd /usr/share/omarchy-iso 2>/dev/null && python -m orchestrator.region "$timezone") || summary_region="global"
if [[ $summary_region != "global" ]]; then
region_row="\n$(omarchy_text Region),$summary_region"
region=$(cd /usr/share/omarchy-iso 2>/dev/null && python -m orchestrator.region "$timezone") || region="global"
region_row=""
if [[ $region != "global" ]]; then
region_row="\n$(omarchy_text Region),$region"
fi
# Add manual padding since gum table -p doesn't respect padding
@@ -937,7 +942,7 @@ run_partition_execute() {
"locale_config": {
"kb_layout": "$keyboard",
"sys_enc": "UTF-8",
"sys_lang": "en_US.UTF-8"
"sys_lang": "$(target_lang)"
},
"mirror_config": {
"custom_repositories": [],
@@ -1139,15 +1144,15 @@ select_installation() {
defer_provisioning=false
install_target="full_disk"
# A rerun arrives with the console language chosen; otherwise Global.
region="${OMARCHY_INSTALL_REGION:-global}"
# A rerun arrives with the language chosen; otherwise English.
language="${OMARCHY_INSTALL_LANGUAGE:-en}"
# Let the live VT reach its settled width before the first screen so the logo
# isn't measured against the transient 80-column boot console.
wait_for_stable_terminal
if [[ -n ${OMARCHY_INSTALL_REGION:-} ]]; then
apply_region_language
if [[ -n ${OMARCHY_INSTALL_LANGUAGE:-} ]]; then
apply_language
else
greeter
fi
@@ -1336,7 +1341,7 @@ cat <<-_EOF_ >user_configuration.json
"locale_config": {
"kb_layout": "$keyboard",
"sys_enc": "UTF-8",
"sys_lang": "en_US.UTF-8"
"sys_lang": "$(target_lang)"
},
"mirror_config": {
"custom_repositories": [],
@@ -1,6 +1,6 @@
# The China installer's console: the VT's Tokyo Night palette, with CJK from wqy-microhei.
# The Chinese installer's console: the VT's Tokyo Night palette, with Noto Sans Mono CJK from the offline mirror.
[main]
font=JetBrains Mono:size=13,WenQuanYi Micro Hei Mono:size=13
font=Noto Sans Mono CJK SC:size=13
[colors-dark]
background=1a1b26
+2 -2
View File
@@ -1,6 +1,6 @@
#!/bin/bash
#
# Every installer text needs an OMARCHY_ZH entry, or a China install shows it in English.
# Every installer text needs an OMARCHY_ZH entry, or a Chinese install shows it in English.
set -euo pipefail
@@ -33,7 +33,7 @@ for text in "${texts[@]}"; do
done
printf 'ok - every installer and dashboard text has a Chinese entry\n'
for action in "View full log" "Drop to shell" "Reboot" "Power off" "Upload log for support" "Global" "China"; do
for action in "View full log" "Drop to shell" "Reboot" "Power off" "Upload log for support"; do
[[ -n ${OMARCHY_ZH[$action]:-} ]] || fail "labels passed through variables have Chinese entries" "missing: $action"
done
printf 'ok - labels passed through variables have Chinese entries\n'