Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e22a13dfeb
|
No files matched your search
@@ -26,6 +26,8 @@ For local development, build the ISO from sibling checkouts:
|
||||
|
||||
Despite the local folder name, the first argument is the Omarchy source checkout (runtime commands, configs, setup scripts, themes, shell, migrations). The installer itself lives in this ISO repo.
|
||||
|
||||
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 the keyboard 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. Esc there goes back to a bilingual language screen, where English 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.
|
||||
|
||||
## Autoinstall
|
||||
|
||||
+58
-22
@@ -17,6 +17,7 @@
|
||||
# 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)
|
||||
# --language LANG Pick en (default) or zh; zh keeps the preselected 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
|
||||
@@ -42,6 +43,7 @@ MEMORY=8192
|
||||
INSTALL_TIMEOUT=2400
|
||||
BOOT_TIMEOUT=600
|
||||
ENCRYPT=false
|
||||
INSTALL_LANGUAGE=en
|
||||
PROVISION=false
|
||||
REUSE_BASE=false
|
||||
INSTALL_ONLY=false
|
||||
@@ -59,6 +61,7 @@ while (($#)); do
|
||||
case "$1" in
|
||||
--keyboard) KEYBOARD_LABEL="$2"; shift ;;
|
||||
--encrypt) ENCRYPT=true ;;
|
||||
--language) INSTALL_LANGUAGE="$2"; shift ;;
|
||||
--provision) PROVISION=true ;;
|
||||
--reuse-base) REUSE_BASE=true ;;
|
||||
--install-only) INSTALL_ONLY=true ;;
|
||||
@@ -89,12 +92,32 @@ if [[ ! -f ${ISO:-} ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
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
|
||||
"English (US)" | "English (UK)" | "Japanese" | "Japanese (US keyboard)" | "Korean" | "Chinese (Simplified, Pinyin)" | "Chinese (Traditional, Zhuyin)") ;;
|
||||
*) echo "The VM harness cannot type credentials with keyboard: $KEYBOARD_LABEL" >&2; exit 1 ;;
|
||||
esac
|
||||
|
||||
omarchy-pkg-add qemu-full edk2-ovmf socat imagemagick tesseract tesseract-data-eng
|
||||
omarchy-pkg-add qemu-full edk2-ovmf socat imagemagick tesseract tesseract-data-eng tesseract-data-chi_sim
|
||||
|
||||
# After the language screen a Chinese install reads in Chinese.
|
||||
OCR_LANGS=eng
|
||||
[[ $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"
|
||||
fi
|
||||
}
|
||||
|
||||
OVMF_CODE="/usr/share/edk2/x64/OVMF_CODE.4m.fd"
|
||||
OVMF_VARS_TEMPLATE="/usr/share/edk2/x64/OVMF_VARS.4m.fd"
|
||||
@@ -104,6 +127,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"
|
||||
[[ $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)"
|
||||
@@ -253,7 +277,13 @@ ocr_screen() {
|
||||
screendump "$shot"
|
||||
[[ -s $shot ]] || return 0
|
||||
magick "$shot" -colorspace gray -negate -resize 150% "$prepped" 2>/dev/null || return 0
|
||||
tesseract "$prepped" - --psm 6 2>/dev/null || true
|
||||
# The logo throws tesseract off CJK, so Chinese runs also read below it, without spaces.
|
||||
if [[ $INSTALL_LANGUAGE == "zh" ]]; then
|
||||
magick "$shot" -gravity north -chop 0x35% -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
|
||||
tesseract "$prepped" - --psm 6 -l "$OCR_LANGS" 2>/dev/null || true
|
||||
fi
|
||||
}
|
||||
|
||||
# Wait until the console shows the given text. Saves the offending screen as
|
||||
@@ -660,23 +690,28 @@ drive_configurator() {
|
||||
capture_console "success-installer-00-greeter"
|
||||
press ret
|
||||
|
||||
# Keyboard is the first screen. Ctrl+C there is the hidden entry into deferred provisioning
|
||||
# mode; a normal install just selects the layout.
|
||||
wait_for_screen "keyboard layout" 300
|
||||
# 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
|
||||
|
||||
# The keyboard follows, for Chinese in cage + foot; 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 "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 "install disk" 60
|
||||
wait_for_screen "$(lang_text "install disk" "安装磁盘")" 60
|
||||
capture_console "success-installer-03-prepare-install-disk"
|
||||
press ret
|
||||
|
||||
wait_for_screen "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
|
||||
@@ -700,27 +735,27 @@ drive_configurator() {
|
||||
press ret
|
||||
|
||||
# Normal flow: user step comes before disk selection.
|
||||
wait_for_screen "Username" 120
|
||||
wait_for_screen "$(lang_text "Username" "用户名")" 120
|
||||
type_text "$GUEST_USER"
|
||||
capture_console "success-installer-02-username"
|
||||
press ret
|
||||
|
||||
wait_for_screen "Password" 60
|
||||
wait_for_screen "$(lang_text "Password" "密码")" 60
|
||||
type_text "$GUEST_PASSWORD"
|
||||
capture_console "success-installer-03-password"
|
||||
press ret
|
||||
|
||||
wait_for_screen "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 "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 "Email address" 60
|
||||
wait_for_screen "$(lang_text "Email address" "邮箱")" 60
|
||||
type_text "test"
|
||||
if [[ $KEYBOARD_LABEL == "Japanese" ]]; then
|
||||
press bracket_left
|
||||
@@ -733,30 +768,30 @@ drive_configurator() {
|
||||
capture_console "success-installer-06-email"
|
||||
press ret
|
||||
|
||||
wait_for_screen "Hostname" 60
|
||||
wait_for_screen "$(lang_text "Hostname" "主机名")" 60
|
||||
type_text "$GUEST_HOSTNAME"
|
||||
capture_console "success-installer-07-hostname"
|
||||
press ret
|
||||
|
||||
wait_for_screen "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 "look right" 60
|
||||
wait_for_screen "$(lang_text "look right" "正确")" 60
|
||||
capture_console "success-installer-09-review"
|
||||
press ret
|
||||
|
||||
wait_for_screen "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 "installation mode\|recovery possible" 60
|
||||
if ocr_screen | grep -qi "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 "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
|
||||
@@ -860,7 +895,8 @@ wait_for_install() {
|
||||
while true; do
|
||||
text=$(ocr_screen)
|
||||
|
||||
if grep -qi "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
|
||||
@@ -876,7 +912,7 @@ wait_for_install() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
if grep -qi "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
|
||||
|
||||
@@ -121,7 +121,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.
|
||||
arch_packages=(linux-t2 git gum jq openssl plymouth ttfx tzupdate omarchy-keyring "$OMARCHY_SETTINGS_PACKAGE" lvm2 cryptsetup parted)
|
||||
# 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
|
||||
|
||||
@@ -10,7 +10,10 @@
|
||||
# - COLUMNS/LINES so gum picks up real terminal size
|
||||
set -euo pipefail
|
||||
|
||||
[[ $(tty) == /dev/tty1 ]] || exit 0
|
||||
[[ $(tty) == /dev/tty1 || -n ${OMARCHY_CJK_CONSOLE:-} ]] || exit 0
|
||||
if [[ -n ${OMARCHY_CJK_CONSOLE:-} ]]; then
|
||||
touch "$XDG_RUNTIME_DIR/cjk-console-started"
|
||||
fi
|
||||
|
||||
export OMARCHY_MIRROR="$(cat /root/omarchy_mirror)"
|
||||
if [[ -f /root/omarchy_iso_ref ]]; then
|
||||
@@ -39,7 +42,8 @@ set_tokyo_night_colors() {
|
||||
echo -en "\033[0m"
|
||||
clear
|
||||
}
|
||||
set_tokyo_night_colors
|
||||
# foot sets the same palette from foot.ini; these escapes are VT-only.
|
||||
[[ -n ${OMARCHY_CJK_CONSOLE:-} ]] || set_tokyo_night_colors
|
||||
|
||||
mkdir -p /var/log
|
||||
touch "$OMARCHY_INSTALL_LOG_FILE"
|
||||
@@ -90,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
|
||||
@@ -98,7 +112,43 @@ if /usr/local/bin/omarchy-cidata-load; then
|
||||
echo "Autoinstall configuration found on cidata drive; skipping the configurator."
|
||||
export OMARCHY_UI_INTERACTIVE=no
|
||||
else
|
||||
./configurator
|
||||
# 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
|
||||
export OMARCHY_VT_RETURN=$vt_return
|
||||
elif command -v cage >/dev/null; then
|
||||
export OMARCHY_CJK_RELAUNCH=$cjk_relaunch
|
||||
fi
|
||||
./configurator && status=0 || status=$?
|
||||
while ((status == cjk_relaunch)); do
|
||||
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_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_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_LANGUAGE=zh ./configurator && status=0 || status=$?
|
||||
fi
|
||||
done
|
||||
if [[ -n ${OMARCHY_CJK_CONSOLE:-} ]] && ((status == vt_return)); then
|
||||
touch "$XDG_RUNTIME_DIR/return-to-vt"
|
||||
exit 0
|
||||
fi
|
||||
((status == 0)) || exit "$status"
|
||||
fi
|
||||
|
||||
# Deferred-provisioning installs skip the celebration/reboot prompt and reboot on
|
||||
@@ -111,6 +161,11 @@ if [[ -f /root/defer-provisioning ]] ||
|
||||
export OMARCHY_UI_DEFER_PROVISIONING=yes
|
||||
fi
|
||||
|
||||
# Only Chinese reaches the install from the CJK console; English returns to the VT.
|
||||
if [[ -n ${OMARCHY_CJK_CONSOLE:-} ]]; then
|
||||
export OMARCHY_INSTALL_LANG=zh
|
||||
fi
|
||||
|
||||
# The foreground dashboard is now the sole visible install UI owner. It starts
|
||||
# the actual installer as a non-interactive child, logs child output, waits for
|
||||
# completion, then renders the final installed-time/reboot prompt itself.
|
||||
|
||||
@@ -24,6 +24,72 @@ if [[ ! -r $SETUP_FORM ]]; then
|
||||
fi
|
||||
source "$SETUP_FORM"
|
||||
|
||||
# Chinese text for OMARCHY_INSTALL_LANG=zh; disk-step failures stay English for support logs.
|
||||
OMARCHY_ZH+=(
|
||||
["Aborted installation"]="安装已中止"
|
||||
["You can retry later by running: ./.automated_script.sh"]="稍后可运行 ./.automated_script.sh 重试"
|
||||
["Let's setup your machine..."]="开始设置这台机器……"
|
||||
["Press Ctrl+C to prepare this machine for another owner."]="按 Ctrl+C 为另一位使用者准备这台机器。"
|
||||
["This prepares the machine for another owner."]="这会为另一位使用者准备这台机器。"
|
||||
["The system installs now, but setup is delayed until first boot."]="系统现在安装,设置留到首次开机。"
|
||||
["Yes, prepare for another owner"]="是,为他人准备"
|
||||
["No, keep setting up"]="否,继续设置"
|
||||
["Prepare this machine for another owner?"]="为另一位使用者准备这台机器?"
|
||||
["Let's setup your user account..."]="开始设置用户账户……"
|
||||
["Field"]="项目"
|
||||
["Value"]="值"
|
||||
["Username"]="用户名"
|
||||
["Password"]="密码"
|
||||
["Full name"]="姓名"
|
||||
["Email address"]="邮箱"
|
||||
["Hostname"]="主机名"
|
||||
["Keyboard"]="键盘"
|
||||
["Region"]="区域"
|
||||
["[Skipped]"]="[已跳过]"
|
||||
["Yes"]="是"
|
||||
["No, change it"]="否,去修改"
|
||||
["Does this look right?"]="以上信息正确吗?"
|
||||
["Not enough free space on %s"]="%s 的空闲空间不足"
|
||||
["%s has %s of usable free space; Omarchy needs at least 32GB."]="%s 有 %s 可用空闲空间;Omarchy 至少需要 32GB。"
|
||||
["Open the partition tool to free at least 32GB on %s, then try again."]="打开分区工具,在 %s 上腾出至少 32GB,然后重试。"
|
||||
["Back"]="返回"
|
||||
["Open partition tool"]="打开分区工具"
|
||||
["Return to installation mode?"]="返回安装方式选择?"
|
||||
["Checking for BitLocker on %s"]="检查 %s 上的 BitLocker"
|
||||
["BitLocker signature detected on %s."]="在 %s 上发现 BitLocker 签名。"
|
||||
["Turn BitLocker off in Windows and wait for the drive to finish decrypting, then try again."]="在 Windows 中关闭 BitLocker,等磁盘解密完成后重试。"
|
||||
["Suspending BitLocker is not enough — the drive stays encrypted."]="只暂停 BitLocker 不够,磁盘仍是加密的。"
|
||||
["Aborted: BitLocker is enabled on this disk."]="已中止:这块磁盘开启了 BitLocker。"
|
||||
["Checking existing EFI partitions on %s"]="检查 %s 上已有的 EFI 分区"
|
||||
["Found a Windows ESP at %s — leaving it untouched."]="在 %s 发现 Windows ESP,保持不动。"
|
||||
["Omarchy will create its own dedicated EFI partition in free space."]="Omarchy 会在空闲空间中创建自己的 EFI 分区。"
|
||||
["A new EFI partition will be created in free space."]="会在空闲空间中新建 EFI 分区。"
|
||||
["Analyzing free space on %s"]="分析 %s 的空闲空间"
|
||||
["Install Omarchy in the %s of free space."]="在 %s 空闲空间中安装 Omarchy。"
|
||||
["Press Ctrl+C for unencrypted install."]="按 Ctrl+C 改为不加密安装。"
|
||||
["Yes, install"]="是,开始安装"
|
||||
["Yes, install without encryption"]="是,不加密安装"
|
||||
["Confirm installing on %s"]="确认安装到 %s"
|
||||
["Creating partitions on %s"]="在 %s 上创建分区"
|
||||
["Setting up LUKS2 on %s"]="在 %s 上设置 LUKS2 加密"
|
||||
["Creating Btrfs filesystem and subvolumes"]="创建 Btrfs 文件系统和子卷"
|
||||
["Let's select where to install Omarchy..."]="选择 Omarchy 的安装位置……"
|
||||
["Select install disk"]="选择安装磁盘"
|
||||
["Partition tool for %s"]="%s 的分区工具"
|
||||
["Create unallocated free space for Omarchy, then write changes and quit."]="为 Omarchy 腾出未分配空间,然后写入更改并退出。"
|
||||
["Do not create an Omarchy partition here — leave the target area as Free space."]="不要在这里创建 Omarchy 分区,目标区域保持为 Free space。"
|
||||
["Tip: free-space install needs at least 32GB unallocated, plus 2GB more if no ESP already exists."]="提示:空闲空间安装至少需要 32GB 未分配空间;没有 ESP 时再加 2GB。"
|
||||
["Open cfdisk"]="打开 cfdisk"
|
||||
["Open partition tool for %s?"]="打开 %s 的分区工具?"
|
||||
["Full disk install"]="整盘安装"
|
||||
["Free space install (alongside existing data)"]="空闲空间安装(保留现有数据)"
|
||||
["Choose a different disk"]="换一块磁盘"
|
||||
["Let's select how to install Omarchy..."]="选择 Omarchy 的安装方式……"
|
||||
["Select installation mode on %s"]="选择 %s 上的安装方式"
|
||||
["Everything will be overwritten. There is no recovery possible."]="磁盘上的一切都会被覆盖,无法恢复。"
|
||||
["Confirm overwriting %s"]="确认覆盖 %s"
|
||||
)
|
||||
|
||||
# Partition creation helpers, shared with test/partition-numbering-test.sh so
|
||||
# the numbering logic can be exercised without a real disk.
|
||||
DISK_PARTITIONING="${DISK_PARTITIONING:-/usr/share/omarchy-iso/disk-partitioning.sh}"
|
||||
@@ -176,9 +242,9 @@ greeter() {
|
||||
}
|
||||
|
||||
abort() {
|
||||
gum style "${1:-Aborted installation}"
|
||||
gum style "${1:-$(omarchy_text "Aborted installation")}"
|
||||
echo
|
||||
gum style "You can retry later by running: ./.automated_script.sh"
|
||||
gum style "$(omarchy_text "You can retry later by running: ./.automated_script.sh")"
|
||||
exit 1
|
||||
}
|
||||
|
||||
@@ -203,6 +269,30 @@ notice() {
|
||||
|
||||
# STEP 1: KEYBOARD LAYOUT
|
||||
|
||||
# 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 [[ $language == "en" && -n ${OMARCHY_VT_RETURN:-} ]]; then
|
||||
exit "$OMARCHY_VT_RETURN"
|
||||
fi
|
||||
if [[ $language == "zh" && -n ${OMARCHY_CJK_CONSOLE:-} ]]; then
|
||||
export OMARCHY_INSTALL_LANG=zh
|
||||
else
|
||||
unset OMARCHY_INSTALL_LANG
|
||||
fi
|
||||
}
|
||||
|
||||
keyboard_form() {
|
||||
# Ctrl+C is the hidden entry into deferred provisioning, offered on every
|
||||
# visit: the user step unwinds back here and nothing is on disk yet. Callers
|
||||
@@ -212,11 +302,24 @@ keyboard_form() {
|
||||
while true; do
|
||||
clear_logo
|
||||
echo
|
||||
say "Let's setup your machine..."
|
||||
say --foreground 8 "Press Ctrl+C to prepare this machine for another owner."
|
||||
say "$(omarchy_text "Let's setup your machine...")"
|
||||
say --foreground 8 "$(omarchy_text "Press Ctrl+C to prepare this machine for another owner.")"
|
||||
echo
|
||||
|
||||
omarchy_prompt_keyboard && status=0 || status=$?
|
||||
status=0
|
||||
if ! $language_chosen; then
|
||||
omarchy_prompt_language && status=0 || status=$?
|
||||
((status == 0)) && apply_language
|
||||
fi
|
||||
# Esc, Ctrl+C or a later "No, change it" asks the language again.
|
||||
language_chosen=false
|
||||
if ((status == 0)); then
|
||||
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
|
||||
|
||||
# Esc means "back", and nothing precedes the first screen, so re-ask.
|
||||
@@ -245,11 +348,11 @@ keyboard_form() {
|
||||
confirm_prepare_for_another_owner() {
|
||||
clear_logo
|
||||
echo
|
||||
say "This prepares the machine for another owner."
|
||||
say --foreground 8 "The system installs now, but setup is delayed until first boot."
|
||||
say "$(omarchy_text "This prepares the machine for another owner.")"
|
||||
say --foreground 8 "$(omarchy_text "The system installs now, but setup is delayed until first boot.")"
|
||||
echo
|
||||
gum confirm --affirmative "Yes, prepare for another owner" --negative "No, keep setting up" \
|
||||
"Prepare this machine for another owner?"
|
||||
gum confirm --affirmative "$(omarchy_text "Yes, prepare for another owner")" --negative "$(omarchy_text "No, keep setting up")" \
|
||||
"$(omarchy_text "Prepare this machine for another owner?")"
|
||||
}
|
||||
|
||||
# The user step. Deferred-provisioning installs skip it entirely — the machine's first owner
|
||||
@@ -257,7 +360,7 @@ confirm_prepare_for_another_owner() {
|
||||
# operator sets nothing user-specific.
|
||||
|
||||
user_form() {
|
||||
step "Let's setup your user account..."
|
||||
step "$(omarchy_text "Let's setup your user account...")"
|
||||
|
||||
# Each prompt reports 0 (set), OMARCHY_FORM_BACK (Esc), or OMARCHY_FORM_SIGNAL
|
||||
# (Ctrl+C). Both non-zero cases unwind to user_step, which decides what they
|
||||
@@ -295,22 +398,24 @@ user_step() {
|
||||
region=$(cd /usr/share/omarchy-iso 2>/dev/null && python -m orchestrator.region "$timezone") || region="global"
|
||||
region_row=""
|
||||
if [[ $region != "global" ]]; then
|
||||
region_row="\nRegion,$region"
|
||||
region_row="\n$(omarchy_text Region),$region"
|
||||
fi
|
||||
|
||||
# Add manual padding since gum table -p doesn't respect padding
|
||||
echo -e "Field,Value
|
||||
Username,$username
|
||||
Password,$(printf "%${#password}s" | tr ' ' '*')
|
||||
Full name,${full_name:-[Skipped]}
|
||||
Email address,${email_address:-[Skipped]}
|
||||
Hostname,$hostname
|
||||
Timezone,$timezone$region_row
|
||||
Keyboard,$keyboard" |
|
||||
local skipped
|
||||
skipped=$(omarchy_text "[Skipped]")
|
||||
echo -e "$(omarchy_text Field),$(omarchy_text Value)
|
||||
$(omarchy_text Username),$username
|
||||
$(omarchy_text Password),$(printf "%${#password}s" | tr ' ' '*')
|
||||
$(omarchy_text "Full name"),${full_name:-$skipped}
|
||||
$(omarchy_text "Email address"),${email_address:-$skipped}
|
||||
$(omarchy_text Hostname),$hostname
|
||||
$(omarchy_text Timezone),$timezone$region_row
|
||||
$(omarchy_text Keyboard),\"$keyboard_label\"" |
|
||||
gum table -s "," -p | sed "s/^/${PADDING_LEFT_SPACES}/"
|
||||
|
||||
echo
|
||||
if gum confirm --negative "No, change it" "Does this look right?"; then
|
||||
if gum confirm --affirmative "$(omarchy_text "Yes")" --negative "$(omarchy_text "No, change it")" "$(omarchy_text "Does this look right?")"; then
|
||||
break
|
||||
else
|
||||
keyboard_form
|
||||
@@ -512,11 +617,11 @@ print_dry_run_files() {
|
||||
# action so users have a way to actually fix the situation.
|
||||
not_enough_space() {
|
||||
local available="${1:-0}"
|
||||
step "Not enough free space on $disk"
|
||||
say --foreground 1 "$disk has $(to_gb $available) of usable free space; Omarchy needs at least 32GB."
|
||||
say "Open the partition tool to free at least 32GB on $disk, then try again."
|
||||
step "$(omarchy_text "Not enough free space on %s" "$disk")"
|
||||
say --foreground 1 "$(omarchy_text "%s has %s of usable free space; Omarchy needs at least 32GB." "$disk" "$(to_gb $available)")"
|
||||
say "$(omarchy_text "Open the partition tool to free at least 32GB on %s, then try again." "$disk")"
|
||||
echo
|
||||
if ! gum confirm --affirmative "Back" --negative "Open partition tool" "Return to installation mode?"; then
|
||||
if ! gum confirm --affirmative "$(omarchy_text "Back")" --negative "$(omarchy_text "Open partition tool")" "$(omarchy_text "Return to installation mode?")"; then
|
||||
open_partition_tool
|
||||
fi
|
||||
return 1
|
||||
@@ -526,14 +631,14 @@ not_enough_space() {
|
||||
# encryption confirm. Sets the globals run_partition_execute needs. Returns 1
|
||||
# to fall back to the install-mode picker.
|
||||
run_partition_decide() {
|
||||
step "Checking for BitLocker on $disk"
|
||||
step "$(omarchy_text "Checking for BitLocker on %s" "$disk")"
|
||||
local bl_part
|
||||
bl_part=$(detect_bitlocker || true)
|
||||
if [[ -n "$bl_part" ]]; then
|
||||
say --foreground 1 "BitLocker signature detected on $bl_part."
|
||||
say "Turn BitLocker off in Windows and wait for the drive to finish decrypting, then try again."
|
||||
say "Suspending BitLocker is not enough — the drive stays encrypted."
|
||||
abort "Aborted: BitLocker is enabled on this disk."
|
||||
say --foreground 1 "$(omarchy_text "BitLocker signature detected on %s." "$bl_part")"
|
||||
say "$(omarchy_text "Turn BitLocker off in Windows and wait for the drive to finish decrypting, then try again.")"
|
||||
say "$(omarchy_text "Suspending BitLocker is not enough — the drive stays encrypted.")"
|
||||
abort "$(omarchy_text "Aborted: BitLocker is enabled on this disk.")"
|
||||
fi
|
||||
|
||||
# Omarchy always creates its own dedicated ESP in free space and never
|
||||
@@ -542,17 +647,17 @@ run_partition_decide() {
|
||||
# Windows ESP is far too small for our Unified Kernel Images, and a shared
|
||||
# ESP forces the install unencrypted. A separate Linux ESP keeps Windows
|
||||
# and Omarchy fully isolated and keeps LUKS on the table.
|
||||
step "Checking existing EFI partitions on $disk"
|
||||
step "$(omarchy_text "Checking existing EFI partitions on %s" "$disk")"
|
||||
local detected_win_esp
|
||||
detected_win_esp=$(detect_windows_esp || true)
|
||||
if [[ -n "$detected_win_esp" ]]; then
|
||||
say "Found a Windows ESP at $detected_win_esp — leaving it untouched."
|
||||
say "Omarchy will create its own dedicated EFI partition in free space."
|
||||
say "$(omarchy_text "Found a Windows ESP at %s — leaving it untouched." "$detected_win_esp")"
|
||||
say "$(omarchy_text "Omarchy will create its own dedicated EFI partition in free space.")"
|
||||
else
|
||||
say "A new EFI partition will be created in free space."
|
||||
say "$(omarchy_text "A new EFI partition will be created in free space.")"
|
||||
fi
|
||||
|
||||
step "Analyzing free space on $disk"
|
||||
step "$(omarchy_text "Analyzing free space on %s" "$disk")"
|
||||
partprobe "$disk" 2>/dev/null || true
|
||||
sleep 1
|
||||
|
||||
@@ -627,21 +732,21 @@ run_partition_decide() {
|
||||
while true; do
|
||||
clear_logo
|
||||
echo
|
||||
say "Install Omarchy in the $(to_gb $INSTALL_MAX_B) of free space."
|
||||
say "$(omarchy_text "Install Omarchy in the %s of free space." "$(to_gb $INSTALL_MAX_B)")"
|
||||
|
||||
case $mode in
|
||||
encrypted)
|
||||
say --foreground 8 "Press Ctrl+C for unencrypted install."
|
||||
affirmative="Yes, install"
|
||||
say --foreground 8 "$(omarchy_text "Press Ctrl+C for unencrypted install.")"
|
||||
affirmative="$(omarchy_text "Yes, install")"
|
||||
;;
|
||||
unencrypted)
|
||||
affirmative="Yes, install without encryption"
|
||||
affirmative="$(omarchy_text "Yes, install without encryption")"
|
||||
;;
|
||||
esac
|
||||
echo
|
||||
|
||||
gum confirm --affirmative "$affirmative" --negative "No, change it" \
|
||||
"Confirm installing on $disk"
|
||||
gum confirm --affirmative "$affirmative" --negative "$(omarchy_text "No, change it")" \
|
||||
"$(omarchy_text "Confirm installing on %s" "$disk")"
|
||||
confirm_status=$?
|
||||
|
||||
case $confirm_status in
|
||||
@@ -699,7 +804,7 @@ run_partition_execute() {
|
||||
say "[dry] partition numbers are assigned by parted at creation, then read back"
|
||||
say "[dry] encrypted=$encrypt_installation kernel=$kernel_choice"
|
||||
else
|
||||
step "Creating partitions on $disk"
|
||||
step "$(omarchy_text "Creating partitions on %s" "$disk")"
|
||||
if $needs_mklabel; then
|
||||
disk_step "initializing GPT on $disk" parted --script "$disk" mklabel gpt
|
||||
partprobe "$disk" 2>/dev/null || true
|
||||
@@ -737,7 +842,7 @@ run_partition_execute() {
|
||||
disk_step "clearing stale signatures on $root_partition_device" wipefs -af "$root_partition_device"
|
||||
|
||||
if [[ "$encrypt_installation" == "true" ]]; then
|
||||
step "Setting up LUKS2 on $root_partition_device"
|
||||
step "$(omarchy_text "Setting up LUKS2 on %s" "$root_partition_device")"
|
||||
# Kept as pipes rather than routed through disk_step: the passphrase must
|
||||
# not become an argv the process table can show. Folding stderr into
|
||||
# stdout still lands any error in the install log.
|
||||
@@ -754,7 +859,7 @@ run_partition_execute() {
|
||||
root_mapper="$root_partition_device"
|
||||
fi
|
||||
|
||||
step "Creating Btrfs filesystem and subvolumes"
|
||||
step "$(omarchy_text "Creating Btrfs filesystem and subvolumes")"
|
||||
disk_step "creating the Btrfs filesystem on $root_mapper" \
|
||||
mkfs.btrfs -f -L OMARCHY "$root_mapper"
|
||||
wait_for_device "$root_mapper" || disk_abort_hook "Root device $root_mapper never appeared"
|
||||
@@ -842,7 +947,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": [],
|
||||
@@ -872,7 +977,7 @@ _EOF_
|
||||
}
|
||||
|
||||
disk_form() {
|
||||
step "Let's select where to install Omarchy..."
|
||||
step "$(omarchy_text "Let's select where to install Omarchy...")"
|
||||
|
||||
# Don't offer the install media as an option (Arch ISO mounts it here)
|
||||
local boot_source
|
||||
@@ -898,19 +1003,19 @@ disk_form() {
|
||||
fi
|
||||
done <<<"$available_disks"
|
||||
|
||||
selected_display=$(echo "$disk_options" | gum choose --header "Select install disk") || abort
|
||||
selected_display=$(echo "$disk_options" | gum choose --header "$(omarchy_text "Select install disk")") || abort
|
||||
disk=$(echo "$selected_display" | awk '{print $1}')
|
||||
}
|
||||
|
||||
# STEP 4: INSTALL MODE
|
||||
|
||||
open_partition_tool() {
|
||||
step "Partition tool for $disk"
|
||||
gum style "Create unallocated free space for Omarchy, then write changes and quit."
|
||||
gum style --foreground 8 "Do not create an Omarchy partition here — leave the target area as Free space."
|
||||
gum style --foreground 8 "Tip: free-space install needs at least 32GB unallocated, plus 2GB more if no ESP already exists."
|
||||
step "$(omarchy_text "Partition tool for %s" "$disk")"
|
||||
gum style "$(omarchy_text "Create unallocated free space for Omarchy, then write changes and quit.")"
|
||||
gum style --foreground 8 "$(omarchy_text "Do not create an Omarchy partition here — leave the target area as Free space.")"
|
||||
gum style --foreground 8 "$(omarchy_text "Tip: free-space install needs at least 32GB unallocated, plus 2GB more if no ESP already exists.")"
|
||||
echo
|
||||
gum confirm --affirmative "Open cfdisk" --negative "Back" "Open partition tool for $disk?" || return 0
|
||||
gum confirm --affirmative "$(omarchy_text "Open cfdisk")" --negative "$(omarchy_text "Back")" "$(omarchy_text "Open partition tool for %s?" "$disk")" || return 0
|
||||
|
||||
clear
|
||||
cfdisk "$disk" || true
|
||||
@@ -943,17 +1048,17 @@ requires_full_disk_install() {
|
||||
}
|
||||
|
||||
install_mode_form() {
|
||||
local choices=("Full disk install")
|
||||
local choices=("$(omarchy_text "Full disk install")")
|
||||
|
||||
# The free-space/protected path registers an EFI boot entry and is UEFI-only.
|
||||
# Full-disk installs still support BIOS through the orchestrator's BIOS branch.
|
||||
if [[ -d /sys/firmware/efi ]] && ! $full_disk_only; then
|
||||
choices+=("Free space install (alongside existing data)")
|
||||
choices+=("$(omarchy_text "Free space install (alongside existing data)")")
|
||||
fi
|
||||
choices+=("Choose a different disk")
|
||||
choices+=("$(omarchy_text "Choose a different disk")")
|
||||
|
||||
step "Let's select how to install Omarchy..."
|
||||
install_mode=$(gum choose --header "Select installation mode on $disk" "${choices[@]}") || abort
|
||||
step "$(omarchy_text "Let's select how to install Omarchy...")"
|
||||
install_mode=$(gum choose --header "$(omarchy_text "Select installation mode on %s" "$disk")" "${choices[@]}") || abort
|
||||
}
|
||||
|
||||
confirm_disk_overwrite() {
|
||||
@@ -963,17 +1068,17 @@ confirm_disk_overwrite() {
|
||||
while true; do
|
||||
clear_logo
|
||||
echo
|
||||
say "Everything will be overwritten. There is no recovery possible."
|
||||
say "$(omarchy_text "Everything will be overwritten. There is no recovery possible.")"
|
||||
|
||||
if [[ $mode == "encrypted" ]]; then
|
||||
say --foreground 8 "Press Ctrl+C for unencrypted install."
|
||||
affirmative="Yes, install"
|
||||
say --foreground 8 "$(omarchy_text "Press Ctrl+C for unencrypted install.")"
|
||||
affirmative="$(omarchy_text "Yes, install")"
|
||||
else
|
||||
affirmative="Yes, install without encryption"
|
||||
affirmative="$(omarchy_text "Yes, install without encryption")"
|
||||
fi
|
||||
|
||||
echo
|
||||
gum confirm --affirmative "$affirmative" --negative "No, change it" "Confirm overwriting ${disk}"
|
||||
gum confirm --affirmative "$affirmative" --negative "$(omarchy_text "No, change it")" "$(omarchy_text "Confirm overwriting %s" "$disk")"
|
||||
confirm_status=$?
|
||||
|
||||
case $confirm_status in
|
||||
@@ -1012,13 +1117,13 @@ select_installation() {
|
||||
# With no free-space option to offer, a full-disk install is the only
|
||||
# mode, so skip the picker and go straight to the overwrite confirm.
|
||||
if $full_disk_only; then
|
||||
install_mode="Full disk install"
|
||||
install_mode=$(omarchy_text "Full disk install")
|
||||
else
|
||||
install_mode_form
|
||||
fi
|
||||
|
||||
case "$install_mode" in
|
||||
"Full disk install")
|
||||
"$(omarchy_text "Full disk install")")
|
||||
if confirm_disk_overwrite; then
|
||||
install_target="full_disk"
|
||||
return 0
|
||||
@@ -1027,13 +1132,13 @@ select_installation() {
|
||||
# wants a different disk.
|
||||
$full_disk_only && disk_form
|
||||
;;
|
||||
"Free space install"*)
|
||||
"$(omarchy_text "Free space install (alongside existing data)")")
|
||||
if run_partition_decide; then
|
||||
install_target="free_space"
|
||||
return 0
|
||||
fi
|
||||
;;
|
||||
"Choose a different disk")
|
||||
"$(omarchy_text "Choose a different disk")")
|
||||
disk_form
|
||||
;;
|
||||
esac
|
||||
@@ -1044,12 +1149,20 @@ select_installation() {
|
||||
|
||||
defer_provisioning=false
|
||||
install_target="full_disk"
|
||||
# A rerun arrives with the language chosen; otherwise English.
|
||||
language="${OMARCHY_INSTALL_LANGUAGE:-en}"
|
||||
language_chosen=false
|
||||
|
||||
# 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
|
||||
|
||||
greeter
|
||||
if [[ -n ${OMARCHY_INSTALL_LANGUAGE:-} ]]; then
|
||||
apply_language
|
||||
language_chosen=true
|
||||
else
|
||||
greeter
|
||||
fi
|
||||
|
||||
keyboard_form
|
||||
|
||||
@@ -1235,7 +1348,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": [],
|
||||
|
||||
@@ -88,6 +88,81 @@ tips=(
|
||||
"Keep the system fresh with Update in the Omarchy menu"
|
||||
)
|
||||
|
||||
# omarchy_text and its Chinese table come from the setup form the configurator uses.
|
||||
SETUP_FORM="${SETUP_FORM:-/usr/share/omarchy-iso/setup-form.sh}"
|
||||
[[ -r $SETUP_FORM ]] || SETUP_FORM="${OMARCHY_PATH:-/usr/share/omarchy}/install/provisioning/setup-form.sh"
|
||||
source "$SETUP_FORM"
|
||||
OMARCHY_ZH+=(
|
||||
["Tip: %s"]="提示:%s"
|
||||
["Installed Omarchy"]="Omarchy 安装完成"
|
||||
["Installed Omarchy in %s"]="Omarchy 安装完成,用时 %s"
|
||||
["Reboot Now"]="立即重启"
|
||||
["Last log lines:"]="日志末尾:"
|
||||
["Last target log lines:"]="目标系统日志末尾:"
|
||||
["Press Enter to continue…"]="按回车继续……"
|
||||
["No log uploader is available in this environment."]="这个环境没有日志上传工具。"
|
||||
["Install log: %s"]="安装日志:%s"
|
||||
["Target log: %s"]="目标系统日志:%s"
|
||||
["Omarchy installation stopped"]="Omarchy 安装已停止"
|
||||
["Installer exited with status %s"]="安装程序退出,状态码 %s"
|
||||
["Get help at https://omarchy.org/discord"]="求助:https://omarchy.org/discord"
|
||||
["What would you like to do?"]="接下来做什么?"
|
||||
["Upload log for support"]="上传日志求助"
|
||||
["View full log"]="查看完整日志"
|
||||
["Drop to shell"]="进入 shell"
|
||||
["Reboot"]="重启"
|
||||
["Power off"]="关机"
|
||||
["The install medium was misread"]="安装介质读取出错"
|
||||
["This package is intact on this ISO, so the download and the write were fine:"]="这个软件包在 ISO 中完好,下载和写入都没有问题:"
|
||||
["Try another USB port or another stick, and test this machine's memory"]="换一个 USB 口或换一个 U 盘,并检测这台机器的内存"
|
||||
["The install medium is damaged"]="安装介质已损坏"
|
||||
["This package no longer matches the checksum it was built with:"]="这个软件包和构建时的校验和不再一致:"
|
||||
["Re-download the ISO, verify it with sha256sum, and write the USB again"]="重新下载 ISO,用 sha256sum 校验,再重新写入 U 盘"
|
||||
["If a verified ISO fails here too, the USB stick itself is the problem"]="如果校验过的 ISO 在这里也失败,问题出在 U 盘本身"
|
||||
["The install medium is damaged or misread"]="安装介质已损坏或读取出错"
|
||||
["pacman rejected this package, read straight off this ISO:"]="pacman 拒绝了这个直接从 ISO 读出的软件包:"
|
||||
["Verify your download with sha256sum, then write the USB again"]="用 sha256sum 校验下载的文件,再重新写入 U 盘"
|
||||
["If the download verifies, the stick or this machine's memory is at fault"]="如果下载校验无误,问题出在 U 盘或这台机器的内存"
|
||||
)
|
||||
|
||||
if [[ ${OMARCHY_INSTALL_LANG:-} == "zh" ]]; then
|
||||
whimsy=(
|
||||
"备好贴心的默认设置"
|
||||
"省掉装机的折腾"
|
||||
"挑选打磨过的软件包"
|
||||
"调配协调的配色"
|
||||
"准备悦目的像素"
|
||||
"唤醒 Hyprland"
|
||||
"接好顺手的界面"
|
||||
"搭起漂亮的系统"
|
||||
"写好趁手的命令"
|
||||
"让机器焕然一新"
|
||||
"擦亮每一个像素"
|
||||
"调好终端的品味"
|
||||
"织出流畅的工作流"
|
||||
)
|
||||
tips=(
|
||||
"Super + Space 打开 Omarchy 菜单:应用、设置等"
|
||||
"Super + K 查看全部快捷键"
|
||||
"Super 是键盘上的 Windows 或 Command 键"
|
||||
"用 Xournal++ 给 PDF 签名"
|
||||
"用 LocalSend 和手机、电脑互传文件"
|
||||
"菜单 安装 > 网页应用 把任意网站变成应用"
|
||||
"Super + Return 打开终端,Super + Shift + Return 打开浏览器"
|
||||
"图片用 Pinta,视频用 Kdenlive,文档用 LibreOffice"
|
||||
"Super + Ctrl + Print 用 OCR 抓取屏幕文字"
|
||||
"Print 截屏,Alt + Print 录屏"
|
||||
"Super + Ctrl + R 设置提醒"
|
||||
"菜单 风格 > 主题 切换主题"
|
||||
"双击菜单栏让它透明"
|
||||
"菜单 安装 > Windows 运行完整的 Windows 虚拟机"
|
||||
"Super + Ctrl + V 打开剪贴板管理器"
|
||||
"Super + 1 到 0 切换工作区,加 Shift 带上窗口"
|
||||
"Super + Print 拾取屏幕上任意位置的颜色"
|
||||
"用菜单里的 更新 让系统保持最新"
|
||||
)
|
||||
fi
|
||||
|
||||
cleanup() {
|
||||
printf '%s%s' "$RESET" "$SHOW_CURSOR" >"$TTY_PATH" 2>/dev/null || true
|
||||
}
|
||||
@@ -286,8 +361,8 @@ left_padding() {
|
||||
|
||||
visible_len() {
|
||||
local text="$1"
|
||||
text="$(printf '%b' "$text" | sed -E $'s/\x1b\\[[0-9;?]*[A-Za-z]//g')"
|
||||
printf '%s' "${#text}"
|
||||
# wc -L counts display columns, so double-width CJK centers too.
|
||||
printf '%b' "$text" | sed -E $'s/\x1b\\[[0-9;?]*[A-Za-z]//g' | wc -L
|
||||
}
|
||||
|
||||
blank_line() { printf '\r%s\n' "$CLEAR_LINE"; }
|
||||
@@ -678,7 +753,7 @@ render_dynamic() {
|
||||
render_icon "$DISPLAY_PM"
|
||||
|
||||
message="$(truncate_for_width "$(current_whimsy)" "$PROGRESS_TEXT_WIDTH")"
|
||||
tip="$(truncate_for_width "Tip: $(current_tip)" "$PROGRESS_TEXT_WIDTH")"
|
||||
tip="$(truncate_for_width "$(omarchy_text "Tip: %s" "$(current_tip)")" "$PROGRESS_TEXT_WIDTH")"
|
||||
printf '%s%d;1H' "$CSI" "$((TOP_ROW + ICON_HEIGHT + 1))"
|
||||
center "${GREEN}$((DISPLAY_PM / 10))%${RESET}" "$PROGRESS_TEXT_WIDTH"
|
||||
center "${GREEN}${message}${RESET}" "$PROGRESS_TEXT_WIDTH"
|
||||
@@ -718,9 +793,13 @@ install_duration() {
|
||||
}
|
||||
|
||||
render_finish() {
|
||||
local duration effect_canvas_width title="Installed Omarchy"
|
||||
local duration effect_canvas_width title
|
||||
duration="$(install_duration || true)"
|
||||
[[ -n $duration ]] && title+=" in ${duration}"
|
||||
if [[ -n $duration ]]; then
|
||||
title=$(omarchy_text "Installed Omarchy in %s" "$duration")
|
||||
else
|
||||
title=$(omarchy_text "Installed Omarchy")
|
||||
fi
|
||||
# ttfx centers its text two columns right of plain centering. A canvas two
|
||||
# columns narrower aligns the animation with the title and fallback logo.
|
||||
effect_canvas_width="$(term_cols)"
|
||||
@@ -765,7 +844,7 @@ render_finish() {
|
||||
}
|
||||
|
||||
reboot_prompt() {
|
||||
local prompt_pad
|
||||
local prompt_pad label
|
||||
|
||||
# Nobody to confirm; the OMARCHY_UI_AUTO_REBOOT check at the call site still
|
||||
# applies, so setting both stops on the finish screen without a keyboard.
|
||||
@@ -776,24 +855,31 @@ reboot_prompt() {
|
||||
# gum allows. FINISH_HEIGHT budgets for the same three rows.
|
||||
printf '%s%d;1H%s' "$CSI" "$((FINISH_TOP_ROW + LOGO_HEIGHT + 2))" "$CLEAR_LINE" >"$TTY_PATH"
|
||||
|
||||
prompt_pad=$(( ( $(term_cols) - 18 ) / 2 ))
|
||||
# gum pads the button label by four columns on each side.
|
||||
label=$(omarchy_text "Reboot Now")
|
||||
prompt_pad=$(( ( $(term_cols) - $(visible_len "$label") - 8 ) / 2 ))
|
||||
(( prompt_pad < 0 )) && prompt_pad=0
|
||||
gum confirm \
|
||||
--padding "0 0 0 $prompt_pad" \
|
||||
--show-help=false \
|
||||
--default \
|
||||
--affirmative "Reboot Now" \
|
||||
--affirmative "$label" \
|
||||
--negative "" \
|
||||
"" <"$TTY_PATH" >"$TTY_PATH" 2>&1
|
||||
}
|
||||
|
||||
# Columns, not characters: each CJK character takes two.
|
||||
truncate_for_width() {
|
||||
local text="$1" width="$2"
|
||||
if (( ${#text} > width )); then
|
||||
printf '%s…' "${text:0:$((width - 1))}"
|
||||
else
|
||||
if (( $(printf '%s' "$text" | wc -L) <= width )); then
|
||||
printf '%s' "$text"
|
||||
return
|
||||
fi
|
||||
text=${text:0:$((width - 1))}
|
||||
while (( $(printf '%s' "$text" | wc -L) > width - 1 )); do
|
||||
text=${text%?}
|
||||
done
|
||||
printf '%s…' "$text"
|
||||
}
|
||||
|
||||
render_failure_log_tail() {
|
||||
@@ -819,8 +905,8 @@ render_failure_log_tail() {
|
||||
fi
|
||||
[[ -f $tail_log ]] || return 0
|
||||
|
||||
label="Last log lines:"
|
||||
[[ $tail_log == /mnt/* ]] && label="Last target log lines:"
|
||||
label=$(omarchy_text "Last log lines:")
|
||||
[[ $tail_log == /mnt/* ]] && label=$(omarchy_text "Last target log lines:")
|
||||
line_at "$CONTENT_WIDTH" 2 "${DIM}${label}${RESET}"
|
||||
printf '\n'
|
||||
tail -n "$lines" "$tail_log" 2>/dev/null | while IFS= read -r line; do
|
||||
@@ -843,7 +929,7 @@ find_log_uploader() {
|
||||
}
|
||||
|
||||
prompt_enter() {
|
||||
printf '\nPress Enter to continue…' >"$TTY_PATH"
|
||||
printf '\n%s' "$(omarchy_text "Press Enter to continue…")" >"$TTY_PATH"
|
||||
IFS= read -r _ <"$TTY_PATH" || true
|
||||
}
|
||||
|
||||
@@ -854,9 +940,9 @@ upload_failure_log() {
|
||||
"$uploader" install >"$TTY_PATH" 2>&1 || true
|
||||
else
|
||||
{
|
||||
echo "No log uploader is available in this environment."
|
||||
echo "Install log: $LOG_FILE"
|
||||
[[ -f /mnt/var/log/omarchy-install.log ]] && echo "Target log: /mnt/var/log/omarchy-install.log"
|
||||
printf '%s\n' "$(omarchy_text "No log uploader is available in this environment.")"
|
||||
printf '%s\n' "$(omarchy_text "Install log: %s" "$LOG_FILE")"
|
||||
[[ -f /mnt/var/log/omarchy-install.log ]] && printf '%s\n' "$(omarchy_text "Target log: %s" /mnt/var/log/omarchy-install.log)"
|
||||
} >"$TTY_PATH"
|
||||
fi
|
||||
prompt_enter
|
||||
@@ -907,6 +993,8 @@ render_media_diagnosis() {
|
||||
blank_line
|
||||
continue
|
||||
fi
|
||||
# The support log keeps English; the screen shows the translation, and package names pass through.
|
||||
[[ ${OMARCHY_INSTALL_LANG:-} == "zh" ]] && line=${OMARCHY_ZH[$line]:-$line}
|
||||
if (( first )); then
|
||||
center "${RED}$(truncate_for_width "$line" "$CONTENT_WIDTH")${RESET}" "$CONTENT_WIDTH"
|
||||
first=0
|
||||
@@ -922,8 +1010,8 @@ render_failure() {
|
||||
blank_line
|
||||
render_logo
|
||||
blank_line
|
||||
center "${RED}Omarchy installation stopped${RESET}" "$CONTENT_WIDTH"
|
||||
center "Installer exited with status $status" "$CONTENT_WIDTH"
|
||||
center "${RED}$(omarchy_text "Omarchy installation stopped")${RESET}" "$CONTENT_WIDTH"
|
||||
center "$(omarchy_text "Installer exited with status %s" "$status")" "$CONTENT_WIDTH"
|
||||
|
||||
render_media_diagnosis "$media_diagnosis"
|
||||
|
||||
@@ -938,12 +1026,12 @@ render_failure() {
|
||||
blank_line
|
||||
render_failure_log_tail "$(media_diagnosis_rows "$media_diagnosis")"
|
||||
blank_line
|
||||
center "${DIM}Get help at https://omarchy.org/discord${RESET}" "$CONTENT_WIDTH"
|
||||
center "${DIM}$(omarchy_text "Get help at https://omarchy.org/discord")${RESET}" "$CONTENT_WIDTH"
|
||||
blank_line
|
||||
}
|
||||
|
||||
failure_menu() {
|
||||
local choice uploader
|
||||
local choice uploader actions shown i
|
||||
|
||||
[[ ${OMARCHY_UI_FAILURE_ACTION:-} == "exit" ]] && return 0
|
||||
# The failure screen and log tail have already rendered; exit with the
|
||||
@@ -953,26 +1041,20 @@ failure_menu() {
|
||||
while true; do
|
||||
uploader=""
|
||||
uploader=$(find_log_uploader || true)
|
||||
if [[ -n $uploader ]]; then
|
||||
choice=$(gum choose \
|
||||
--height 6 \
|
||||
--header "What would you like to do?" \
|
||||
"Upload log for support" \
|
||||
"View full log" \
|
||||
"Drop to shell" \
|
||||
"Reboot" \
|
||||
"Power off" \
|
||||
<"$TTY_PATH" 2>"$TTY_PATH") || choice="Drop to shell"
|
||||
else
|
||||
choice=$(gum choose \
|
||||
--height 5 \
|
||||
--header "What would you like to do?" \
|
||||
"View full log" \
|
||||
"Drop to shell" \
|
||||
"Reboot" \
|
||||
"Power off" \
|
||||
<"$TTY_PATH" 2>"$TTY_PATH") || choice="Drop to shell"
|
||||
fi
|
||||
actions=("View full log" "Drop to shell" "Reboot" "Power off")
|
||||
[[ -n $uploader ]] && actions=("Upload log for support" "${actions[@]}")
|
||||
shown=()
|
||||
for i in "${!actions[@]}"; do
|
||||
shown+=("$(omarchy_text "${actions[i]}")")
|
||||
done
|
||||
choice=$(gum choose \
|
||||
--height "$((${#actions[@]} + 1))" \
|
||||
--header "$(omarchy_text "What would you like to do?")" \
|
||||
"${shown[@]}" \
|
||||
<"$TTY_PATH" 2>"$TTY_PATH") || choice=""
|
||||
for i in "${!shown[@]}"; do
|
||||
[[ ${shown[i]} == "$choice" ]] && choice=${actions[i]}
|
||||
done
|
||||
|
||||
case "$choice" in
|
||||
"Upload log for support")
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# The Chinese installer's console: the VT's Tokyo Night palette, with Noto Sans Mono CJK from the offline mirror.
|
||||
[main]
|
||||
font=Noto Sans Mono CJK SC:size=13
|
||||
# Noto's tall default rows leave the summary too few lines for the logo.
|
||||
line-height=22px
|
||||
|
||||
[colors-dark]
|
||||
background=1a1b26
|
||||
foreground=a9b1d6
|
||||
regular0=1a1b26
|
||||
regular1=f7768e
|
||||
regular2=9ece6a
|
||||
regular3=e0af68
|
||||
regular4=7aa2f7
|
||||
regular5=bb9af7
|
||||
regular6=7dcfff
|
||||
regular7=a9b1d6
|
||||
bright0=414868
|
||||
bright1=f7768e
|
||||
bright2=9ece6a
|
||||
bright3=e0af68
|
||||
bright4=7aa2f7
|
||||
bright5=bb9af7
|
||||
bright6=7dcfff
|
||||
bright7=c0caf5
|
||||
|
||||
# cage draws no title bar, and a reserved one leaves a black strip.
|
||||
[csd]
|
||||
preferred=none
|
||||
@@ -273,6 +273,12 @@ mkdir -p "$omarchy_share"
|
||||
printf 'logo bottom row%*s\n' 66 ''
|
||||
} >"$omarchy_share/logo.txt"
|
||||
|
||||
# The ISO vendors the runtime's setup form; the dashboard only needs its text lookup.
|
||||
cat >"$work/setup-form.sh" <<'FORM'
|
||||
declare -gA OMARCHY_ZH=()
|
||||
omarchy_text() { local text=$1; shift; printf -- "$text" "$@"; }
|
||||
FORM
|
||||
|
||||
run_dashboard() {
|
||||
local install_log="$1"
|
||||
|
||||
@@ -284,7 +290,7 @@ run_dashboard() {
|
||||
"error": "Pacstrap failed. See /var/log/archinstall.log"}]}
|
||||
STATE
|
||||
: >"$screen"
|
||||
script -qefc "stty rows 40 cols 120; PATH='$stubs:$PATH' OMARCHY_PATH='$omarchy_share' OMARCHY_UI_INTERACTIVE=no OMARCHY_UI_FAILURE_ACTION=exit OMARCHY_FAILURE_TAIL_LOG='$install_log' '$DASHBOARD' '$install_log' '$state_file' -- bash -c 'exit 1'" \
|
||||
script -qefc "stty rows 40 cols 120; PATH='$stubs:$PATH' OMARCHY_PATH='$omarchy_share' SETUP_FORM='$work/setup-form.sh' OMARCHY_UI_INTERACTIVE=no OMARCHY_UI_FAILURE_ACTION=exit OMARCHY_FAILURE_TAIL_LOG='$install_log' '$DASHBOARD' '$install_log' '$state_file' -- bash -c 'exit 1'" \
|
||||
"$screen" >/dev/null 2>&1
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Every installer text needs an OMARCHY_ZH entry, or a Chinese install shows it in English.
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/../.." && pwd)
|
||||
SETUP_FORM="${OMARCHY_SOURCE:-$ROOT/../omarchy}/install/provisioning/setup-form.sh"
|
||||
|
||||
fail() {
|
||||
printf 'not ok - %s\n' "$1"
|
||||
[[ -z ${2:-} ]] || printf '%s\n' "$2" | sed 's/^/# /'
|
||||
exit 1
|
||||
}
|
||||
|
||||
if [[ ! -r $SETUP_FORM ]]; then
|
||||
printf 'ok - # skip the setup form is not checked out next to this repo (set OMARCHY_SOURCE)\n'
|
||||
exit 0
|
||||
fi
|
||||
|
||||
source "$SETUP_FORM"
|
||||
for file in configs/airootfs/root/configurator configs/airootfs/usr/local/bin/omarchy-install-dashboard; do
|
||||
eval "$(sed -n '/^OMARCHY_ZH+=(/,/^)/p' "$ROOT/$file")"
|
||||
done
|
||||
|
||||
mapfile -t texts < <(
|
||||
grep -ho 'omarchy_text "[^"$]*"' "$ROOT/configs/airootfs/root/configurator" "$ROOT/configs/airootfs/usr/local/bin/omarchy-install-dashboard" |
|
||||
sed 's/^omarchy_text "//; s/"$//' | sort -u
|
||||
)
|
||||
((${#texts[@]} > 50)) || fail "the installer routes its text through omarchy_text" "found ${#texts[@]}"
|
||||
for text in "${texts[@]}"; do
|
||||
[[ -n ${OMARCHY_ZH[$text]:-} ]] || fail "every installer text has a Chinese entry" "missing: $text"
|
||||
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"; 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'
|
||||
|
||||
mapfile -t diagnosis < <(grep -x ' *echo "[^"$]*"' "$ROOT/configs/airootfs/usr/local/bin/omarchy-install-diagnose-media" | sed 's/^ *echo "//; s/"$//')
|
||||
((${#diagnosis[@]} >= 10)) || fail "the media diagnosis sentences are found" "found ${#diagnosis[@]}"
|
||||
for line in "${diagnosis[@]}"; do
|
||||
[[ -n ${OMARCHY_ZH[$line]:-} ]] || fail "every media diagnosis sentence has a Chinese entry" "missing: $line"
|
||||
done
|
||||
printf 'ok - every media diagnosis sentence has a Chinese entry\n'
|
||||
|
||||
[[ $(OMARCHY_INSTALL_LANG=zh omarchy_text "Confirm overwriting %s" /dev/vda) == "确认覆盖 /dev/vda" ]] ||
|
||||
fail "Chinese text keeps its printf arguments"
|
||||
[[ $(omarchy_text "Confirm overwriting %s" /dev/vda) == "Confirm overwriting /dev/vda" ]] ||
|
||||
fail "English stays the default"
|
||||
printf 'ok - omarchy_text formats Chinese and English alike\n'
|
||||
Reference in new issue
Block a user