diff --git a/CHANGELOG.md b/CHANGELOG.md index 98373c5082..69e1f55c8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), - Package Manager: Added --no-confirm flag to 'hyde-shell pm.py' commands. - Lua: Added 'hyde-shell luainit' to initialize the Lua runtime. It is slow and should be optional for now. - Python: 'hyde-shell pyinit' will now sync like pip to preserve user packages. +- i18n: Added a gettext-based zh_CN runtime localization POC for notifications and keybinding hints. ## v26.4.3 | 3rd week of April 2026 Release! diff --git a/Configs/.local/lib/hyde/keybinds_hint.sh b/Configs/.local/lib/hyde/keybinds_hint.sh index bfd78342bc..eb4263c9c4 100755 --- a/Configs/.local/lib/hyde/keybinds_hint.sh +++ b/Configs/.local/lib/hyde/keybinds_hint.sh @@ -1,13 +1,23 @@ #!/usr/bin/env bash pkill -x rofi && exit [[ $HYDE_SHELL_INIT -ne 1 ]] && eval "$(hyde-shell init)" +# shellcheck source=/dev/null +source "${LIB_DIR}/hyde/shutils/l10n.sh" confDir="${XDG_CONFIG_HOME:-$HOME/.config}" keyconfDir="$confDir/hypr" kb_hint_conf=("$keyconfDir/hyprland.conf" "$keyconfDir/keybindings.conf" "$keyconfDir/userprefs.conf") kb_hint_conf+=("${ROFI_KEYBIND_HINT_CONFIG[@]}") kb_cache="$XDG_RUNTIME_DIR/hyde/keybinds_hint.rofi" + +update_keybind_cache() { + "${LIB_DIR}/hyde/keybinds/hint-hyprland.py" --format rofi > "$kb_cache" && { + hyde_gettext "Keybind cache updated" + printf '\n' + } +} + [ -f "$kb_cache" ] && { - trap '${LIB_DIR}/hyde/keybinds/hint-hyprland.py --format rofi > "$kb_cache" && echo "Keybind cache updated" ' EXIT + trap update_keybind_cache EXIT } output="$(if ! cat "$kb_cache" 2> /dev/null @@ -16,12 +26,13 @@ then fi)" wait if [ -z "$output" ]; then - notify-send "Keybind Hint" "Initialization failed." + notify-send "$(hyde_gettext "Keybind Hint")" "$(hyde_gettext "Initialization failed.")" exit 0 fi if ! command -v rofi &> /dev/null; then echo "$output" - echo "rofi not detected. Displaying on terminal instead" + hyde_gettext "rofi not detected. Displaying on terminal instead" + printf '\n' exit 0 fi hypr_border=${hypr_border:-$(hyprctl -j getoption decoration:rounding | jq '.int')} @@ -43,9 +54,12 @@ font_name=${font_name:-$(get_hyprConf "FONT")} font_override="* {font: \"${font_name:-"JetBrainsMono Nerd Font"} $font_scale\";}" icon_override=$(gsettings get org.gnome.desktop.interface icon-theme | sed "s/'//g") icon_override="configuration {icon-theme: \"$icon_override\";}" +keybindings_label="$(hyde_gettext "Keybindings")" +keybinds_label="$(hyde_gettext "Keybinds")" +description_label="$(hyde_gettext "Description")" selected=$(echo -e "$output" | rofi -dmenu -p \ - -theme-str "entry { placeholder: \"\t⌨️ Keybindings \";}" \ - " Keybinds \t\tﴕ Description" \ + -theme-str "entry { placeholder: \"\t⌨️ ${keybindings_label} \";}" \ + " ${keybinds_label} \t\tﴕ ${description_label}" \ -p -i \ -display-columns 1 \ -display-column-separator ":::" \ @@ -63,8 +77,9 @@ RUN() { if [ -n "$dispatch" ] && [ "$(echo "$dispatch" | wc -l)" -eq 1 ]; then if [ "$repeat" = repeat ]; then while true; do - repeat_command=$(echo -e "Repeat" | rofi -dmenu -no-custom -p - "[Enter] repeat; [ESC] exit" -theme "notification") - if [ "$repeat_command" = "Repeat" ]; then + repeat_label="$(hyde_gettext "Repeat")" + repeat_command=$(echo -e "$repeat_label" | rofi -dmenu -no-custom -p - "$(hyde_gettext "[Enter] repeat; [ESC] exit")" -theme "notification") + if [ "$repeat_command" = "$repeat_label" ]; then RUN else exit 0 diff --git a/Configs/.local/lib/hyde/notifications.py b/Configs/.local/lib/hyde/notifications.py index 0ff9cab75c..586fa834a6 100755 --- a/Configs/.local/lib/hyde/notifications.py +++ b/Configs/.local/lib/hyde/notifications.py @@ -4,6 +4,8 @@ import json import sys +from pyutils.i18n import t + def get_dunst_history(): result = subprocess.run(["dunstctl", "history"], stdout=subprocess.PIPE, check=True) @@ -15,11 +17,11 @@ def format_history(history): count = len(history["data"][0]) alt = "none" tooltip_click = [] - tooltip_click.append("󰎟 Notifications") - tooltip_click.append("󰳽 scroll-down:  history pop") - tooltip_click.append("󰳽 click-left:  Enable & Disable DND") - tooltip_click.append("󰳽 click-middle: 󰛌 clear history") - tooltip_click.append("󰳽 click-right: 󱄊 close all") + tooltip_click.append("󰎟 " + t("Notifications")) + tooltip_click.append("󰳽 " + t("scroll-down: history pop", "scroll-down:  history pop")) + tooltip_click.append("󰳽 " + t("click-left: Enable & Disable DND", "click-left:  Enable & Disable DND")) + tooltip_click.append("󰳽 " + t("click-middle: clear history", "click-middle: 󰛌 clear history")) + tooltip_click.append("󰳽 " + t("click-right: close all", "click-right: 󱄊 close all")) tooltip = [] @@ -51,7 +53,7 @@ def format_history(history): def main(): history = get_dunst_history() formatted_history = format_history(history) - sys.stdout.write(json.dumps(formatted_history) + "\n") + sys.stdout.write(json.dumps(formatted_history, ensure_ascii=False) + "\n") sys.stdout.flush() diff --git a/Configs/.local/lib/hyde/pyutils/i18n.py b/Configs/.local/lib/hyde/pyutils/i18n.py new file mode 100644 index 0000000000..92848aa6da --- /dev/null +++ b/Configs/.local/lib/hyde/pyutils/i18n.py @@ -0,0 +1,63 @@ +import gettext +import os +from functools import lru_cache +from pathlib import Path + +DOMAIN = "hyde" + + +def _normalize_locale(lang: str | None) -> str: + lang = (lang or "en").split(":", 1)[0].split(".", 1)[0].split("@", 1)[0] + lang = lang.replace("-", "_") + lowered = lang.lower() + + if lowered in {"", "c", "posix"}: + return "en" + if lowered in {"zh", "zh_cn", "zh_sg"}: + return "zh_CN" + return lang + + +def _language() -> str: + return _normalize_locale( + os.getenv("HYDE_LANG") + or os.getenv("I18N_LANGUAGE") + or os.getenv("LC_MESSAGES") + or os.getenv("LANG") + or "en" + ) + + +def _locale_dir() -> Path: + share_dir = os.getenv("SHARE_DIR") + if share_dir: + return Path(share_dir) / "hyde" / "locale" + + return Path(os.getenv("XDG_DATA_HOME", Path.home() / ".local/share")) / "hyde" / "locale" + + +@lru_cache(maxsize=None) +def _translation(lang: str) -> gettext.NullTranslations: + try: + return gettext.translation( + DOMAIN, + localedir=str(_locale_dir()), + languages=[lang], + fallback=True, + ) + except Exception: + return gettext.NullTranslations() + + +def t(message: str, default: str | None = None, *args: object) -> str: + translated = _translation(_language()).gettext(message) + if translated == message and default is not None: + translated = default + + if not args: + return translated + + try: + return translated % args + except (TypeError, ValueError): + return translated diff --git a/Configs/.local/lib/hyde/shutils/l10n.sh b/Configs/.local/lib/hyde/shutils/l10n.sh index afa8abfe09..3545d5a760 100644 --- a/Configs/.local/lib/hyde/shutils/l10n.sh +++ b/Configs/.local/lib/hyde/shutils/l10n.sh @@ -1,17 +1,57 @@ #!/usr/bin/env bash -# Source this file in any script that needs localization support. It sets up the _T associative array with translations based on the user's locale. +# Source this file in scripts that need lightweight gettext-style localization. -# Extract the system locale and set DESKTOP_LANG to the first two characters (language code) -_raw_sys_lang="${LC_ALL:-${LANG:-en}}" -export DESKTOP_LANG="${DESKTOP_LANG:-${_raw_sys_lang:0:2}}" -export DESKTOP_LANG="${DESKTOP_LANG,,}" -#? Handles edge cases where locale is set to "C" or "POSIX" which are not actual languages -[[ "$DESKTOP_LANG" == "c" || "$DESKTOP_LANG" == "po" ]] && export DESKTOP_LANG="en" +_hyde_l10n_normalize_locale() { + local lang="${1:-${HYDE_LANG:-${I18N_LANGUAGE:-${LC_MESSAGES:-${LANG:-en}}}}}" + lang="${lang%%:*}" + lang="${lang%%.*}" + lang="${lang%%@*}" + lang="${lang//-/_}" -# Initialize the _T associative array for translations -declare -A _T 2>/dev/null || : # Localization support -[[ -f "${XDG_DATA_HOME:-$HOME/.local/share}/hyde/locale/${DESKTOP_LANG}.sh" ]] && source "${XDG_DATA_HOME:-$HOME/.local/share}/hyde/locale/${DESKTOP_LANG}.sh" -[[ -f "${XDG_CONFIG_HOME:-$HOME/.config}/hyde/locale/${DESKTOP_LANG}.sh" ]] && source "${XDG_CONFIG_HOME:-$HOME/.config}/hyde/locale/${DESKTOP_LANG}.sh" + case "${lang,,}" in + "" | c | posix) + printf '%s\n' "en" + ;; + zh | zh_cn | zh_sg) + printf '%s\n' "zh_CN" + ;; + *) + printf '%s\n' "$lang" + ;; + esac +} + +_hyde_l10n_locale_dir() { + if [[ -n "${SHARE_DIR:-}" ]]; then + printf '%s\n' "${SHARE_DIR%/}/hyde/locale" + return + fi + + printf '%s\n' "${XDG_DATA_HOME:-$HOME/.local/share}/hyde/locale" +} + +_hyde_l10n_source_map() { + local map_file="$1" + [[ -r "$map_file" ]] || return 0 + # shellcheck source=/dev/null + source "$map_file" +} + +DESKTOP_LANG="$(_hyde_l10n_normalize_locale)" +export DESKTOP_LANG + +declare -gA _T 2>/dev/null || declare -A _T 2>/dev/null || : +_hyde_l10n_source_map "$(_hyde_l10n_locale_dir)/${DESKTOP_LANG}.sh" +_hyde_l10n_source_map "${XDG_CONFIG_HOME:-$HOME/.config}/hyde/locale/${DESKTOP_LANG}.sh" + +hyde_gettext() { + local msg="${1:-}" + if [[ -n "$msg" && -n "${_T[$msg]+_}" ]]; then + printf '%s' "${_T[$msg]}" + return + fi + printf '%s' "$msg" +} # method overrides for localization @@ -21,7 +61,7 @@ send_notifs() { for arg in "$@"; do # If it's not a flag (starts with -), try to translate it if [[ ! "$arg" =~ ^- ]]; then - args+=("${_T[$arg]:-$arg}") + args+=("$(hyde_gettext "$arg")") else args+=("$arg") fi @@ -35,7 +75,8 @@ print_log_L() { case "$1" in -r | +r | -g | +g | -y | +y | -b | +b | -m | +m | -c | +c | -wt | +w | -n | +n | -stat | -crit | -warn | -sec | -err) # $2 is the message. Translate it or use original. - local msg="${_T[$2]:-$2}" + local msg + msg="$(hyde_gettext "$2")" case "$1" in -r | +r) echo -ne "\e[31m$msg\e[0m" >&2 ;; -g | +g) echo -ne "\e[32m$msg\e[0m" >&2 ;; @@ -55,13 +96,14 @@ print_log_L() { ;; +) # Custom color: $3 is the message - local msg="${_T[$3]:-$3}" + local msg + msg="$(hyde_gettext "$3")" echo -ne "\e[38;5;$2m$msg\e[0m" >&2 shift 3 ;; *) # Standard text - echo -ne "${_T[$1]:-$1}" >&2 + echo -ne "$(hyde_gettext "$1")" >&2 shift ;; esac @@ -69,4 +111,4 @@ print_log_L() { echo "" >&2 } -export -f send_notifs print_log_L +export -f hyde_gettext send_notifs print_log_L diff --git a/Configs/.local/share/hyde/locale/zh_CN.sh b/Configs/.local/share/hyde/locale/zh_CN.sh new file mode 100644 index 0000000000..eed240ead8 --- /dev/null +++ b/Configs/.local/share/hyde/locale/zh_CN.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Generated by Source/locale/build.py; do not edit manually. +# shellcheck shell=bash disable=SC2034 +declare -gA _T 2>/dev/null || declare -A _T 2>/dev/null || : +_T[$'Description']=$'说明' +_T[$'Initialization failed.']=$'初始化失败。' +_T[$'Keybind Hint']=$'快捷键提示' +_T[$'Keybind cache updated']=$'快捷键缓存已更新' +_T[$'Keybindings']=$'快捷键' +_T[$'Keybinds']=$'快捷键' +_T[$'Notifications']=$'通知' +_T[$'Repeat']=$'重复执行' +_T[$'[Enter] repeat; [ESC] exit']=$'[Enter] 重复;[ESC] 退出' +_T[$'click-left: Enable & Disable DND']=$'左键:启用/关闭免打扰' +_T[$'click-middle: clear history']=$'中键:清空历史记录' +_T[$'click-right: close all']=$'右键:关闭全部通知' +_T[$'rofi not detected. Displaying on terminal instead']=$'未检测到 rofi,改为在终端中显示' +_T[$'scroll-down: history pop']=$'向下滚动:弹出历史通知' diff --git a/Configs/.local/share/hyde/locale/zh_CN/LC_MESSAGES/hyde.mo b/Configs/.local/share/hyde/locale/zh_CN/LC_MESSAGES/hyde.mo new file mode 100644 index 0000000000..e22a964009 Binary files /dev/null and b/Configs/.local/share/hyde/locale/zh_CN/LC_MESSAGES/hyde.mo differ diff --git a/Source/locale/README.md b/Source/locale/README.md new file mode 100644 index 0000000000..4d39a862df --- /dev/null +++ b/Source/locale/README.md @@ -0,0 +1,43 @@ +# HyDE Runtime Localization + +HyDE uses gettext `.po` files as the editable source for runtime translations. +Generated `.mo` files are used by Python and other gettext consumers, while Bash +loads a small generated associative-array map from the same `.po` file. + +## Language selection + +Force Simplified Chinese: + +```sh +HYDE_LANG=zh_CN hyde-shell keybinds_hint +``` + +Force English: + +```sh +HYDE_LANG=en hyde-shell keybinds_hint +``` + +Language resolution checks `HYDE_LANG`, `I18N_LANGUAGE`, `LC_MESSAGES`, and +`LANG`, then falls back to English/original strings. + +## Regenerating files + +After editing `Source/locale/zh_CN/LC_MESSAGES/hyde.po`, regenerate runtime +translation files: + +```sh +python3 Source/locale/build.py +``` + +The script uses standard gettext tools when available: + +- `xgettext` updates `Source/locale/hyde.pot` +- `msgmerge` updates `.po` files from the template +- `msgfmt` compiles `.po` files into `.mo` + +It also generates Bash maps such as +`Configs/.local/share/hyde/locale/zh_CN.sh`. + +Missing translation files or missing keys safely fall back to the original +English strings. diff --git a/Source/locale/build.py b/Source/locale/build.py new file mode 100644 index 0000000000..05c8de96db --- /dev/null +++ b/Source/locale/build.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python3 +from __future__ import annotations + +import ast +import shutil +import subprocess +import sys +from pathlib import Path + +DOMAIN = "hyde" +ROOT = Path(__file__).resolve().parents[2] +SOURCE_DIR = Path(__file__).resolve().parent +POT_FILE = SOURCE_DIR / f"{DOMAIN}.pot" +PO_FILES = [SOURCE_DIR / "zh_CN" / "LC_MESSAGES" / f"{DOMAIN}.po"] +PYTHON_SOURCES = [ROOT / "Configs/.local/lib/hyde/notifications.py"] +SHELL_SOURCES = [ROOT / "Configs/.local/lib/hyde/keybinds_hint.sh"] +RUNTIME_LOCALE_DIR = ROOT / "Configs/.local/share/hyde/locale" + + +def run_if_available(tool: str, args: list[str]) -> bool: + executable = shutil.which(tool) + if executable is None: + print(f"skip: {tool} not found", file=sys.stderr) + return False + + subprocess.run([executable, *args], check=True) + return True + + +def normalize_gettext_header(path: Path) -> None: + if not path.exists(): + return + + lines = [] + for line in path.read_text(encoding="utf-8").splitlines(): + if line == "# This file is distributed under the same license as the PACKAGE package.": + lines.append("# This file is distributed under the same license as the HyDE package.") + elif line.startswith('"Project-Id-Version: '): + lines.append('"Project-Id-Version: HyDE\\n"') + elif line.startswith('"Report-Msgid-Bugs-To: '): + lines.append('"Report-Msgid-Bugs-To: https://github.com/HyDE-Project/HyDE/issues\\n"') + elif line.startswith('"POT-Creation-Date: '): + lines.append('"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\\n"') + elif line == '"Content-Type: text/plain; charset=CHARSET\\n"': + lines.append('"Content-Type: text/plain; charset=UTF-8\\n"') + else: + lines.append(line) + + path.write_text("\n".join(lines) + "\n", encoding="utf-8") + + +def update_pot() -> None: + if shutil.which("xgettext") is None: + print("skip: xgettext not found", file=sys.stderr) + return + + tmp_pot = POT_FILE.with_suffix(".pot.tmp") + if tmp_pot.exists(): + tmp_pot.unlink() + + subprocess.run( + [ + "xgettext", + "--from-code=UTF-8", + "--language=Python", + "--package-name=HyDE", + "--msgid-bugs-address=https://github.com/HyDE-Project/HyDE/issues", + "--keyword=t:1", + "--output", + str(tmp_pot), + *[str(path.relative_to(ROOT)) for path in PYTHON_SOURCES], + ], + check=True, + cwd=ROOT, + ) + normalize_gettext_header(tmp_pot) + + shell_args = [ + "xgettext", + "--from-code=UTF-8", + "--language=Shell", + "--keyword=hyde_gettext:1", + "--output", + str(tmp_pot), + *[str(path.relative_to(ROOT)) for path in SHELL_SOURCES], + ] + if tmp_pot.exists(): + shell_args.insert(4, "--join-existing") + subprocess.run(shell_args, check=True, cwd=ROOT) + + tmp_pot.replace(POT_FILE) + normalize_gettext_header(POT_FILE) + + +def merge_po_files() -> None: + if not POT_FILE.exists(): + return + + for po_file in PO_FILES: + if not po_file.exists(): + continue + if run_if_available( + "msgmerge", + ["--update", "--backup=none", str(po_file), str(POT_FILE)], + ): + normalize_gettext_header(po_file) + + +def compile_mo_files() -> None: + for po_file in PO_FILES: + if not po_file.exists(): + continue + + locale = po_file.parents[1].name + mo_file = RUNTIME_LOCALE_DIR / locale / "LC_MESSAGES" / f"{DOMAIN}.mo" + mo_file.parent.mkdir(parents=True, exist_ok=True) + run_if_available("msgfmt", ["--check", "--output-file", str(mo_file), str(po_file)]) + + +def decode_po_string(value: str) -> str: + return ast.literal_eval(value) + + +def parse_po(po_file: Path) -> dict[str, str]: + entries: dict[str, str] = {} + msgid: str | None = None + msgstr: str | None = None + section: str | None = None + fuzzy = False + + def flush() -> None: + nonlocal msgid, msgstr, section, fuzzy + if msgid and msgstr and not fuzzy: + entries[msgid] = msgstr + msgid = None + msgstr = None + section = None + fuzzy = False + + for raw_line in po_file.read_text(encoding="utf-8").splitlines(): + line = raw_line.strip() + if not line: + flush() + continue + if line.startswith("#,") and "fuzzy" in line: + fuzzy = True + continue + if line.startswith("#"): + continue + if line.startswith("msgid "): + flush() + msgid = decode_po_string(line[6:].strip()) + msgstr = "" + section = "msgid" + continue + if line.startswith("msgstr "): + msgstr = decode_po_string(line[7:].strip()) + section = "msgstr" + continue + if line.startswith('"'): + if section == "msgid" and msgid is not None: + msgid += decode_po_string(line) + elif section == "msgstr" and msgstr is not None: + msgstr += decode_po_string(line) + + flush() + return entries + + +def bash_ansi_c_quote(value: str) -> str: + escaped = ( + value.replace("\\", "\\\\") + .replace("'", "\\'") + .replace("\n", "\\n") + .replace("\r", "\\r") + .replace("\t", "\\t") + ) + return f"$'{escaped}'" + + +def write_shell_map(po_file: Path) -> None: + if not po_file.exists(): + return + + locale = po_file.parents[1].name + map_file = RUNTIME_LOCALE_DIR / f"{locale}.sh" + map_file.parent.mkdir(parents=True, exist_ok=True) + entries = parse_po(po_file) + + lines = [ + "#!/usr/bin/env bash", + "# Generated by Source/locale/build.py; do not edit manually.", + "# shellcheck shell=bash disable=SC2034", + "declare -gA _T 2>/dev/null || declare -A _T 2>/dev/null || :", + ] + for msgid, msgstr in sorted(entries.items()): + lines.append(f"_T[{bash_ansi_c_quote(msgid)}]={bash_ansi_c_quote(msgstr)}") + + map_file.write_text("\n".join(lines) + "\n", encoding="utf-8") + + +def generate_shell_maps() -> None: + for po_file in PO_FILES: + write_shell_map(po_file) + + +def main() -> None: + update_pot() + merge_po_files() + compile_mo_files() + generate_shell_maps() + + +if __name__ == "__main__": + main() diff --git a/Source/locale/hyde.pot b/Source/locale/hyde.pot new file mode 100644 index 0000000000..67dfc8667a --- /dev/null +++ b/Source/locale/hyde.pot @@ -0,0 +1,74 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the HyDE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: HyDE\n" +"Report-Msgid-Bugs-To: https://github.com/HyDE-Project/HyDE/issues\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: Configs/.local/lib/hyde/notifications.py:20 +msgid "Notifications" +msgstr "" + +#: Configs/.local/lib/hyde/notifications.py:21 +msgid "scroll-down: history pop" +msgstr "" + +#: Configs/.local/lib/hyde/notifications.py:22 +msgid "click-left: Enable & Disable DND" +msgstr "" + +#: Configs/.local/lib/hyde/notifications.py:23 +msgid "click-middle: clear history" +msgstr "" + +#: Configs/.local/lib/hyde/notifications.py:24 +msgid "click-right: close all" +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:14 +msgid "Keybind cache updated" +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:29 +msgid "Keybind Hint" +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:29 +msgid "Initialization failed." +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:34 +msgid "rofi not detected. Displaying on terminal instead" +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:57 +msgid "Keybindings" +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:58 +msgid "Keybinds" +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:59 +msgid "Description" +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:80 +msgid "Repeat" +msgstr "" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:81 +msgid "[Enter] repeat; [ESC] exit" +msgstr "" diff --git a/Source/locale/zh_CN/LC_MESSAGES/hyde.po b/Source/locale/zh_CN/LC_MESSAGES/hyde.po new file mode 100644 index 0000000000..dd9a1a2126 --- /dev/null +++ b/Source/locale/zh_CN/LC_MESSAGES/hyde.po @@ -0,0 +1,72 @@ +# Simplified Chinese translations for HyDE runtime strings. +# Copyright (C) 2026 HyDE contributors +# This file is distributed under the same license as the HyDE package. +# +msgid "" +msgstr "" +"Project-Id-Version: HyDE\n" +"Report-Msgid-Bugs-To: https://github.com/HyDE-Project/HyDE/issues\n" +"POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n" +"PO-Revision-Date: 2026-06-07 00:00+0000\n" +"Last-Translator: HyDE contributors\n" +"Language-Team: Chinese (Simplified)\n" +"Language: zh_CN\n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#: Configs/.local/lib/hyde/notifications.py:20 +msgid "Notifications" +msgstr "通知" + +#: Configs/.local/lib/hyde/notifications.py:21 +msgid "scroll-down: history pop" +msgstr "向下滚动:弹出历史通知" + +#: Configs/.local/lib/hyde/notifications.py:22 +msgid "click-left: Enable & Disable DND" +msgstr "左键:启用/关闭免打扰" + +#: Configs/.local/lib/hyde/notifications.py:23 +msgid "click-middle: clear history" +msgstr "中键:清空历史记录" + +#: Configs/.local/lib/hyde/notifications.py:24 +msgid "click-right: close all" +msgstr "右键:关闭全部通知" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:14 +msgid "Keybind cache updated" +msgstr "快捷键缓存已更新" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:29 +msgid "Keybind Hint" +msgstr "快捷键提示" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:29 +msgid "Initialization failed." +msgstr "初始化失败。" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:34 +msgid "rofi not detected. Displaying on terminal instead" +msgstr "未检测到 rofi,改为在终端中显示" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:57 +msgid "Keybindings" +msgstr "快捷键" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:58 +msgid "Keybinds" +msgstr "快捷键" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:59 +msgid "Description" +msgstr "说明" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:80 +msgid "Repeat" +msgstr "重复执行" + +#: Configs/.local/lib/hyde/keybinds_hint.sh:81 +msgid "[Enter] repeat; [ESC] exit" +msgstr "[Enter] 重复;[ESC] 退出"