Revert "进一步的 kvmd 国际化(汉化)支持,添加配置入口"

This reverts commit 35397c54143f3dba89bebc4e30bc09b0804b5798.
This commit is contained in:
mofeng-git 2024-11-20 11:51:37 +00:00
parent 50819d0a35
commit b419641251
47 changed files with 181 additions and 567 deletions

View File

@ -22,7 +22,7 @@
import subprocess
from .languages import Languages
from .lanuages import Lanuages
from .logging import get_logger
@ -38,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(Languages().gettext("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(Languages().gettext("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

View File

@ -26,7 +26,7 @@ import asyncio
import asyncio.subprocess
import logging
from .languages import Languages
from .lanuages import Lanuages
import setproctitle
from .logging import get_logger
@ -86,7 +86,7 @@ async def log_stdout_infinite(proc: asyncio.subprocess.Process, logger: logging.
else:
empty += 1
if empty == 100: # asyncio bug
raise RuntimeError(Languages().gettext("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
@ -101,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(Languages().gettext("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(Languages().gettext("Can't kill process pid=%d"), proc.pid)
logger.exception(Lanuages().gettext("Can't kill process pid=%d"), proc.pid)
else:
logger.info(Languages().gettext("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:
@ -117,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(Languages().gettext("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

View File

@ -105,9 +105,7 @@ from ..validators.hw import valid_otg_gadget
from ..validators.hw import valid_otg_id
from ..validators.hw import valid_otg_ethernet
from ..validators.languages import valid_languages
from ..languages import Languages
from ..lanuages import Lanuages
# =====
def init(
@ -129,16 +127,16 @@ def init(
add_help=add_help,
formatter_class=argparse.ArgumentDefaultsHelpFormatter,
)
_ = translation(domain="message",localedir="/kvmd/i18n",languages=["zh"]).gettext
parser.add_argument("-c", "--config", default="/etc/kvmd/main.yaml", type=valid_abs_file,
help="Set config file path", metavar="<file>")
help=_("Set config file path"), metavar="<file>")
parser.add_argument("-o", "--set-options", default=[], nargs="+",
help="Override config options list (like sec/sub/opt=value)", metavar="<k=v>",)
help=_("Override config options list (like sec/sub/opt=value)"), metavar="<k=v>",)
parser.add_argument("-m", "--dump-config", action="store_true",
help="View current configuration (include all overrides)")
help=_("View current configuration (include all overrides)"))
if check_run:
parser.add_argument("--run", dest="run", action="store_true",
help="Run the service")
help=_("Run the service"))
(options, remaining) = parser.parse_known_args(argv)
if options.dump_config:
@ -153,18 +151,9 @@ def init(
))
raise SystemExit()
config = _init_config(options.config, options.set_options, **load)
logging.captureWarnings(True)
logging.config.dictConfig(config.logging)
if isinstance(config.get("languages"), dict) and isinstance(config["languages"].get("console"), str):
i18n_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))+"/i18n"
Languages.init("message", i18n_path, config["languages"]["console"])
gettext = Languages().gettext
logging.addLevelName(20, gettext("INFO"))
logging.addLevelName(30, gettext("WARNING"))
logging.addLevelName(40, gettext("ERROR"))
if cli_logging:
logging.getLogger().handlers[0].setFormatter(logging.Formatter(
"-- {levelname:>7} -- {message}",
@ -173,7 +162,7 @@ def init(
if check_run and not options.run:
raise SystemExit(
gettext("To prevent accidental startup, you must specify the --run option to start.\n")+gettext("Try the --help option to find out what this service does.\n")+gettext("Make sure you understand exactly what you are doing!"))
_("To prevent accidental startup, you must specify the --run option to start.\n")+_("Try the --help option to find out what this service does.\n")+_("Make sure you understand exactly what you are doing!"))
return (parser, remaining, config)
@ -798,9 +787,4 @@ def _get_config_scheme() -> dict:
"timeout": Option(300, type=valid_int_f1),
"interval": Option(30, type=valid_int_f1),
},
"languages": {
"console": Option("default", type=valid_languages),
"web": Option("default", type=valid_languages),
},
}

View File

@ -26,7 +26,7 @@ from ...plugins.hid import get_hid_class
from ...plugins.atx import get_atx_class
from ...plugins.msd import get_msd_class
from ...languages import Languages
from ...lanuages import Lanuages
from .. import init
@ -112,4 +112,4 @@ def main(argv: (list[str] | None)=None) -> None:
stream_forever=config.streamer.forever,
).run(**config.server._unpack())
get_logger(0).info(Languages().gettext("Bye-bye"))
get_logger(0).info(Lanuages().gettext("Bye-bye"))

View File

@ -34,7 +34,7 @@ from ...plugins.auth import get_auth_service_class
from ...htserver import HttpExposed
from ...languages import Languages
from ...lanuages import Lanuages
# =====
class AuthManager:
@ -52,7 +52,7 @@ class AuthManager:
totp_secret_path: str,
) -> None:
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
self.__enabled = enabled
if not enabled:
get_logger().warning(self.gettext("AUTHORIZATION IS DISABLED"))

View File

@ -33,8 +33,6 @@ from aiohttp.web import Request
from aiohttp.web import Response
from aiohttp.web import WebSocketResponse
from ...languages import Languages
from ...logging import get_logger
from ...errors import OperationError
@ -86,17 +84,17 @@ from .api.redfish import RedfishApi
# =====
class StreamerQualityNotSupported(OperationError):
def __init__(self) -> None:
super().__init__(Languages().gettext("This streamer does not support quality settings"))
super().__init__("This streamer does not support quality settings")
class StreamerResolutionNotSupported(OperationError):
def __init__(self) -> None:
super().__init__(Languages().gettext("This streamer does not support resolution settings"))
super().__init__("This streamer does not support resolution settings")
class StreamerH264NotSupported(OperationError):
def __init__(self) -> None:
super().__init__(Languages().gettext("This streamer does not support H264"))
super().__init__("This streamer does not support H264")
# =====
@ -212,8 +210,6 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
self.__reset_streamer = False
self.__new_streamer_params: dict = {}
self.gettext=Languages().gettext
# ===== STREAMER CONTROLLER
@exposed_http("POST", "/streamer/set_params")
@ -295,24 +291,24 @@ class KvmdServer(HttpServer): # pylint: disable=too-many-arguments,too-many-ins
async def _on_shutdown(self) -> None:
logger = get_logger(0)
logger.info(self.gettext("Waiting short tasks ..."))
logger.info("Waiting short tasks ...")
await aiotools.wait_all_short_tasks()
logger.info(self.gettext("Stopping system tasks ..."))
logger.info("Stopping system tasks ...")
await aiotools.stop_all_deadly_tasks()
logger.info(self.gettext("Disconnecting clients ..."))
logger.info("Disconnecting clients ...")
await self._close_all_wss()
logger.info(self.gettext("On-Shutdown complete"))
logger.info("On-Shutdown complete")
async def _on_cleanup(self) -> None:
logger = get_logger(0)
for sub in self.__subsystems:
if sub.cleanup:
logger.info(self.gettext("Cleaning up %s ..."), sub.name)
logger.info("Cleaning up %s ...", sub.name)
try:
await sub.cleanup() # type: ignore
except Exception:
logger.exception(self.gettext("Cleanup error on %s"), sub.name)
logger.info(self.gettext("On-Cleanup complete"))
logger.exception("Cleanup error on %s", sub.name)
logger.info("On-Cleanup complete")
async def _on_ws_opened(self) -> None:
self.__streamer_notifier.notify()

View File

@ -34,7 +34,7 @@ import aiohttp
from PIL import Image as PilImage
from ...languages import Languages
from ...lanuages import Lanuages
from ...logging import get_logger
@ -228,7 +228,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes
self.__notifier = aiotools.AioNotifier()
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
# =====

View File

@ -26,7 +26,7 @@ from typing import AsyncGenerator
from typing import Callable
from typing import Any
from ...languages import Languages
from ...lanuages import Lanuages
from ...logging import get_logger
@ -48,22 +48,22 @@ from ...yamlconf import Section
# =====
class GpioChannelNotFoundError(GpioOperationError):
def __init__(self) -> None:
super().__init__(Languages().gettext("GPIO channel is not found"))
super().__init__(Lanuages().gettext("GPIO channel is not found"))
class GpioSwitchNotSupported(GpioOperationError):
def __init__(self) -> None:
super().__init__(Languages().gettext("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__(Languages().gettext("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__(Languages().gettext("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"))
# =====
@ -82,7 +82,7 @@ class _GpioInput:
self.__driver = driver
self.__driver.register_input(self.__pin, config.debounce)
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def get_scheme(self) -> dict:
return {
@ -255,7 +255,7 @@ class UserGpio:
self.__inputs: dict[str, _GpioInput] = {}
self.__outputs: dict[str, _GpioOutput] = {}
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
for (channel, ch_config) in tools.sorted_kvs(config.scheme):
driver = self.__drivers[ch_config.driver]

View File

@ -29,7 +29,7 @@ import argparse
from os.path import join
from ...languages import Languages
from ...lanuages import Lanuages
from ...logging import get_logger
@ -207,7 +207,7 @@ def _cmd_start(config: Section) -> None: # pylint: disable=too-many-statements,
# https://www.isticktoit.net/?p=1383
logger = get_logger()
gettext=Languages().gettext
gettext=Lanuages().gettext
_check_config(config)
@ -300,7 +300,7 @@ def _cmd_stop(config: Section) -> None:
gadget_path = usb.get_gadget_path(config.otg.gadget)
logger.info(Languages().gettext("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)

View File

@ -26,7 +26,7 @@ import dataclasses
import itertools
import argparse
from ...languages import Languages
from ...lanuages import Lanuages
from ...logging import get_logger
@ -89,7 +89,7 @@ class _Service: # pylint: disable=too-many-instance-attributes
self.__gadget: str = config.otg.gadget
self.__driver: str = config.otg.devices.ethernet.driver
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def start(self) -> None:
asyncio.run(self.__run(True))

View File

@ -28,8 +28,6 @@ import contextlib
import aiohttp
from ...languages import Languages
from ...logging import get_logger
from ...keyboard.keysym import SymmapModifiers
@ -135,8 +133,6 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
self.__modifiers = 0
self.gettext=Languages().gettext
# =====
async def run(self) -> None:
@ -160,13 +156,13 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
logger = get_logger(0)
await self.__stage1_authorized.wait_passed()
logger.info(self.gettext("%s [kvmd]: Waiting for the SetEncodings message ..."), self._remote)
logger.info("%s [kvmd]: Waiting for the SetEncodings message ...", self._remote)
if not (await self.__stage2_encodings_accepted.wait_passed(timeout=5)):
raise RfbError(self.gettext("No SetEncodings message recieved from the client in 5 secs"))
raise RfbError("No SetEncodings message recieved from the client in 5 secs")
assert self.__kvmd_session
try:
logger.info(self.gettext("%s [kvmd]: Applying HID params: mouse_output=%s ..."), self._remote, self.__mouse_output)
logger.info("%s [kvmd]: Applying HID params: mouse_output=%s ...", self._remote, self.__mouse_output)
await self.__kvmd_session.hid.set_params(mouse_output=self.__mouse_output)
async with self.__kvmd_session.ws() as self.__kvmd_ws:
@ -174,7 +170,7 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
self.__stage3_ws_connected.set_passed()
async for (event_type, event) in self.__kvmd_ws.communicate():
await self.__process_ws_event(event_type, event)
raise RfbError(self.gettext("KVMD closed the websocket (the server may have been stopped)"))
raise RfbError("KVMD closed the websocket (the server may have been stopped)")
finally:
self.__kvmd_ws = None
@ -208,19 +204,19 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
while True:
frame = await read_frame(not self.__fb_has_key)
if not streaming:
logger.info(self.gettext("%s [streamer]: Streaming ..."), self._remote)
logger.info("%s [streamer]: Streaming ...", self._remote)
streaming = True
if frame["online"]:
await self.__queue_frame(frame)
else:
await self.__queue_frame(self.gettext("No signal"))
await self.__queue_frame("No signal")
except StreamerError as err:
if isinstance(err, StreamerPermError):
streamer = self.__get_default_streamer()
logger.info(self.gettext("%s [streamer]: Permanent error: %s; switching to %s ..."), self._remote, err, streamer)
logger.info("%s [streamer]: Permanent error: %s; switching to %s ...", self._remote, err, streamer)
else:
logger.info(self.gettext("%s [streamer]: Waiting for stream: %s"), self._remote, err)
await self.__queue_frame(self.gettext("Waiting for stream ..."))
logger.info("%s [streamer]: Waiting for stream: %s", self._remote, err)
await self.__queue_frame("Waiting for stream ...")
await asyncio.sleep(1)
def __get_preferred_streamer(self) -> BaseStreamerClient:
@ -231,13 +227,13 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
streamer: (BaseStreamerClient | None) = None
for streamer in self.__streamers:
if getattr(self._encodings, formats[streamer.get_format()]):
get_logger(0).info(self.gettext("%s [streamer]: Using preferred %s"), self._remote, streamer)
get_logger(0).info("%s [streamer]: Using preferred %s", self._remote, streamer)
return streamer
raise RuntimeError("No streamers found")
def __get_default_streamer(self) -> BaseStreamerClient:
streamer = self.__streamers[-1]
get_logger(0).info(self.gettext("%s [streamer]: Using default %s"), self._remote, streamer)
get_logger(0).info("%s [streamer]: Using default %s", self._remote, streamer)
return streamer
async def __queue_frame(self, frame: (dict | str)) -> None:
@ -302,13 +298,13 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
await self._send_fb_jpeg(last["data"])
elif last["format"] == StreamFormats.H264:
if not self._encodings.has_h264:
raise RfbError(self.gettext("The client doesn't want to accept H264 anymore"))
raise RfbError("The client doesn't want to accept H264 anymore")
if self.__fb_has_key:
await self._send_fb_h264(last["data"])
else:
await self._send_fb_allow_again()
else:
raise RuntimeError(self.gettext(f"Unknown format: {last['format']}"))
raise RuntimeError(f"Unknown format: {last['format']}")
last["data"] = b""
# =====
@ -414,7 +410,7 @@ class _Client(RfbClient): # pylint: disable=too-many-instance-attributes
has_quality = (await self.__kvmd_session.streamer.get_state())["features"]["quality"]
quality = (self._encodings.tight_jpeg_quality if has_quality else None)
get_logger(0).info(self.gettext("%s [main]: Applying streamer params: jpeg_quality=%s; desired_fps=%d ..."),
get_logger(0).info("%s [main]: Applying streamer params: jpeg_quality=%s; desired_fps=%d ...",
self._remote, quality, self.__desired_fps)
await self.__kvmd_session.streamer.set_params(quality, self.__desired_fps)
@ -460,16 +456,14 @@ class VncServer: # pylint: disable=too-many-instance-attributes
shared_params = _SharedParams()
self.gettext=Languages().gettext
async def cleanup_client(writer: asyncio.StreamWriter) -> None:
if (await aiotools.close_writer(writer)):
get_logger(0).info(self.gettext("%s [entry]: Connection is closed in an emergency"), rfb_format_remote(writer))
get_logger(0).info("%s [entry]: Connection is closed in an emergency", rfb_format_remote(writer))
async def handle_client(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
logger = get_logger(0)
remote = rfb_format_remote(writer)
logger.info(self.gettext("%s [entry]: Connected client"), remote)
logger.info("%s [entry]: Connected client", remote)
try:
sock = writer.get_extra_info("socket")
if no_delay:
@ -488,7 +482,7 @@ class VncServer: # pylint: disable=too-many-instance-attributes
async with kvmd.make_session("", "") as kvmd_session:
none_auth_only = await kvmd_session.auth.check()
except (aiohttp.ClientError, asyncio.TimeoutError) as err:
logger.error(self.gettext("%s [entry]: Can't check KVMD auth mode: %s"), remote, tools.efmt(err))
logger.error("%s [entry]: Can't check KVMD auth mode: %s", remote, tools.efmt(err))
return
await _Client(
@ -510,7 +504,7 @@ class VncServer: # pylint: disable=too-many-instance-attributes
shared_params=shared_params,
).run()
except Exception:
logger.exception(self.gettext("%s [entry]: Unhandled exception in client task"), remote)
logger.exception("%s [entry]: Unhandled exception in client task", remote)
finally:
await aiotools.shield_fg(cleanup_client(writer))
@ -520,7 +514,7 @@ class VncServer: # pylint: disable=too-many-instance-attributes
if not (await self.__vnc_auth_manager.read_credentials())[1]:
raise SystemExit(1)
get_logger(0).info(self.gettext("Listening VNC on TCP [%s]:%d ..."), self.__host, self.__port)
get_logger(0).info("Listening VNC on TCP [%s]:%d ...", self.__host, self.__port)
(family, _, _, _, addr) = socket.getaddrinfo(self.__host, self.__port, type=socket.SOCK_STREAM)[0]
with contextlib.closing(socket.socket(family, socket.SOCK_STREAM)) as sock:
if family == socket.AF_INET6:
@ -538,4 +532,4 @@ class VncServer: # pylint: disable=too-many-instance-attributes
def run(self) -> None:
aiotools.run(self.__inner_run())
get_logger().info(self.gettext("Bye-bye"))
get_logger().info("Bye-bye")

View File

@ -22,8 +22,6 @@
import dataclasses
from ...languages import Languages
from ...logging import get_logger
from ... import aiotools
@ -32,7 +30,7 @@ from ... import aiotools
# =====
class VncAuthError(Exception):
def __init__(self, path: str, lineno: int, msg: str) -> None:
super().__init__(Languages().gettext(f"Syntax error at {path}:{lineno}: {msg}"))
super().__init__(f"Syntax error at {path}:{lineno}: {msg}")
# =====
@ -51,7 +49,6 @@ class VncAuthManager:
self.__path = path
self.__enabled = enabled
self.gettext=Languages().gettext
async def read_credentials(self) -> tuple[dict[str, VncAuthKvmdCredentials], bool]:
if self.__enabled:
@ -60,7 +57,7 @@ class VncAuthManager:
except VncAuthError as err:
get_logger(0).error(str(err))
except Exception:
get_logger(0).exception(self.gettext("Unhandled exception while reading VNCAuth passwd file"))
get_logger(0).exception("Unhandled exception while reading VNCAuth passwd file")
return ({}, (not self.__enabled))
async def __inner_read_credentials(self) -> dict[str, VncAuthKvmdCredentials]:
@ -71,19 +68,19 @@ class VncAuthManager:
continue
if " -> " not in line:
raise VncAuthError(self.__path, lineno, self.gettext("Missing ' -> ' operator"))
raise VncAuthError(self.__path, lineno, "Missing ' -> ' operator")
(vnc_passwd, kvmd_userpass) = map(str.lstrip, line.split(" -> ", 1))
if ":" not in kvmd_userpass:
raise VncAuthError(self.__path, lineno, self.gettext("Missing ':' operator in KVMD credentials (right part)"))
raise VncAuthError(self.__path, lineno, "Missing ':' operator in KVMD credentials (right part)")
(kvmd_user, kvmd_passwd) = kvmd_userpass.split(":")
kvmd_user = kvmd_user.strip()
if len(kvmd_user) == 0:
raise VncAuthError(self.__path, lineno, self.gettext("Empty KVMD user (right part)"))
raise VncAuthError(self.__path, lineno, "Empty KVMD user (right part)")
if vnc_passwd in credentials:
raise VncAuthError(self.__path, lineno, self.gettext("Duplicating VNC password (left part)"))
raise VncAuthError(self.__path, lineno, "Duplicating VNC password (left part)")
credentials[vnc_passwd] = VncAuthKvmdCredentials(kvmd_user, kvmd_passwd)
return credentials

View File

@ -28,7 +28,7 @@ from typing import AsyncGenerator
import aiohttp
import aiohttp.multipart
from .languages import Languages
from .lanuages import Lanuages
from . import __version__
@ -60,7 +60,7 @@ def get_filename(response: aiohttp.ClientResponse) -> str:
try:
return os.path.basename(response.url.path)
except Exception:
raise aiohttp.ClientError(Languages().gettext("Can't determine filename"))
raise aiohttp.ClientError(Lanuages().gettext("Can't determine filename"))
@contextlib.asynccontextmanager

View File

@ -52,7 +52,7 @@ from .errors import IsBusyError
from .validators import ValidatorError
from .languages import Languages
from .lanuages import Lanuages
from . import aiotools
@ -282,7 +282,7 @@ class HttpServer:
self.__ws_bin_handlers: dict[int, Callable] = {}
self.__ws_sessions: list[WsSession] = []
self.__ws_sessions_lock = asyncio.Lock()
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def run(
self,

Binary file not shown.

View File

@ -7,8 +7,8 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-08-14 22:40+0800\n"
"PO-Revision-Date: 2024-08-14 22:40+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 <LL@li.org>\n"
@ -90,34 +90,37 @@ msgstr "因收到忽略标识而取消监视 %s"
msgid "Can't find any UDC"
msgstr "未找到任何 UDC"
#: kvmd/apps/__init__.py:164
msgid "INFO"
msgstr "消息"
#: kvmd/apps/__init__.py:132
msgid "Set config file path"
msgstr "设置配置文件路径"
#: kvmd/apps/__init__.py:134
msgid "Override config options list (like sec/sub/opt=value)"
msgstr "覆盖配置文件选项列表(如 sec/sub/opt=value"
#: kvmd/apps/__init__.py:136
msgid "View current configuration (include all overrides)"
msgstr "查看当前配置(包括所有覆盖配置文件)"
#: kvmd/apps/__init__.py:139
msgid "Run the service"
msgstr "启动此服务"
#: kvmd/apps/__init__.py:165
msgid "WARNING"
msgstr "警告"
#: kvmd/apps/__init__.py:166
msgid "ERROR"
msgstr "错误"
#: kvmd/apps/__init__.py:176
msgid ""
"To prevent accidental startup, you must specify the --run option to "
"start.\n"
msgstr "为了防止意外启动,必须在启动时指定 --run 选项。\n"
#: kvmd/apps/__init__.py:176
#: kvmd/apps/__init__.py:165
msgid "Try the --help option to find out what this service does.\n"
msgstr "尝试使用 --help 选项来了解某项服务的功能。\n"
#: kvmd/apps/__init__.py:176
#: kvmd/apps/__init__.py:165
msgid "Make sure you understand exactly what you are doing!"
msgstr "请确定你自己在做什么!"
#: kvmd/apps/kvmd/__init__.py:115 kvmd/apps/otgnet/__init__.py:132
#: kvmd/apps/vnc/server.py:541
msgid "Bye-bye"
msgstr "再见"
@ -169,48 +172,6 @@ msgstr "无法生成新的唯一令牌"
msgid "Logged out user %r (%d)"
msgstr "已注销用户 %r (%d)"
#: kvmd/apps/kvmd/server.py:89
msgid "This streamer does not support quality settings"
msgstr "该 streamer 不支持质量设置"
#: kvmd/apps/kvmd/server.py:94
msgid "This streamer does not support resolution settings"
msgstr "该 streamer 不支持分辨率设置"
#: kvmd/apps/kvmd/server.py:99
msgid "This streamer does not support H264"
msgstr "该 streamer 不支持 H264 设置"
#: kvmd/apps/kvmd/server.py:298
msgid "Waiting short tasks ..."
msgstr "正在等待短时任务结束......"
#: kvmd/apps/kvmd/server.py:300
msgid "Stopping system tasks ..."
msgstr "正在停止系统任务 ......"
#: kvmd/apps/kvmd/server.py:302
msgid "Disconnecting clients ..."
msgstr "断开客户端连接 ......"
#: kvmd/apps/kvmd/server.py:304
msgid "On-Shutdown complete"
msgstr "全部服务关闭完成"
#: kvmd/apps/kvmd/server.py:310
#, python-format
msgid "Cleaning up %s ..."
msgstr "正在清理 %s ......"
#: kvmd/apps/kvmd/server.py:314
#, python-format
msgid "Cleanup error on %s"
msgstr "在 %s 上发生清理错误"
#: kvmd/apps/kvmd/server.py:315
msgid "On-Cleanup complete"
msgstr "全部清理完毕"
#: kvmd/apps/kvmd/streamer.py:245
msgid "Streamer stop cancelled"
msgstr "Streamer 停止已取消"
@ -414,115 +375,6 @@ msgstr "使用 OTG gadget %r ......"
msgid "Using OTG Ethernet interface %r ..."
msgstr "使用 OTG 以太网接口 %r ......"
#: kvmd/apps/vnc/server.py:163
#, python-format
msgid "%s [kvmd]: Waiting for the SetEncodings message ..."
msgstr "%s [kvmd] 等待 SetEncodings 信息 ......"
#: kvmd/apps/vnc/server.py:165
msgid "No SetEncodings message recieved from the client in 5 secs"
msgstr "5 秒内未收到客户端的 SetEncodings 信息"
#: kvmd/apps/vnc/server.py:169
#, python-format
msgid "%s [kvmd]: Applying HID params: mouse_output=%s ..."
msgstr "%s [kvmd] 应用 HID 参数mouse_output=%s ......"
#: kvmd/apps/vnc/server.py:177
msgid "KVMD closed the websocket (the server may have been stopped)"
msgstr "KVMD 关闭了 websocket服务器可能已停止运行"
#: kvmd/apps/vnc/server.py:211
#, python-format
msgid "%s [streamer]: Streaming ..."
msgstr "%s [streamer]:获取视频流中 ......"
#: kvmd/apps/vnc/server.py:216
msgid "No signal"
msgstr "无信号"
#: kvmd/apps/vnc/server.py:220
#, python-format
msgid "%s [streamer]: Permanent error: %s; switching to %s ..."
msgstr "%s [streamer] 持续错误: %s; 切换到 %s ......"
#: kvmd/apps/vnc/server.py:222
#, python-format
msgid "%s [streamer]: Waiting for stream: %s"
msgstr "%s [streamer] 正在等待数据流:%s"
#: kvmd/apps/vnc/server.py:223
msgid "Waiting for stream ..."
msgstr "正在启动 streamer ......"
#: kvmd/apps/vnc/server.py:234
#, python-format
msgid "%s [streamer]: Using preferred %s"
msgstr "%s [streamer] 使用首选 %s"
#: kvmd/apps/vnc/server.py:240
#, python-format
msgid "%s [streamer]: Using default %s"
msgstr "%s [streamer] 使用默认 %s"
#: kvmd/apps/vnc/server.py:305
msgid "The client doesn't want to accept H264 anymore"
msgstr "客户端不接受 H264 视频"
#: kvmd/apps/vnc/server.py:311
msgid "format"
msgstr "格式"
#: kvmd/apps/vnc/server.py:417
#, python-format
msgid "%s [main]: Applying streamer params: jpeg_quality=%s; desired_fps=%d ..."
msgstr "%s [main] 应用流媒体参数: jpeg_quality=%s; desired_fps=%d ..."
#: kvmd/apps/vnc/server.py:467
#, python-format
msgid "%s [entry]: Connection is closed in an emergency"
msgstr "%s [entry] 连接因紧急情况关闭"
#: kvmd/apps/vnc/server.py:472
#, python-format
msgid "%s [entry]: Connected client"
msgstr "%s [entry] 已连接客户端"
#: kvmd/apps/vnc/server.py:491
#, python-format
msgid "%s [entry]: Can't check KVMD auth mode: %s"
msgstr "%s [entry] 无法检查 KVMD 身份验证模式: %s"
#: kvmd/apps/vnc/server.py:513
#, python-format
msgid "%s [entry]: Unhandled exception in client task"
msgstr "%s [entry] 客户端任务中出现无法处理的异常"
#: kvmd/apps/vnc/server.py:523
#, python-format
msgid "Listening VNC on TCP [%s]:%d ..."
msgstr "正在监听 TCP [%s]:%d 上的 VNC 服务 ......"
#: kvmd/apps/vnc/vncauth.py:63
msgid "Unhandled exception while reading VNCAuth passwd file"
msgstr "读取 VNCAuth 密码文件时出现无法处理的异常"
#: kvmd/apps/vnc/vncauth.py:74
msgid "Missing ' -> ' operator"
msgstr "缺少\"->\"运算符"
#: kvmd/apps/vnc/vncauth.py:78
msgid "Missing ':' operator in KVMD credentials (right part)"
msgstr "KVMD 证书中缺少\": \"运算符(右侧部分)"
#: kvmd/apps/vnc/vncauth.py:83
msgid "Empty KVMD user (right part)"
msgstr "空的 KVMD 用户(右侧部分)"
#: kvmd/apps/vnc/vncauth.py:86
msgid "Duplicating VNC password (left part)"
msgstr "复制 VNC 密码(左侧部分)"
#: kvmd/keyboard/keysym.py:69
#, python-format
msgid "Invalid modifier key at mapping %s: %s / %s"
@ -816,15 +668,3 @@ msgstr "无法执行重新挂载辅助程序"
msgid "Failed ANELPWR POST request to pin %s: %s"
msgstr "向引脚 %s 发送 ANELPWR POST 请求失败:%s"
#~ msgid "Set config file path"
#~ msgstr "设置配置文件路径"
#~ msgid "Override config options list (like sec/sub/opt=value)"
#~ msgstr "覆盖配置文件选项列表(如 sec/sub/opt=value"
#~ msgid "View current configuration (include all overrides)"
#~ msgstr "查看当前配置(包括所有覆盖配置文件)"
#~ msgid "Run the service"
#~ msgstr "启动此服务"

View File

@ -34,7 +34,7 @@ from typing import Generator
from .logging import get_logger
from .languages import Languages
from .lanuages import Lanuages
from . import aiotools
from . import libc
@ -196,7 +196,7 @@ class Inotify:
for path in paths:
path = os.path.normpath(path)
assert path not in self.__wd_by_path, path
get_logger().info(Languages().gettext("Watching for %s"), path)
get_logger().info(Lanuages().gettext("Watching for %s"), path)
# Асинхронно, чтобы не висло на NFS
wd = _inotify_check(await aiotools.run_async(libc.inotify_add_watch, self.__fd, _fs_encode(path), mask))
self.__wd_by_path[path] = wd
@ -255,7 +255,7 @@ class Inotify:
if event.mask & InotifyMask.IGNORED:
ignored_path = self.__path_by_wd[event.wd]
if self.__wd_by_path[ignored_path] == event.wd:
logger.info(Languages().gettext("Unwatching %s because IGNORED was received"), ignored_path)
logger.info(Lanuages().gettext("Unwatching %s because IGNORED was received"), ignored_path)
del self.__wd_by_path[ignored_path]
continue

View File

@ -27,7 +27,7 @@ import importlib.machinery
import Xlib.keysymdef
from ..languages import Languages
from ..lanuages import Lanuages
from ..logging import get_logger
@ -66,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(Languages().gettext("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 = (
@ -119,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(Languages().gettext("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")))

View File

@ -1,18 +0,0 @@
from gettext import translation
class Languages:
use_ttranslation = None
languages = "default"
@classmethod
def gettext(cls, string: str) -> str:
if cls.languages == "default" or cls.languages == "en" :
return string
else:
return cls.use_ttranslation(string)
@classmethod
def init(cls, domain:str, localedir: str, languages: str) -> None:
cls.languages = languages
cls.use_ttranslation = translation(domain=domain, localedir=localedir, languages=[cls.languages]).gettext

7
kvmd/lanuages.py Normal file
View File

@ -0,0 +1,7 @@
from gettext import translation
class Lanuages:
t = translation(domain="message",localedir="/kvmd/i18n",languages=["zh"]).gettext
def gettext(self,string: str) -> str:
return self.t(string)

View File

@ -25,7 +25,7 @@ from typing import AsyncGenerator
from ...errors import OperationError
from ...errors import IsBusyError
from ...languages import Languages
from ...lanuages import Lanuages
from .. import BasePlugin
from .. import get_plugin_class
@ -42,7 +42,7 @@ class AtxOperationError(OperationError, AtxError):
class AtxIsBusyError(IsBusyError, AtxError):
def __init__(self) -> None:
super().__init__(Languages().gettext("Performing another ATX operation, please try again later"))
super().__init__(Lanuages().gettext("Performing another ATX operation, please try again later"))
# =====

View File

@ -39,7 +39,7 @@ from ...validators.basic import valid_float_f01
from ...validators.os import valid_abs_path
from ...validators.hw import valid_gpio_pin
from ...languages import Languages
from ...lanuages import Lanuages
from . import AtxIsBusyError
from . import BaseAtx
@ -193,7 +193,7 @@ class Plugin(BaseAtx): # pylint: disable=too-many-instance-attributes
await self.__inner_click(name, pin, delay)
else:
await aiotools.run_region_task(
Languages().gettext(f"Can't perform ATX {name} click or operation was not completed"),
Lanuages().gettext(f"Can't perform ATX {name} click or operation was not completed"),
self.__region, self.__inner_click, name, pin, delay,
)
@ -206,4 +206,4 @@ class Plugin(BaseAtx): # pylint: disable=too-many-instance-attributes
finally:
self.__line_request.set_value(pin, gpiod.line.Value(False))
await asyncio.sleep(1)
get_logger(0).info(Languages().gettext("Clicked ATX button %r"), name)
get_logger(0).info(Lanuages().gettext("Clicked ATX button %r"), name)

View File

@ -32,7 +32,7 @@ from ...logging import get_logger
from ... import htclient
from ...languages import Languages
from ...lanuages import Lanuages
from . import BaseAuthService
@ -91,7 +91,7 @@ class Plugin(BaseAuthService):
htclient.raise_not_200(response)
return True
except Exception:
get_logger().exception(Languages().gettext("Failed HTTP auth request for user %r"), user)
get_logger().exception(Lanuages().gettext("Failed HTTP auth request for user %r"), user)
return False
async def cleanup(self) -> None:

View File

@ -33,7 +33,7 @@ from ...logging import get_logger
from ... import tools
from ... import aiotools
from ...languages import Languages
from ...lanuages import Lanuages
from . import BaseAuthService
@ -103,9 +103,9 @@ class Plugin(BaseAuthService):
except ldap.INVALID_CREDENTIALS:
pass
except ldap.SERVER_DOWN as err:
get_logger().error(Languages().gettext("LDAP server is down: %s"), tools.efmt(err))
get_logger().error(Lanuages().gettext("LDAP server is down: %s"), tools.efmt(err))
except Exception as err:
get_logger().error(Languages().gettext("Unexpected LDAP error: %s"), tools.efmt(err))
get_logger().error(Lanuages().gettext("Unexpected LDAP error: %s"), tools.efmt(err))
finally:
if conn is not None:
try:

View File

@ -34,7 +34,7 @@ from ...logging import get_logger
from ... import aiotools
from ...languages import Languages
from ...lanuages import Lanuages
from . import BaseAuthService
@ -88,13 +88,13 @@ class Plugin(BaseAuthService):
return False
else:
if uid < self.__allow_uids_at:
get_logger().error(Languages().gettext("Unallowed UID of user %r: uid=%d < allow_uids_at=%d"),
get_logger().error(Lanuages().gettext("Unallowed UID of user %r: uid=%d < allow_uids_at=%d"),
user, uid, self.__allow_uids_at)
return False
pam_obj = pam.pam()
if not pam_obj.authenticate(user, passwd, service=self.__service):
get_logger().error(Languages().gettext("Can't authorize user %r using PAM: code=%d; reason=%s"),
get_logger().error(Lanuages().gettext("Can't authorize user %r using PAM: code=%d; reason=%s"),
user, pam_obj.code, pam_obj.reason)
return False
return True

View File

@ -36,7 +36,7 @@ from ...logging import get_logger
from ... import aiotools
from ...languages import Languages
from ...lanuages import Lanuages
from . import BaseAuthService
@ -442,5 +442,5 @@ class Plugin(BaseAuthService):
response = client.SendPacket(request)
return (response.code == pyrad.packet.AccessAccept)
except Exception:
get_logger().exception(Languages().gettext("Failed RADIUS auth request for user %r"), user)
get_logger().exception(Lanuages().gettext("Failed RADIUS auth request for user %r"), user)
return False

View File

@ -46,7 +46,7 @@ from ....validators.basic import valid_float_f01
from ....validators.os import valid_abs_path
from ....validators.hw import valid_gpio_pin_optional
from ....languages import Languages
from ....lanuages import Lanuages
from .. import BaseHid
@ -146,7 +146,7 @@ class BaseMcuHid(BaseHid, multiprocessing.Process): # pylint: disable=too-many-
self.__stop_event = multiprocessing.Event()
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
@classmethod
def get_plugin_options(cls) -> dict:

View File

@ -27,7 +27,7 @@ import gpiod
from ....logging import get_logger
from ....languages import Languages
from ....lanuages import Lanuages
# =====
class Gpio: # pylint: disable=too-many-instance-attributes
@ -51,7 +51,7 @@ class Gpio: # pylint: disable=too-many-instance-attributes
self.__line_request: (gpiod.LineRequest | None) = None
self.__last_power: (bool | None) = None
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def __enter__(self) -> None:
if self.__power_detect_pin >= 0 or self.__reset_pin >= 0:

View File

@ -40,7 +40,7 @@ from .... import aiotools
from .... import aiomulti
from .... import aioproc
from ....languages import Languages
from ....lanuages import Lanuages
from .. import BaseHid
@ -109,7 +109,7 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
stop_event=self.__stop_event,
)
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
@classmethod
def get_plugin_options(cls) -> dict:

View File

@ -38,7 +38,7 @@ from .... import aiomulti
from ....keyboard.mappings import UsbKey
from ....languages import Languages
from ....lanuages import Lanuages
from ..otg.events import BaseEvent
from ..otg.events import ClearEvent
@ -117,7 +117,7 @@ class BtServer: # pylint: disable=too-many-instance-attributes
self.__keys: list[UsbKey | None] = [None] * 6
self.__mouse_buttons = 0
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def run(self) -> None:
with self.__iface:

View File

@ -41,7 +41,7 @@ from ....validators.basic import valid_float_f01
from ....validators.os import valid_abs_path
from ....validators.hw import valid_tty_speed
from ....languages import Languages
from ....lanuages import Lanuages
from .. import BaseHid
@ -84,7 +84,7 @@ class Plugin(BaseHid, multiprocessing.Process): # pylint: disable=too-many-inst
self.__keyboard = Keyboard()
self.__mouse = Mouse()
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
@classmethod
def get_plugin_options(cls) -> dict:

View File

@ -25,7 +25,7 @@ import contextlib
from typing import Generator
from ....languages import Languages
from ....lanuages import Lanuages
# =====
@ -37,7 +37,7 @@ class ChipResponseError(Exception):
class ChipConnection:
def __init__(self, tty: serial.Serial) -> None:
self.__tty = tty
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def xfer(self, cmd: bytes) -> int:
self.__send(cmd)

View File

@ -24,7 +24,7 @@ from typing import Iterable
from typing import AsyncGenerator
from typing import Any
from ....languages import Languages
from ....lanuages import Lanuages
from ....logging import get_logger
@ -120,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(Languages().gettext("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:

View File

@ -37,7 +37,7 @@ from .... import aiomulti
from .... import aioproc
from .... import usb
from ....languages import Languages
from ....lanuages import Lanuages
from .events import BaseEvent
@ -78,7 +78,7 @@ class BaseDeviceProcess(multiprocessing.Process): # pylint: disable=too-many-in
self.__logger: (logging.Logger | None) = None
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def start(self, udc: str) -> None: # type: ignore # pylint: disable=arguments-differ
self.__udc_state_path = usb.get_udc_path(udc, usb.U_STATE)

View File

@ -41,7 +41,7 @@ from .events import get_led_scroll
from .events import get_led_num
from .events import make_keyboard_report
from ....languages import Languages
from ....lanuages import Lanuages
# =====
class KeyboardProcess(BaseDeviceProcess):
@ -55,7 +55,7 @@ class KeyboardProcess(BaseDeviceProcess):
self.__pressed_modifiers: set[UsbKey] = set()
self.__pressed_keys: list[UsbKey | None] = [None] * 6
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def cleanup(self) -> None:
self._stop()

View File

@ -36,7 +36,7 @@ from .events import MouseRelativeEvent
from .events import MouseWheelEvent
from .events import make_mouse_report
from ....languages import Languages
from ....lanuages import Lanuages
# =====
class MouseProcess(BaseDeviceProcess):
@ -55,7 +55,7 @@ class MouseProcess(BaseDeviceProcess):
self.__x = 0 # For absolute
self.__y = 0
self.__win98_fix = False
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
def is_absolute(self) -> bool:
return self.__absolute

View File

@ -41,7 +41,7 @@ from ...validators.basic import valid_int_f1
from ...validators.basic import valid_float_f01
from ...validators.hw import valid_gpio_pin_optional
from ...languages import Lanuages
from ...lanuages import Lanuages
from ._mcu import BasePhyConnection
from ._mcu import BasePhy

View File

@ -40,7 +40,7 @@ from ... import aiotools
from .. import BasePlugin
from .. import get_plugin_class
from ...languages import Languages
from ...lanuages import Lanuages
# =====
class MsdError(Exception):
@ -53,43 +53,43 @@ class MsdOperationError(OperationError, MsdError):
class MsdIsBusyError(IsBusyError, MsdError):
def __init__(self) -> None:
gettext=Languages().gettext
gettext=Lanuages().gettext
super().__init__(gettext("Performing another MSD operation, please try again later"))
class MsdOfflineError(MsdOperationError):
def __init__(self) -> None:
gettext=Languages().gettext
gettext=Lanuages().gettext
super().__init__(gettext("MSD is not found"))
class MsdConnectedError(MsdOperationError):
def __init__(self) -> None:
gettext=Languages().gettext
gettext=Lanuages().gettext
super().__init__(gettext("MSD is connected to Server, but shouldn't for this operation"))
class MsdDisconnectedError(MsdOperationError):
def __init__(self) -> None:
gettext=Languages().gettext
gettext=Lanuages().gettext
super().__init__(gettext("MSD is disconnected from Server, but should be for this operation"))
class MsdImageNotSelected(MsdOperationError):
def __init__(self) -> None:
gettext=Languages().gettext
gettext=Lanuages().gettext
super().__init__(gettext("The image is not selected"))
class MsdUnknownImageError(MsdOperationError):
def __init__(self) -> None:
gettext=Languages().gettext
gettext=Lanuages().gettext
super().__init__(gettext("The image is not found in the storage"))
class MsdImageExistsError(MsdOperationError):
def __init__(self) -> None:
gettext=Languages().gettext
gettext=Lanuages().gettext
super().__init__(gettext("This image is already exists"))

View File

@ -31,7 +31,7 @@ from . import BaseMsdReader
from . import BaseMsdWriter
from . import BaseMsd
from ...languages import Languages
from ...lanuages import Lanuages
# =====
class MsdDisabledError(MsdOperationError):

View File

@ -29,7 +29,7 @@ import os
from typing import AsyncGenerator
from ....languages import Languages
from ....lanuages import Lanuages
from ....logging import get_logger
from ....inotify import InotifyMask
@ -45,7 +45,7 @@ from ....validators.kvm import valid_msd_image_name
from .... import aiotools
from .... import fstab
from ....languages import Languages
from ....lanuages import Lanuages
from .. import MsdIsBusyError
from .. import MsdOfflineError
@ -143,7 +143,7 @@ class Plugin(BaseMsd): # pylint: disable=too-many-instance-attributes
self.__notifier = aiotools.AioNotifier()
self.__state = _State(self.__notifier)
self.gettext=Languages().gettext
self.gettext=Lanuages().gettext
logger = get_logger(0)
logger.info(self.gettext("Using OTG gadget %r as MSD"), gadget)

View File

@ -27,13 +27,13 @@ from .... import usb
from .. import MsdOperationError
from ....languages import Languages
from ....lanuages import Lanuages
# =====
class MsdDriveLockedError(MsdOperationError):
def __init__(self) -> None:
super().__init__(Languages().gettext("MSD drive is locked on IO operation"))
super().__init__(Lanuages().gettext("MSD drive is locked on IO operation"))
# =====

View File

@ -31,7 +31,7 @@ from typing import Optional
import aiofiles
import aiofiles.os
from ....languages import Languages
from ....lanuages import Lanuages
from .... import aiotools
from .... import aiohelpers
@ -294,4 +294,4 @@ class Storage(_StorageDc):
async def remount_rw(self, rw: bool, fatal: bool=True) -> None:
if not (await aiohelpers.remount("MSD", self.__remount_cmd, rw)):
if fatal:
raise MsdError(Languages().gettext("Can't execute remount helper"))
raise MsdError(Lanuages().gettext("Can't execute remount helper"))

View File

@ -41,7 +41,7 @@ from ...validators.basic import valid_bool
from ...validators.basic import valid_number
from ...validators.basic import valid_float_f01
from ...languages import Languages
from ...lanuages import Lanuages
from . import BaseUserGpioDriver
from . import GpioDriverOfflineError
@ -149,7 +149,7 @@ class Plugin(BaseUserGpioDriver): # pylint: disable=too-many-instance-attribute
htclient.raise_not_200(response)
except Exception as err:
get_logger().error(Languages().gettext("Failed ANELPWR POST request to pin %s: %s"), pin, tools.efmt(err))
get_logger().error(Lanuages().gettext("Failed ANELPWR POST request to pin %s: %s"), pin, tools.efmt(err))
raise GpioDriverOfflineError(self)
self.__update_notifier.notify()

View File

@ -22,7 +22,7 @@
import os
from .languages import Languages
from .lanuages import Lanuages
from . import env
@ -33,10 +33,10 @@ def find_udc(udc: str) -> str:
candidates = sorted(os.listdir(path))
if not udc:
if len(candidates) == 0:
raise RuntimeError(Languages().gettext("Can't find any UDC"))
raise RuntimeError(Lanuages().gettext("Can't find any UDC"))
udc = candidates[0]
elif udc not in candidates:
raise RuntimeError(Languages().gettext(f"Can't find selected UDC: {udc}"))
raise RuntimeError(Lanuages().gettext(f"Can't find selected UDC: {udc}"))
return udc # fe980000.usb

View File

@ -1,34 +0,0 @@
# ========================================================================== #
# #
# KVMD - The main PiKVM daemon. #
# #
# Copyright (C) 2018-2024 Maxim Devaev <mdevaev@gmail.com> #
# #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
# #
# ========================================================================== #
from typing import Any
from . import check_string_in_list
from .basic import valid_number
# =====
def valid_languages(arg: Any) -> str:
return check_string_in_list(arg, "Languages", ["zh", "en", "default"])

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PROJECT VERSION\n"
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n"
"POT-Creation-Date: 2024-08-14 22:40+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 <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -89,34 +89,37 @@ msgstr ""
msgid "Can't find any UDC"
msgstr ""
#: kvmd/apps/__init__.py:164
msgid "INFO"
#: kvmd/apps/__init__.py:132
msgid "Set config file path"
msgstr ""
#: kvmd/apps/__init__.py:134
msgid "Override config options list (like sec/sub/opt=value)"
msgstr ""
#: kvmd/apps/__init__.py:136
msgid "View current configuration (include all overrides)"
msgstr ""
#: kvmd/apps/__init__.py:139
msgid "Run the service"
msgstr ""
#: kvmd/apps/__init__.py:165
msgid "WARNING"
msgstr ""
#: kvmd/apps/__init__.py:166
msgid "ERROR"
msgstr ""
#: kvmd/apps/__init__.py:176
msgid ""
"To prevent accidental startup, you must specify the --run option to "
"start.\n"
msgstr ""
#: kvmd/apps/__init__.py:176
#: kvmd/apps/__init__.py:165
msgid "Try the --help option to find out what this service does.\n"
msgstr ""
#: kvmd/apps/__init__.py:176
#: kvmd/apps/__init__.py:165
msgid "Make sure you understand exactly what you are doing!"
msgstr ""
#: kvmd/apps/kvmd/__init__.py:115 kvmd/apps/otgnet/__init__.py:132
#: kvmd/apps/vnc/server.py:541
msgid "Bye-bye"
msgstr ""
@ -168,48 +171,6 @@ msgstr ""
msgid "Logged out user %r (%d)"
msgstr ""
#: kvmd/apps/kvmd/server.py:89
msgid "This streamer does not support quality settings"
msgstr ""
#: kvmd/apps/kvmd/server.py:94
msgid "This streamer does not support resolution settings"
msgstr ""
#: kvmd/apps/kvmd/server.py:99
msgid "This streamer does not support H264"
msgstr ""
#: kvmd/apps/kvmd/server.py:298
msgid "Waiting short tasks ..."
msgstr ""
#: kvmd/apps/kvmd/server.py:300
msgid "Stopping system tasks ..."
msgstr ""
#: kvmd/apps/kvmd/server.py:302
msgid "Disconnecting clients ..."
msgstr ""
#: kvmd/apps/kvmd/server.py:304
msgid "On-Shutdown complete"
msgstr ""
#: kvmd/apps/kvmd/server.py:310
#, python-format
msgid "Cleaning up %s ..."
msgstr ""
#: kvmd/apps/kvmd/server.py:314
#, python-format
msgid "Cleanup error on %s"
msgstr ""
#: kvmd/apps/kvmd/server.py:315
msgid "On-Cleanup complete"
msgstr ""
#: kvmd/apps/kvmd/streamer.py:245
msgid "Streamer stop cancelled"
msgstr ""
@ -413,115 +374,6 @@ msgstr ""
msgid "Using OTG Ethernet interface %r ..."
msgstr ""
#: kvmd/apps/vnc/server.py:163
#, python-format
msgid "%s [kvmd]: Waiting for the SetEncodings message ..."
msgstr ""
#: kvmd/apps/vnc/server.py:165
msgid "No SetEncodings message recieved from the client in 5 secs"
msgstr ""
#: kvmd/apps/vnc/server.py:169
#, python-format
msgid "%s [kvmd]: Applying HID params: mouse_output=%s ..."
msgstr ""
#: kvmd/apps/vnc/server.py:177
msgid "KVMD closed the websocket (the server may have been stopped)"
msgstr ""
#: kvmd/apps/vnc/server.py:211
#, python-format
msgid "%s [streamer]: Streaming ..."
msgstr ""
#: kvmd/apps/vnc/server.py:216
msgid "No signal"
msgstr ""
#: kvmd/apps/vnc/server.py:220
#, python-format
msgid "%s [streamer]: Permanent error: %s; switching to %s ..."
msgstr ""
#: kvmd/apps/vnc/server.py:222
#, python-format
msgid "%s [streamer]: Waiting for stream: %s"
msgstr ""
#: kvmd/apps/vnc/server.py:223
msgid "Waiting for stream ..."
msgstr ""
#: kvmd/apps/vnc/server.py:234
#, python-format
msgid "%s [streamer]: Using preferred %s"
msgstr ""
#: kvmd/apps/vnc/server.py:240
#, python-format
msgid "%s [streamer]: Using default %s"
msgstr ""
#: kvmd/apps/vnc/server.py:305
msgid "The client doesn't want to accept H264 anymore"
msgstr ""
#: kvmd/apps/vnc/server.py:311
msgid "format"
msgstr ""
#: kvmd/apps/vnc/server.py:417
#, python-format
msgid "%s [main]: Applying streamer params: jpeg_quality=%s; desired_fps=%d ..."
msgstr ""
#: kvmd/apps/vnc/server.py:467
#, python-format
msgid "%s [entry]: Connection is closed in an emergency"
msgstr ""
#: kvmd/apps/vnc/server.py:472
#, python-format
msgid "%s [entry]: Connected client"
msgstr ""
#: kvmd/apps/vnc/server.py:491
#, python-format
msgid "%s [entry]: Can't check KVMD auth mode: %s"
msgstr ""
#: kvmd/apps/vnc/server.py:513
#, python-format
msgid "%s [entry]: Unhandled exception in client task"
msgstr ""
#: kvmd/apps/vnc/server.py:523
#, python-format
msgid "Listening VNC on TCP [%s]:%d ..."
msgstr ""
#: kvmd/apps/vnc/vncauth.py:63
msgid "Unhandled exception while reading VNCAuth passwd file"
msgstr ""
#: kvmd/apps/vnc/vncauth.py:74
msgid "Missing ' -> ' operator"
msgstr ""
#: kvmd/apps/vnc/vncauth.py:78
msgid "Missing ':' operator in KVMD credentials (right part)"
msgstr ""
#: kvmd/apps/vnc/vncauth.py:83
msgid "Empty KVMD user (right part)"
msgstr ""
#: kvmd/apps/vnc/vncauth.py:86
msgid "Duplicating VNC password (left part)"
msgstr ""
#: kvmd/keyboard/keysym.py:69
#, python-format
msgid "Invalid modifier key at mapping %s: %s / %s"

View File

@ -65,7 +65,3 @@ nginx:
janus:
cmd:
- "/bin/true"
languages:
console: zh
web: zh