diff --git a/kvmd/aiohelpers.py b/kvmd/aiohelpers.py index c3b257d1..a0b86399 100644 --- a/kvmd/aiohelpers.py +++ b/kvmd/aiohelpers.py @@ -22,6 +22,8 @@ import subprocess +from .lanuages import Lanuages + from .logging import get_logger from . import tools @@ -36,13 +38,13 @@ async def remount(name: str, base_cmd: list[str], rw: bool) -> bool: part.format(mode=mode) for part in base_cmd ] - logger.info("Remounting %s storage to %s: %s ...", name, mode.upper(), tools.cmdfmt(cmd)) + logger.info(Lanuages().gettext("Remounting %s storage to %s: %s ..."), name, mode.upper(), tools.cmdfmt(cmd)) try: proc = await aioproc.log_process(cmd, logger) if proc.returncode != 0: assert proc.returncode is not None raise subprocess.CalledProcessError(proc.returncode, cmd) except Exception as err: - logger.error("Can't remount %s storage: %s", name, tools.efmt(err)) + logger.error(Lanuages().gettext("Can't remount %s storage: %s"), name, tools.efmt(err)) return False return True diff --git a/kvmd/aioproc.py b/kvmd/aioproc.py index 376df004..39181d0c 100644 --- a/kvmd/aioproc.py +++ b/kvmd/aioproc.py @@ -26,6 +26,7 @@ import asyncio import asyncio.subprocess import logging +from .lanuages import Lanuages import setproctitle from .logging import get_logger @@ -85,7 +86,7 @@ async def log_stdout_infinite(proc: asyncio.subprocess.Process, logger: logging. else: empty += 1 if empty == 100: # asyncio bug - raise RuntimeError("Asyncio process: too many empty lines") + raise RuntimeError(Lanuages().gettext("Asyncio process: too many empty lines")) async def kill_process(proc: asyncio.subprocess.Process, wait: float, logger: logging.Logger) -> None: # pylint: disable=no-member @@ -100,14 +101,14 @@ async def kill_process(proc: asyncio.subprocess.Process, wait: float, logger: lo if proc.returncode is not None: raise await proc.wait() - logger.info("Process killed: retcode=%d", proc.returncode) + logger.info(Lanuages().gettext("Process killed: retcode=%d"), proc.returncode) except asyncio.CancelledError: pass except Exception: if proc.returncode is None: - logger.exception("Can't kill process pid=%d", proc.pid) + logger.exception(Lanuages().gettext("Can't kill process pid=%d"), proc.pid) else: - logger.info("Process killed: retcode=%d", proc.returncode) + logger.info(Lanuages().gettext("Process killed: retcode=%d"), proc.returncode) def rename_process(suffix: str, prefix: str="kvmd") -> None: @@ -116,7 +117,7 @@ def rename_process(suffix: str, prefix: str="kvmd") -> None: def settle(name: str, suffix: str, prefix: str="kvmd") -> logging.Logger: logger = get_logger(1) - logger.info("Started %s pid=%d", name, os.getpid()) + logger.info(Lanuages().gettext("Started %s pid=%d"), name, os.getpid()) os.setpgrp() rename_process(suffix, prefix) return logger diff --git a/kvmd/apps/kvmd/streamer.py b/kvmd/apps/kvmd/streamer.py index 26904d40..87601a5f 100644 --- a/kvmd/apps/kvmd/streamer.py +++ b/kvmd/apps/kvmd/streamer.py @@ -34,6 +34,8 @@ import aiohttp from PIL import Image as PilImage +from ...lanuages import Lanuages + from ...logging import get_logger from ... import tools @@ -226,6 +228,9 @@ class Streamer: # pylint: disable=too-many-instance-attributes self.__notifier = aiotools.AioNotifier() + self.gettext=Lanuages().gettext + + # ===== @aiotools.atomic_fg @@ -237,15 +242,15 @@ class Streamer: # pylint: disable=too-many-instance-attributes if not self.__stop_wip: self.__stop_task.cancel() await asyncio.gather(self.__stop_task, return_exceptions=True) - logger.info("Streamer stop cancelled") + logger.info(self.gettext("Streamer stop cancelled")) return else: await asyncio.gather(self.__stop_task, return_exceptions=True) if reset and self.__reset_delay > 0: - logger.info("Waiting %.2f seconds for reset delay ...", self.__reset_delay) + logger.info(self.gettext("Waiting %.2f seconds for reset delay ..."), self.__reset_delay) await asyncio.sleep(self.__reset_delay) - logger.info("Starting streamer ...") + logger.info(self.gettext("Starting streamer ...")) await self.__inner_start() @aiotools.atomic_fg @@ -258,12 +263,12 @@ class Streamer: # pylint: disable=too-many-instance-attributes if not self.__stop_wip: self.__stop_task.cancel() await asyncio.gather(self.__stop_task, return_exceptions=True) - logger.info("Stopping streamer immediately ...") + logger.info(self.gettext("Stopping streamer immediately ...")) await self.__inner_stop() else: await asyncio.gather(self.__stop_task, return_exceptions=True) else: - logger.info("Stopping streamer immediately ...") + logger.info(self.gettext("Stopping streamer immediately ...")) await self.__inner_stop() elif not self.__stop_task: @@ -272,13 +277,13 @@ class Streamer: # pylint: disable=too-many-instance-attributes try: await asyncio.sleep(self.__shutdown_delay) self.__stop_wip = True - logger.info("Stopping streamer after delay ...") + logger.info(self.gettext("Stopping streamer after delay ...")) await self.__inner_stop() finally: self.__stop_task = None self.__stop_wip = False - logger.info("Planning to stop streamer in %.2f seconds ...", self.__shutdown_delay) + logger.info(self.gettext("Planning to stop streamer in %.2f seconds ..."), self.__shutdown_delay) self.__stop_task = asyncio.create_task(delayed_stop()) def is_working(self) -> bool: @@ -307,7 +312,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes except (aiohttp.ClientConnectionError, aiohttp.ServerConnectionError): pass except Exception: - get_logger().exception("Invalid streamer response from /state") + get_logger().exception(self.gettext("Invalid streamer response from /state")) snapshot: (dict | None) = None if self.__snapshot: @@ -325,10 +330,10 @@ class Streamer: # pylint: disable=too-many-instance-attributes async def poll_state(self) -> AsyncGenerator[dict, None]: def signal_handler(*_: Any) -> None: - get_logger(0).info("Got SIGUSR2, checking the stream state ...") + get_logger(0).info(self.gettext("Got SIGUSR2, checking the stream state ...")) self.__notifier.notify() - get_logger(0).info("Installing SIGUSR2 streamer handler ...") + get_logger(0).info(self.gettext("Installing SIGUSR2 streamer handler ...")) asyncio.get_event_loop().add_signal_handler(signal.SIGUSR2, signal_handler) waiter_task: (asyncio.Task | None) = None @@ -384,12 +389,12 @@ class Streamer: # pylint: disable=too-many-instance-attributes self.__snapshot = snapshot self.__notifier.notify() return snapshot - logger.error("Stream is offline, no signal or so") + logger.error(self.gettext("Stream is offline, no signal or so")) except (aiohttp.ClientConnectionError, aiohttp.ServerConnectionError) as err: - logger.error("Can't connect to streamer: %s", tools.efmt(err)) + logger.error(self.gettext("Can't connect to streamer: %s"), tools.efmt(err)) except Exception: - logger.exception("Invalid streamer response from /snapshot") + logger.exception(self.gettext("Invalid streamer response from /snapshot")) return None def remove_snapshot(self) -> None: @@ -446,14 +451,14 @@ class Streamer: # pylint: disable=too-many-instance-attributes await self.__start_streamer_proc() assert self.__streamer_proc is not None await aioproc.log_stdout_infinite(self.__streamer_proc, logger) - raise RuntimeError("Streamer unexpectedly died") + raise RuntimeError(self.gettext("Streamer unexpectedly died")) except asyncio.CancelledError: break except Exception: if self.__streamer_proc: - logger.exception("Unexpected streamer error: pid=%d", self.__streamer_proc.pid) + logger.exception(self.gettext("Unexpected streamer error: pid=%d"), self.__streamer_proc.pid) else: - logger.exception("Can't start streamer") + logger.exception(self.gettext("Can't start streamer")) await self.__kill_streamer_proc() await asyncio.sleep(1) @@ -474,13 +479,13 @@ class Streamer: # pylint: disable=too-many-instance-attributes try: await aioproc.log_process(cmd, logger, prefix=name) except Exception as err: - logger.exception("Can't execute command: %s", err) + logger.exception(self.gettext("Can't execute command: %s"), err) async def __start_streamer_proc(self) -> None: assert self.__streamer_proc is None cmd = self.__make_cmd(self.__cmd) self.__streamer_proc = await aioproc.run_process(cmd) - get_logger(0).info("Started streamer pid=%d: %s", self.__streamer_proc.pid, tools.cmdfmt(cmd)) + get_logger(0).info(self.gettext("Started streamer pid=%d: %s"), self.__streamer_proc.pid, tools.cmdfmt(cmd)) async def __kill_streamer_proc(self) -> None: if self.__streamer_proc: diff --git a/kvmd/apps/kvmd/ugpio.py b/kvmd/apps/kvmd/ugpio.py index 872d5f6c..2ccad33c 100644 --- a/kvmd/apps/kvmd/ugpio.py +++ b/kvmd/apps/kvmd/ugpio.py @@ -26,6 +26,8 @@ from typing import AsyncGenerator from typing import Callable from typing import Any +from ...lanuages import Lanuages + from ...logging import get_logger from ...errors import IsBusyError @@ -46,22 +48,22 @@ from ...yamlconf import Section # ===== class GpioChannelNotFoundError(GpioOperationError): def __init__(self) -> None: - super().__init__("GPIO channel is not found") + super().__init__(Lanuages().gettext("GPIO channel is not found")) class GpioSwitchNotSupported(GpioOperationError): def __init__(self) -> None: - super().__init__("This GPIO channel does not support switching") + super().__init__(Lanuages().gettext("This GPIO channel does not support switching")) class GpioPulseNotSupported(GpioOperationError): def __init__(self) -> None: - super().__init__("This GPIO channel does not support pulsing") + super().__init__(Lanuages().gettext("This GPIO channel does not support pulsing")) class GpioChannelIsBusyError(IsBusyError, GpioError): def __init__(self) -> None: - super().__init__("Performing another GPIO operation on this channel, please try again later") + super().__init__(Lanuages().gettext("Performing another GPIO operation on this channel, please try again later")) # ===== @@ -80,6 +82,8 @@ class _GpioInput: self.__driver = driver self.__driver.register_input(self.__pin, config.debounce) + self.gettext=Lanuages().gettext + def get_scheme(self) -> dict: return { "hw": { @@ -188,7 +192,7 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes await func(*args) else: await aiotools.run_region_task( - f"Can't perform {name} of {self} or operation was not completed", + self.gettext(f"Can't perform {name} of {self} or operation was not completed"), self.__region, self.__action_task_wrapper, name, func, *args, ) @@ -197,12 +201,12 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes try: return (await func(*args)) except GpioDriverOfflineError: - get_logger(0).error("Can't perform %s of %s or operation was not completed: driver offline", name, self) + get_logger(0).error(self.gettext("Can't perform %s of %s or operation was not completed: driver offline"), name, self) @aiotools.atomic_fg async def __inner_switch(self, state: bool) -> None: await self.__write(state) - get_logger(0).info("Ensured switch %s to state=%d", self, state) + get_logger(0).info(self.gettext("Ensured switch %s to state=%d"), self, state) await asyncio.sleep(self.__busy_delay) @aiotools.atomic_fg @@ -213,7 +217,7 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes finally: await self.__write(False) await asyncio.sleep(self.__busy_delay) - get_logger(0).info("Pulsed %s with delay=%.2f", self, delay) + get_logger(0).info(self.gettext("Pulsed %s with delay=%.2f"), self, delay) # ===== @@ -224,7 +228,7 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes await self.__driver.write(self.__pin, (state ^ self.__inverted)) def __str__(self) -> str: - return f"Output({self.__channel}, driver={self.__driver}, pin={self.__pin})" + return self.gettext(f"Output({self.__channel}, driver={self.__driver}, pin={self.__pin})") __repr__ = __str__ @@ -249,6 +253,8 @@ class UserGpio: self.__inputs: dict[str, _GpioInput] = {} self.__outputs: dict[str, _GpioOutput] = {} + self.gettext=Lanuages().gettext + for (channel, ch_config) in tools.sorted_kvs(config.scheme): driver = self.__drivers[ch_config.driver] if ch_config.mode == UserGpioModes.INPUT: @@ -289,12 +295,12 @@ class UserGpio: await self.__notifier.wait() def sysprep(self) -> None: - get_logger(0).info("Preparing User-GPIO drivers ...") + get_logger(0).info(self.gettext("Preparing User-GPIO drivers ...")) for (_, driver) in tools.sorted_kvs(self.__drivers): driver.prepare() async def systask(self) -> None: - get_logger(0).info("Running User-GPIO drivers ...") + get_logger(0).info(self.gettext("Running User-GPIO drivers ...")) await asyncio.gather(*[ driver.run() for (_, driver) in tools.sorted_kvs(self.__drivers) @@ -305,7 +311,7 @@ class UserGpio: try: await driver.cleanup() except Exception: - get_logger().exception("Can't cleanup driver %s", driver) + get_logger().exception(self.gettext("Can't cleanup driver %s"), driver) async def switch(self, channel: str, state: bool, wait: bool) -> None: gout = self.__outputs.get(channel) diff --git a/kvmd/apps/otg/__init__.py b/kvmd/apps/otg/__init__.py index 1da23c67..f054cd4d 100644 --- a/kvmd/apps/otg/__init__.py +++ b/kvmd/apps/otg/__init__.py @@ -27,7 +27,9 @@ import json import time import argparse -from os.path import join # pylint: disable=ungrouped-imports +from os.path import join + +from ...lanuages import Lanuages from ...logging import get_logger @@ -201,13 +203,14 @@ def _cmd_start(config: Section) -> None: # pylint: disable=too-many-statements, # https://www.isticktoit.net/?p=1383 logger = get_logger() + gettext=Lanuages().gettext _check_config(config) udc = usb.find_udc(config.otg.udc) - logger.info("Using UDC %s", udc) + logger.info(gettext("Using UDC %s"), udc) - logger.info("Creating gadget %r ...", config.otg.gadget) + logger.info(gettext("Creating gadget %r ..."), config.otg.gadget) gadget_path = usb.get_gadget_path(config.otg.gadget) _mkdir(gadget_path) @@ -248,39 +251,39 @@ def _cmd_start(config: Section) -> None: # pylint: disable=too-many-statements, cod = config.otg.devices if cod.serial.enabled: - logger.info("===== Serial =====") + logger.info(gettext("===== Serial =====")) gc.add_serial(cod.serial.start) if cod.ethernet.enabled: - logger.info("===== Ethernet =====") + logger.info(gettext("===== Ethernet =====")) gc.add_ethernet(**cod.ethernet._unpack(ignore=["enabled"])) if config.kvmd.hid.type == "otg": - logger.info("===== HID-Keyboard =====") + logger.info(gettext("===== HID-Keyboard =====")) gc.add_keyboard(cod.hid.keyboard.start, config.otg.remote_wakeup) - logger.info("===== HID-Mouse =====") + logger.info(gettext("===== HID-Mouse =====")) gc.add_mouse(cod.hid.mouse.start, config.otg.remote_wakeup, config.kvmd.hid.mouse.absolute, config.kvmd.hid.mouse.horizontal_wheel) if config.kvmd.hid.mouse_alt.device: - logger.info("===== HID-Mouse-Alt =====") + logger.info(gettext("===== HID-Mouse-Alt =====")) gc.add_mouse(cod.hid.mouse.start, config.otg.remote_wakeup, (not config.kvmd.hid.mouse.absolute), config.kvmd.hid.mouse.horizontal_wheel) if config.kvmd.msd.type == "otg": - logger.info("===== MSD =====") + logger.info(gettext("===== MSD =====")) gc.add_msd(cod.msd.start, config.otg.user, **cod.msd.default._unpack()) if cod.drives.enabled: for count in range(cod.drives.count): - logger.info("===== MSD Extra: %d =====", count + 1) + logger.info(gettext("===== MSD Extra: %d ====="), count + 1) gc.add_msd(cod.drives.start, "root", **cod.drives.default._unpack()) - logger.info("===== Preparing complete =====") + logger.info(gettext("===== Preparing complete =====")) - logger.info("Enabling the gadget ...") + logger.info(gettext("Enabling the gadget ...")) _write(join(gadget_path, "UDC"), udc) time.sleep(config.otg.init_delay) _chown(join(gadget_path, "UDC"), config.otg.user) _chown(profile_path, config.otg.user) - logger.info("Ready to work") + logger.info(gettext("Ready to work")) # ===== @@ -293,7 +296,7 @@ def _cmd_stop(config: Section) -> None: gadget_path = usb.get_gadget_path(config.otg.gadget) - logger.info("Disabling gadget %r ...", config.otg.gadget) + logger.info(Lanuages().gettext("Disabling gadget %r ..."), config.otg.gadget) _write(join(gadget_path, "UDC"), "\n") _unlink(join(gadget_path, "os_desc", usb.G_PROFILE_NAME), optional=True) diff --git a/kvmd/apps/otgnet/__init__.py b/kvmd/apps/otgnet/__init__.py index 3519d98b..0306fece 100644 --- a/kvmd/apps/otgnet/__init__.py +++ b/kvmd/apps/otgnet/__init__.py @@ -26,6 +26,8 @@ import dataclasses import itertools import argparse +from ...lanuages import Lanuages + from ...logging import get_logger from ...yamlconf import Section @@ -87,6 +89,8 @@ class _Service: # pylint: disable=too-many-instance-attributes self.__gadget: str = config.otg.gadget self.__driver: str = config.otg.devices.ethernet.driver + self.gettext=Lanuages().gettext + def start(self) -> None: asyncio.run(self.__run(True)) @@ -121,20 +125,20 @@ class _Service: # pylint: disable=too-many-instance-attributes for ctl in ctls: if not (await self.__run_ctl(ctl, True)): raise SystemExit(1) - get_logger(0).info("Ready to work") + get_logger(0).info(self.gettext("Ready to work")) else: for ctl in reversed(ctls): await self.__run_ctl(ctl, False) - get_logger(0).info("Bye-bye") + get_logger(0).info(self.gettext("Bye-bye")) async def __run_ctl(self, ctl: BaseCtl, direct: bool) -> bool: logger = get_logger() cmd = ctl.get_command(direct) - logger.info("CMD: %s", tools.cmdfmt(cmd)) + logger.info(self.gettext("CMD: %s"), tools.cmdfmt(cmd)) try: return (not (await aioproc.log_process(cmd, logger)).returncode) except Exception as err: - logger.exception("Can't execute command: %s", err) + logger.exception(self.gettext("Can't execute command: %s"), err) return False # ===== @@ -143,10 +147,10 @@ class _Service: # pylint: disable=too-many-instance-attributes iface = self.__find_iface() logger = get_logger() - logger.info("Using IPv4 network %s ...", self.__iface_net) + logger.info(self.gettext("Using IPv4 network %s ..."), self.__iface_net) net = ipaddress.IPv4Network(self.__iface_net) if net.prefixlen > 31: - raise RuntimeError("Too small network, required at least /31") + raise RuntimeError(self.gettext("Too small network, required at least /31")) if net.prefixlen == 31: iface_ip = str(net[0]) @@ -166,7 +170,7 @@ class _Service: # pylint: disable=too-many-instance-attributes dhcp_ip_end=dhcp_ip_end, dhcp_option_3=(f"3,{iface_ip}" if self.__forward_iface else "3"), ) - logger.info("Calculated %r address is %s/%d", iface, iface_ip, netcfg.net_prefix) + logger.info(self.gettext("Calculated %r address is %s/%d"), iface, iface_ip, netcfg.net_prefix) return netcfg def __find_iface(self) -> str: @@ -175,10 +179,10 @@ class _Service: # pylint: disable=too-many-instance-attributes if self.__driver == "rndis5": real_driver = "rndis" path = usb.get_gadget_path(self.__gadget, usb.G_FUNCTIONS, f"{real_driver}.usb0/ifname") - logger.info("Using OTG gadget %r ...", self.__gadget) + logger.info(self.gettext("Using OTG gadget %r ..."), self.__gadget) with open(path) as file: iface = file.read().strip() - logger.info("Using OTG Ethernet interface %r ...", iface) + logger.info(self.gettext("Using OTG Ethernet interface %r ..."), iface) assert iface return iface diff --git a/kvmd/i18n/zh/LC_MESSAGES/message.mo b/kvmd/i18n/zh/LC_MESSAGES/message.mo index ec6a1c48..7a114704 100644 Binary files a/kvmd/i18n/zh/LC_MESSAGES/message.mo and b/kvmd/i18n/zh/LC_MESSAGES/message.mo differ diff --git a/kvmd/i18n/zh/LC_MESSAGES/message.po b/kvmd/i18n/zh/LC_MESSAGES/message.po index 6171e244..3273b20d 100644 --- a/kvmd/i18n/zh/LC_MESSAGES/message.po +++ b/kvmd/i18n/zh/LC_MESSAGES/message.po @@ -7,8 +7,8 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-08-06 21:57+0800\n" -"PO-Revision-Date: 2024-08-06 21:57+0800\n" +"POT-Creation-Date: 2024-08-12 22:07+0800\n" +"PO-Revision-Date: 2024-08-12 22:07+0800\n" "Last-Translator: \n" "Language: zh\n" "Language-Team: zh \n" @@ -18,6 +18,35 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.15.0\n" +#: kvmd/aiohelpers.py:41 +#, python-format +msgid "Remounting %s storage to %s: %s ..." +msgstr "重新挂载 %s 存储到 %s: %s ......" + +#: kvmd/aiohelpers.py:48 +#, python-format +msgid "Can't remount %s storage: %s" +msgstr "无法重新挂载 %s 存储:%s" + +#: kvmd/aioproc.py:89 +msgid "Asyncio process: too many empty lines" +msgstr "Asyncio 进程:空行过多" + +#: kvmd/aioproc.py:104 kvmd/aioproc.py:111 +#, python-format +msgid "Process killed: retcode=%d" +msgstr "进程被杀死:retcode=%d" + +#: kvmd/aioproc.py:109 +#, python-format +msgid "Can't kill process pid=%d" +msgstr "无法杀死进程 pid=%d" + +#: kvmd/aioproc.py:120 +#, python-format +msgid "Started %s pid=%d" +msgstr "已启动 %s pid=%d" + #: kvmd/htclient.py:63 msgid "Can't determine filename" msgstr "无法确定文件名" @@ -91,58 +120,271 @@ msgstr "尝试使用 --help 选项来了解某项服务的功能。\n" msgid "Make sure you understand exactly what you are doing!" msgstr "请确定你自己在做什么!" -#: kvmd/apps/kvmd/__init__.py:115 +#: kvmd/apps/kvmd/__init__.py:115 kvmd/apps/otgnet/__init__.py:132 msgid "Bye-bye" msgstr "再见" -#: kvmd/apps/kvmd/auth.py:57 +#: kvmd/apps/kvmd/auth.py:58 msgid "AUTHORIZATION IS DISABLED" msgstr "身份验证服务已被禁用" -#: kvmd/apps/kvmd/auth.py:61 +#: kvmd/apps/kvmd/auth.py:62 #, python-format msgid "Authorization is disabled for API %r" msgstr "由于 API %r 身份验证服务已被禁用" -#: kvmd/apps/kvmd/auth.py:66 +#: kvmd/apps/kvmd/auth.py:67 #, python-format msgid "Using internal auth service %r" msgstr "使用内部身份验证服务 %r" -#: kvmd/apps/kvmd/auth.py:73 +#: kvmd/apps/kvmd/auth.py:74 #, python-format msgid "Using external auth service %r" msgstr "使用外部身份验证服务 %r" -#: kvmd/apps/kvmd/auth.py:101 +#: kvmd/apps/kvmd/auth.py:103 #, python-format msgid "Got access denied for user %r by TOTP" msgstr "用户 %r 被 TOTP 拒绝访问" -#: kvmd/apps/kvmd/auth.py:112 +#: kvmd/apps/kvmd/auth.py:114 #, python-format msgid "Authorized user %r via auth service %r" msgstr "用户 %r 已通过身份认证服务 %r 授权" -#: kvmd/apps/kvmd/auth.py:114 +#: kvmd/apps/kvmd/auth.py:116 #, python-format msgid "Got access denied for user %r from auth service %r" msgstr "身份验证服务 %r 拒绝了用户 %r 的访问请求" -#: kvmd/apps/kvmd/auth.py:124 +#: kvmd/apps/kvmd/auth.py:126 #, python-format msgid "Logged in user %r" msgstr "已登录用户 %r" -#: kvmd/apps/kvmd/auth.py:134 +#: kvmd/apps/kvmd/auth.py:136 msgid "Can't generate new unique token" msgstr "无法生成新的唯一令牌" -#: kvmd/apps/kvmd/auth.py:145 +#: kvmd/apps/kvmd/auth.py:147 #, python-format msgid "Logged out user %r (%d)" msgstr "已注销用户 %r (%d)" +#: kvmd/apps/kvmd/streamer.py:245 +msgid "Streamer stop cancelled" +msgstr "Streamer 停止已取消" + +#: kvmd/apps/kvmd/streamer.py:251 +#, python-format +msgid "Waiting %.2f seconds for reset delay ..." +msgstr "等待 %.2f 秒的重置延迟 ......" + +#: kvmd/apps/kvmd/streamer.py:253 +msgid "Starting streamer ..." +msgstr "正在启动 streamer......" + +#: kvmd/apps/kvmd/streamer.py:266 kvmd/apps/kvmd/streamer.py:271 +msgid "Stopping streamer immediately ..." +msgstr "正在停止 streamer......" + +#: kvmd/apps/kvmd/streamer.py:280 +msgid "Stopping streamer after delay ..." +msgstr "在延迟时间到后停止 streamer......" + +#: kvmd/apps/kvmd/streamer.py:286 +#, python-format +msgid "Planning to stop streamer in %.2f seconds ..." +msgstr "计划在 %.2f 秒后停止streamer......" + +#: kvmd/apps/kvmd/streamer.py:315 +msgid "Invalid streamer response from /state" +msgstr "来自 /state 的无效 streamer 响应" + +#: kvmd/apps/kvmd/streamer.py:333 +msgid "Got SIGUSR2, checking the stream state ..." +msgstr "收到 SIGUSR2 信号,正在检查数据流状态 ..." + +#: kvmd/apps/kvmd/streamer.py:336 +msgid "Installing SIGUSR2 streamer handler ..." +msgstr "安装 SIGUSR2 streamer 处理程序 ..." + +#: kvmd/apps/kvmd/streamer.py:392 +msgid "Stream is offline, no signal or so" +msgstr "流媒体离线,没有信号或其他原因" + +#: kvmd/apps/kvmd/streamer.py:395 +#, python-format +msgid "Can't connect to streamer: %s" +msgstr "无法连接 streamer:%s" + +#: kvmd/apps/kvmd/streamer.py:397 +msgid "Invalid streamer response from /snapshot" +msgstr "来自 /snapshot 的无效 streamer 响应" + +#: kvmd/apps/kvmd/streamer.py:454 +msgid "Streamer unexpectedly died" +msgstr "Streamer 意外停止" + +#: kvmd/apps/kvmd/streamer.py:459 +#, python-format +msgid "Unexpected streamer error: pid=%d" +msgstr "Streamer 意外错误:pid=%d" + +#: kvmd/apps/kvmd/streamer.py:461 +msgid "Can't start streamer" +msgstr "无法启动 streamer" + +#: kvmd/apps/kvmd/streamer.py:482 kvmd/apps/otgnet/__init__.py:141 +#, python-format +msgid "Can't execute command: %s" +msgstr "无法执行命令: %s" + +#: kvmd/apps/kvmd/streamer.py:488 +#, python-format +msgid "Started streamer pid=%d: %s" +msgstr "已启动 streamer pid=%d: %s" + +#: kvmd/apps/kvmd/ugpio.py:51 +msgid "GPIO channel is not found" +msgstr "GPIO 未找到" + +#: kvmd/apps/kvmd/ugpio.py:56 +msgid "This GPIO channel does not support switching" +msgstr "该 GPIO 通道不支持切换" + +#: kvmd/apps/kvmd/ugpio.py:61 +msgid "This GPIO channel does not support pulsing" +msgstr "该 GPIO 通道不支持脉冲信号" + +#: kvmd/apps/kvmd/ugpio.py:66 +msgid "Performing another GPIO operation on this channel, please try again later" +msgstr "在此通道上正在执行另一个 GPIO 操作,请稍后再试" + +#: kvmd/apps/kvmd/ugpio.py:204 +#, python-format +msgid "Can't perform %s of %s or operation was not completed: driver offline" +msgstr "无法执行 %s 的 %s 或操作未完成:驱动程序离线" + +#: kvmd/apps/kvmd/ugpio.py:209 +#, python-format +msgid "Ensured switch %s to state=%d" +msgstr "确保将 %s 切换到状态=%d" + +#: kvmd/apps/kvmd/ugpio.py:220 +#, python-format +msgid "Pulsed %s with delay=%.2f" +msgstr "脉冲%s,延迟=%.2f" + +#: kvmd/apps/kvmd/ugpio.py:298 +msgid "Preparing User-GPIO drivers ..." +msgstr "准备 User-GPIO 驱动程序 ......" + +#: kvmd/apps/kvmd/ugpio.py:303 +msgid "Running User-GPIO drivers ..." +msgstr "运行 User-GPIO 驱动程序 ......" + +#: kvmd/apps/kvmd/ugpio.py:314 +#, python-format +msgid "Can't cleanup driver %s" +msgstr "无法清理驱动程序 %s" + +#: kvmd/apps/otg/__init__.py:211 kvmd/plugins/hid/otg/__init__.py:123 +#, python-format +msgid "Using UDC %s" +msgstr "使用 UDC %s" + +#: kvmd/apps/otg/__init__.py:213 +#, python-format +msgid "Creating gadget %r ..." +msgstr "新建 gadget %r ......" + +#: kvmd/apps/otg/__init__.py:254 +msgid "===== Serial =====" +msgstr "===== 串口 =====" + +#: kvmd/apps/otg/__init__.py:258 +msgid "===== Ethernet =====" +msgstr "===== 以太网 =====" + +#: kvmd/apps/otg/__init__.py:262 +msgid "===== HID-Keyboard =====" +msgstr "===== HID-键盘 =====" + +#: kvmd/apps/otg/__init__.py:264 +msgid "===== HID-Mouse =====" +msgstr "===== HID-鼠标 =====" + +#: kvmd/apps/otg/__init__.py:267 +msgid "===== HID-Mouse-Alt =====" +msgstr "===== HID-绝对鼠标 =====" + +#: kvmd/apps/otg/__init__.py:271 +msgid "===== MSD =====" +msgstr "===== MSD =====" + +#: kvmd/apps/otg/__init__.py:275 +#, python-format +msgid "===== MSD Extra: %d =====" +msgstr "===== MSD 扩展: %d =====" + +#: kvmd/apps/otg/__init__.py:278 +msgid "===== Preparing complete =====" +msgstr "===== 准备完成 =====" + +#: kvmd/apps/otg/__init__.py:280 +msgid "Enabling the gadget ..." +msgstr "启用此 gadget ......" + +#: kvmd/apps/otg/__init__.py:286 kvmd/apps/otgnet/__init__.py:128 +msgid "Ready to work" +msgstr "准备就绪" + +#: kvmd/apps/otg/__init__.py:299 +#, python-format +msgid "Disabling gadget %r ..." +msgstr "禁用 gadget %r ......" + +#: kvmd/apps/otgnet/__init__.py:137 +#, python-format +msgid "CMD: %s" +msgstr "命令行: %s" + +#: kvmd/apps/otgnet/__init__.py:150 +#, python-format +msgid "Using IPv4 network %s ..." +msgstr "使用 IPv4 网络 %s ......" + +#: kvmd/apps/otgnet/__init__.py:153 +msgid "Too small network, required at least /31" +msgstr "网络段太小,至少需要 /31" + +#: kvmd/apps/otgnet/__init__.py:173 +#, python-format +msgid "Calculated %r address is %s/%d" +msgstr "计算出的 %r 地址为 %s/%d" + +#: kvmd/apps/otgnet/__init__.py:182 +#, python-format +msgid "Using OTG gadget %r ..." +msgstr "使用 OTG gadget %r ......" + +#: kvmd/apps/otgnet/__init__.py:185 +#, python-format +msgid "Using OTG Ethernet interface %r ..." +msgstr "使用 OTG 以太网接口 %r ......" + +#: kvmd/keyboard/keysym.py:69 +#, python-format +msgid "Invalid modifier key at mapping %s: %s / %s" +msgstr "映射 %s 处的修改键无效: %s / %s" + +#: kvmd/keyboard/keysym.py:122 +#, python-format +msgid "Reading keyboard layout %s ..." +msgstr "读取键盘布局 %s ......" + #: kvmd/plugins/atx/__init__.py:45 msgid "Performing another ATX operation, please try again later" msgstr "正在处理另一个 ATX 动作,请稍等" @@ -188,7 +430,7 @@ msgstr "正在启动 HID 守护程序......" #: kvmd/plugins/hid/bt/__init__.py:182 kvmd/plugins/hid/ch9329/__init__.py:141 msgid "Stopping HID daemon ..." -msgstr "正在启停止 HID 守护程序......" +msgstr "正在停止 HID 守护程序......" #: kvmd/plugins/hid/bt/__init__.py:231 msgid "Unexpected HID error" @@ -197,7 +439,7 @@ msgstr "未知 HID 错误" #: kvmd/plugins/hid/bt/server.py:153 #, python-format msgid "Listening [%s]:%d for %s ..." -msgstr "监听 [%s]:%d for %s ..." +msgstr "监听 [%s]:%d for %s ......" #: kvmd/plugins/hid/bt/server.py:190 #, python-format diff --git a/kvmd/keyboard/keysym.py b/kvmd/keyboard/keysym.py index 5e80d789..1683ad53 100644 --- a/kvmd/keyboard/keysym.py +++ b/kvmd/keyboard/keysym.py @@ -27,6 +27,8 @@ import importlib.machinery import Xlib.keysymdef +from ..lanuages import Lanuages + from ..logging import get_logger from .mappings import At1Key @@ -64,7 +66,7 @@ def build_symmap(path: str) -> dict[int, dict[int, str]]: # x11 keysym -> [(mod or (web_name in WebModifiers.ALTS and key.altgr) or (web_name in WebModifiers.CTRLS and key.ctrl) ): - logger.error("Invalid modifier key at mapping %s: %s / %s", src, web_name, key) + logger.error(Lanuages().gettext("Invalid modifier key at mapping %s: %s / %s"), src, web_name, key) continue modifiers = ( @@ -117,7 +119,7 @@ def _resolve_keysym(name: str) -> int: def _read_keyboard_layout(path: str) -> dict[int, list[At1Key]]: # Keysym to evdev (at1) logger = get_logger(0) - logger.info("Reading keyboard layout %s ...", path) + logger.info(Lanuages().gettext("Reading keyboard layout %s ..."), path) with open(path) as file: lines = list(map(str.strip, file.read().split("\n"))) diff --git a/kvmd/plugins/hid/otg/__init__.py b/kvmd/plugins/hid/otg/__init__.py index 3516546d..202dddca 100644 --- a/kvmd/plugins/hid/otg/__init__.py +++ b/kvmd/plugins/hid/otg/__init__.py @@ -24,6 +24,8 @@ from typing import Iterable from typing import AsyncGenerator from typing import Any +from ....lanuages import Lanuages + from ....logging import get_logger from .... import aiomulti @@ -118,7 +120,7 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes def sysprep(self) -> None: udc = usb.find_udc(self.__udc) - get_logger(0).info("Using UDC %s", udc) + get_logger(0).info(Lanuages().gettext("Using UDC %s"), udc) self.__keyboard_proc.start(udc) self.__mouse_proc.start(udc) if self.__mouse_alt_proc: diff --git a/message.pot b/message.pot index ff584f26..01bec020 100644 --- a/message.pot +++ b/message.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PROJECT VERSION\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2024-08-06 21:57+0800\n" +"POT-Creation-Date: 2024-08-12 22:07+0800\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -17,6 +17,35 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Generated-By: Babel 2.15.0\n" +#: kvmd/aiohelpers.py:41 +#, python-format +msgid "Remounting %s storage to %s: %s ..." +msgstr "" + +#: kvmd/aiohelpers.py:48 +#, python-format +msgid "Can't remount %s storage: %s" +msgstr "" + +#: kvmd/aioproc.py:89 +msgid "Asyncio process: too many empty lines" +msgstr "" + +#: kvmd/aioproc.py:104 kvmd/aioproc.py:111 +#, python-format +msgid "Process killed: retcode=%d" +msgstr "" + +#: kvmd/aioproc.py:109 +#, python-format +msgid "Can't kill process pid=%d" +msgstr "" + +#: kvmd/aioproc.py:120 +#, python-format +msgid "Started %s pid=%d" +msgstr "" + #: kvmd/htclient.py:63 msgid "Can't determine filename" msgstr "" @@ -90,58 +119,271 @@ msgstr "" msgid "Make sure you understand exactly what you are doing!" msgstr "" -#: kvmd/apps/kvmd/__init__.py:115 +#: kvmd/apps/kvmd/__init__.py:115 kvmd/apps/otgnet/__init__.py:132 msgid "Bye-bye" msgstr "" -#: kvmd/apps/kvmd/auth.py:57 +#: kvmd/apps/kvmd/auth.py:58 msgid "AUTHORIZATION IS DISABLED" msgstr "" -#: kvmd/apps/kvmd/auth.py:61 +#: kvmd/apps/kvmd/auth.py:62 #, python-format msgid "Authorization is disabled for API %r" msgstr "" -#: kvmd/apps/kvmd/auth.py:66 +#: kvmd/apps/kvmd/auth.py:67 #, python-format msgid "Using internal auth service %r" msgstr "" -#: kvmd/apps/kvmd/auth.py:73 +#: kvmd/apps/kvmd/auth.py:74 #, python-format msgid "Using external auth service %r" msgstr "" -#: kvmd/apps/kvmd/auth.py:101 +#: kvmd/apps/kvmd/auth.py:103 #, python-format msgid "Got access denied for user %r by TOTP" msgstr "" -#: kvmd/apps/kvmd/auth.py:112 +#: kvmd/apps/kvmd/auth.py:114 #, python-format msgid "Authorized user %r via auth service %r" msgstr "" -#: kvmd/apps/kvmd/auth.py:114 +#: kvmd/apps/kvmd/auth.py:116 #, python-format msgid "Got access denied for user %r from auth service %r" msgstr "" -#: kvmd/apps/kvmd/auth.py:124 +#: kvmd/apps/kvmd/auth.py:126 #, python-format msgid "Logged in user %r" msgstr "" -#: kvmd/apps/kvmd/auth.py:134 +#: kvmd/apps/kvmd/auth.py:136 msgid "Can't generate new unique token" msgstr "" -#: kvmd/apps/kvmd/auth.py:145 +#: kvmd/apps/kvmd/auth.py:147 #, python-format msgid "Logged out user %r (%d)" msgstr "" +#: kvmd/apps/kvmd/streamer.py:245 +msgid "Streamer stop cancelled" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:251 +#, python-format +msgid "Waiting %.2f seconds for reset delay ..." +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:253 +msgid "Starting streamer ..." +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:266 kvmd/apps/kvmd/streamer.py:271 +msgid "Stopping streamer immediately ..." +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:280 +msgid "Stopping streamer after delay ..." +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:286 +#, python-format +msgid "Planning to stop streamer in %.2f seconds ..." +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:315 +msgid "Invalid streamer response from /state" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:333 +msgid "Got SIGUSR2, checking the stream state ..." +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:336 +msgid "Installing SIGUSR2 streamer handler ..." +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:392 +msgid "Stream is offline, no signal or so" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:395 +#, python-format +msgid "Can't connect to streamer: %s" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:397 +msgid "Invalid streamer response from /snapshot" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:454 +msgid "Streamer unexpectedly died" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:459 +#, python-format +msgid "Unexpected streamer error: pid=%d" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:461 +msgid "Can't start streamer" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:482 kvmd/apps/otgnet/__init__.py:141 +#, python-format +msgid "Can't execute command: %s" +msgstr "" + +#: kvmd/apps/kvmd/streamer.py:488 +#, python-format +msgid "Started streamer pid=%d: %s" +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:51 +msgid "GPIO channel is not found" +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:56 +msgid "This GPIO channel does not support switching" +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:61 +msgid "This GPIO channel does not support pulsing" +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:66 +msgid "Performing another GPIO operation on this channel, please try again later" +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:204 +#, python-format +msgid "Can't perform %s of %s or operation was not completed: driver offline" +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:209 +#, python-format +msgid "Ensured switch %s to state=%d" +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:220 +#, python-format +msgid "Pulsed %s with delay=%.2f" +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:298 +msgid "Preparing User-GPIO drivers ..." +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:303 +msgid "Running User-GPIO drivers ..." +msgstr "" + +#: kvmd/apps/kvmd/ugpio.py:314 +#, python-format +msgid "Can't cleanup driver %s" +msgstr "" + +#: kvmd/apps/otg/__init__.py:211 kvmd/plugins/hid/otg/__init__.py:123 +#, python-format +msgid "Using UDC %s" +msgstr "" + +#: kvmd/apps/otg/__init__.py:213 +#, python-format +msgid "Creating gadget %r ..." +msgstr "" + +#: kvmd/apps/otg/__init__.py:254 +msgid "===== Serial =====" +msgstr "" + +#: kvmd/apps/otg/__init__.py:258 +msgid "===== Ethernet =====" +msgstr "" + +#: kvmd/apps/otg/__init__.py:262 +msgid "===== HID-Keyboard =====" +msgstr "" + +#: kvmd/apps/otg/__init__.py:264 +msgid "===== HID-Mouse =====" +msgstr "" + +#: kvmd/apps/otg/__init__.py:267 +msgid "===== HID-Mouse-Alt =====" +msgstr "" + +#: kvmd/apps/otg/__init__.py:271 +msgid "===== MSD =====" +msgstr "" + +#: kvmd/apps/otg/__init__.py:275 +#, python-format +msgid "===== MSD Extra: %d =====" +msgstr "" + +#: kvmd/apps/otg/__init__.py:278 +msgid "===== Preparing complete =====" +msgstr "" + +#: kvmd/apps/otg/__init__.py:280 +msgid "Enabling the gadget ..." +msgstr "" + +#: kvmd/apps/otg/__init__.py:286 kvmd/apps/otgnet/__init__.py:128 +msgid "Ready to work" +msgstr "" + +#: kvmd/apps/otg/__init__.py:299 +#, python-format +msgid "Disabling gadget %r ..." +msgstr "" + +#: kvmd/apps/otgnet/__init__.py:137 +#, python-format +msgid "CMD: %s" +msgstr "" + +#: kvmd/apps/otgnet/__init__.py:150 +#, python-format +msgid "Using IPv4 network %s ..." +msgstr "" + +#: kvmd/apps/otgnet/__init__.py:153 +msgid "Too small network, required at least /31" +msgstr "" + +#: kvmd/apps/otgnet/__init__.py:173 +#, python-format +msgid "Calculated %r address is %s/%d" +msgstr "" + +#: kvmd/apps/otgnet/__init__.py:182 +#, python-format +msgid "Using OTG gadget %r ..." +msgstr "" + +#: kvmd/apps/otgnet/__init__.py:185 +#, python-format +msgid "Using OTG Ethernet interface %r ..." +msgstr "" + +#: kvmd/keyboard/keysym.py:69 +#, python-format +msgid "Invalid modifier key at mapping %s: %s / %s" +msgstr "" + +#: kvmd/keyboard/keysym.py:122 +#, python-format +msgid "Reading keyboard layout %s ..." +msgstr "" + #: kvmd/plugins/atx/__init__.py:45 msgid "Performing another ATX operation, please try again later" msgstr ""