mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2025-12-12 01:00:29 +08:00
进一步的 kvmd 国际化(汉化)支持
This commit is contained in:
parent
0af0e2b4d0
commit
5b25b3661f
@ -22,6 +22,8 @@
|
|||||||
|
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
||||||
|
from .lanuages import Lanuages
|
||||||
|
|
||||||
from .logging import get_logger
|
from .logging import get_logger
|
||||||
|
|
||||||
from . import tools
|
from . import tools
|
||||||
@ -36,13 +38,13 @@ async def remount(name: str, base_cmd: list[str], rw: bool) -> bool:
|
|||||||
part.format(mode=mode)
|
part.format(mode=mode)
|
||||||
for part in base_cmd
|
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:
|
try:
|
||||||
proc = await aioproc.log_process(cmd, logger)
|
proc = await aioproc.log_process(cmd, logger)
|
||||||
if proc.returncode != 0:
|
if proc.returncode != 0:
|
||||||
assert proc.returncode is not None
|
assert proc.returncode is not None
|
||||||
raise subprocess.CalledProcessError(proc.returncode, cmd)
|
raise subprocess.CalledProcessError(proc.returncode, cmd)
|
||||||
except Exception as err:
|
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 False
|
||||||
return True
|
return True
|
||||||
|
|||||||
@ -26,6 +26,7 @@ import asyncio
|
|||||||
import asyncio.subprocess
|
import asyncio.subprocess
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
from .lanuages import Lanuages
|
||||||
import setproctitle
|
import setproctitle
|
||||||
|
|
||||||
from .logging import get_logger
|
from .logging import get_logger
|
||||||
@ -85,7 +86,7 @@ async def log_stdout_infinite(proc: asyncio.subprocess.Process, logger: logging.
|
|||||||
else:
|
else:
|
||||||
empty += 1
|
empty += 1
|
||||||
if empty == 100: # asyncio bug
|
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
|
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:
|
if proc.returncode is not None:
|
||||||
raise
|
raise
|
||||||
await proc.wait()
|
await proc.wait()
|
||||||
logger.info("Process killed: retcode=%d", proc.returncode)
|
logger.info(Lanuages().gettext("Process killed: retcode=%d"), proc.returncode)
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
if proc.returncode is None:
|
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:
|
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:
|
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:
|
def settle(name: str, suffix: str, prefix: str="kvmd") -> logging.Logger:
|
||||||
logger = get_logger(1)
|
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()
|
os.setpgrp()
|
||||||
rename_process(suffix, prefix)
|
rename_process(suffix, prefix)
|
||||||
return logger
|
return logger
|
||||||
|
|||||||
@ -34,6 +34,8 @@ import aiohttp
|
|||||||
|
|
||||||
from PIL import Image as PilImage
|
from PIL import Image as PilImage
|
||||||
|
|
||||||
|
from ...lanuages import Lanuages
|
||||||
|
|
||||||
from ...logging import get_logger
|
from ...logging import get_logger
|
||||||
|
|
||||||
from ... import tools
|
from ... import tools
|
||||||
@ -226,6 +228,9 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
self.__notifier = aiotools.AioNotifier()
|
self.__notifier = aiotools.AioNotifier()
|
||||||
|
|
||||||
|
self.gettext=Lanuages().gettext
|
||||||
|
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
|
|
||||||
@aiotools.atomic_fg
|
@aiotools.atomic_fg
|
||||||
@ -237,15 +242,15 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
if not self.__stop_wip:
|
if not self.__stop_wip:
|
||||||
self.__stop_task.cancel()
|
self.__stop_task.cancel()
|
||||||
await asyncio.gather(self.__stop_task, return_exceptions=True)
|
await asyncio.gather(self.__stop_task, return_exceptions=True)
|
||||||
logger.info("Streamer stop cancelled")
|
logger.info(self.gettext("Streamer stop cancelled"))
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
await asyncio.gather(self.__stop_task, return_exceptions=True)
|
await asyncio.gather(self.__stop_task, return_exceptions=True)
|
||||||
|
|
||||||
if reset and self.__reset_delay > 0:
|
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)
|
await asyncio.sleep(self.__reset_delay)
|
||||||
logger.info("Starting streamer ...")
|
logger.info(self.gettext("Starting streamer ..."))
|
||||||
await self.__inner_start()
|
await self.__inner_start()
|
||||||
|
|
||||||
@aiotools.atomic_fg
|
@aiotools.atomic_fg
|
||||||
@ -258,12 +263,12 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
if not self.__stop_wip:
|
if not self.__stop_wip:
|
||||||
self.__stop_task.cancel()
|
self.__stop_task.cancel()
|
||||||
await asyncio.gather(self.__stop_task, return_exceptions=True)
|
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()
|
await self.__inner_stop()
|
||||||
else:
|
else:
|
||||||
await asyncio.gather(self.__stop_task, return_exceptions=True)
|
await asyncio.gather(self.__stop_task, return_exceptions=True)
|
||||||
else:
|
else:
|
||||||
logger.info("Stopping streamer immediately ...")
|
logger.info(self.gettext("Stopping streamer immediately ..."))
|
||||||
await self.__inner_stop()
|
await self.__inner_stop()
|
||||||
|
|
||||||
elif not self.__stop_task:
|
elif not self.__stop_task:
|
||||||
@ -272,13 +277,13 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
try:
|
try:
|
||||||
await asyncio.sleep(self.__shutdown_delay)
|
await asyncio.sleep(self.__shutdown_delay)
|
||||||
self.__stop_wip = True
|
self.__stop_wip = True
|
||||||
logger.info("Stopping streamer after delay ...")
|
logger.info(self.gettext("Stopping streamer after delay ..."))
|
||||||
await self.__inner_stop()
|
await self.__inner_stop()
|
||||||
finally:
|
finally:
|
||||||
self.__stop_task = None
|
self.__stop_task = None
|
||||||
self.__stop_wip = False
|
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())
|
self.__stop_task = asyncio.create_task(delayed_stop())
|
||||||
|
|
||||||
def is_working(self) -> bool:
|
def is_working(self) -> bool:
|
||||||
@ -307,7 +312,7 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
except (aiohttp.ClientConnectionError, aiohttp.ServerConnectionError):
|
except (aiohttp.ClientConnectionError, aiohttp.ServerConnectionError):
|
||||||
pass
|
pass
|
||||||
except Exception:
|
except Exception:
|
||||||
get_logger().exception("Invalid streamer response from /state")
|
get_logger().exception(self.gettext("Invalid streamer response from /state"))
|
||||||
|
|
||||||
snapshot: (dict | None) = None
|
snapshot: (dict | None) = None
|
||||||
if self.__snapshot:
|
if self.__snapshot:
|
||||||
@ -325,10 +330,10 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
async def poll_state(self) -> AsyncGenerator[dict, None]:
|
async def poll_state(self) -> AsyncGenerator[dict, None]:
|
||||||
def signal_handler(*_: Any) -> 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()
|
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)
|
asyncio.get_event_loop().add_signal_handler(signal.SIGUSR2, signal_handler)
|
||||||
|
|
||||||
waiter_task: (asyncio.Task | None) = None
|
waiter_task: (asyncio.Task | None) = None
|
||||||
@ -384,12 +389,12 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
self.__snapshot = snapshot
|
self.__snapshot = snapshot
|
||||||
self.__notifier.notify()
|
self.__notifier.notify()
|
||||||
return snapshot
|
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:
|
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:
|
except Exception:
|
||||||
logger.exception("Invalid streamer response from /snapshot")
|
logger.exception(self.gettext("Invalid streamer response from /snapshot"))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def remove_snapshot(self) -> None:
|
def remove_snapshot(self) -> None:
|
||||||
@ -446,14 +451,14 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
await self.__start_streamer_proc()
|
await self.__start_streamer_proc()
|
||||||
assert self.__streamer_proc is not None
|
assert self.__streamer_proc is not None
|
||||||
await aioproc.log_stdout_infinite(self.__streamer_proc, logger)
|
await aioproc.log_stdout_infinite(self.__streamer_proc, logger)
|
||||||
raise RuntimeError("Streamer unexpectedly died")
|
raise RuntimeError(self.gettext("Streamer unexpectedly died"))
|
||||||
except asyncio.CancelledError:
|
except asyncio.CancelledError:
|
||||||
break
|
break
|
||||||
except Exception:
|
except Exception:
|
||||||
if self.__streamer_proc:
|
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:
|
else:
|
||||||
logger.exception("Can't start streamer")
|
logger.exception(self.gettext("Can't start streamer"))
|
||||||
await self.__kill_streamer_proc()
|
await self.__kill_streamer_proc()
|
||||||
await asyncio.sleep(1)
|
await asyncio.sleep(1)
|
||||||
|
|
||||||
@ -474,13 +479,13 @@ class Streamer: # pylint: disable=too-many-instance-attributes
|
|||||||
try:
|
try:
|
||||||
await aioproc.log_process(cmd, logger, prefix=name)
|
await aioproc.log_process(cmd, logger, prefix=name)
|
||||||
except Exception as err:
|
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:
|
async def __start_streamer_proc(self) -> None:
|
||||||
assert self.__streamer_proc is None
|
assert self.__streamer_proc is None
|
||||||
cmd = self.__make_cmd(self.__cmd)
|
cmd = self.__make_cmd(self.__cmd)
|
||||||
self.__streamer_proc = await aioproc.run_process(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:
|
async def __kill_streamer_proc(self) -> None:
|
||||||
if self.__streamer_proc:
|
if self.__streamer_proc:
|
||||||
|
|||||||
@ -26,6 +26,8 @@ from typing import AsyncGenerator
|
|||||||
from typing import Callable
|
from typing import Callable
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from ...lanuages import Lanuages
|
||||||
|
|
||||||
from ...logging import get_logger
|
from ...logging import get_logger
|
||||||
|
|
||||||
from ...errors import IsBusyError
|
from ...errors import IsBusyError
|
||||||
@ -46,22 +48,22 @@ from ...yamlconf import Section
|
|||||||
# =====
|
# =====
|
||||||
class GpioChannelNotFoundError(GpioOperationError):
|
class GpioChannelNotFoundError(GpioOperationError):
|
||||||
def __init__(self) -> None:
|
def __init__(self) -> None:
|
||||||
super().__init__("GPIO channel is not found")
|
super().__init__(Lanuages().gettext("GPIO channel is not found"))
|
||||||
|
|
||||||
|
|
||||||
class GpioSwitchNotSupported(GpioOperationError):
|
class GpioSwitchNotSupported(GpioOperationError):
|
||||||
def __init__(self) -> None:
|
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):
|
class GpioPulseNotSupported(GpioOperationError):
|
||||||
def __init__(self) -> None:
|
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):
|
class GpioChannelIsBusyError(IsBusyError, GpioError):
|
||||||
def __init__(self) -> None:
|
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 = driver
|
||||||
self.__driver.register_input(self.__pin, config.debounce)
|
self.__driver.register_input(self.__pin, config.debounce)
|
||||||
|
|
||||||
|
self.gettext=Lanuages().gettext
|
||||||
|
|
||||||
def get_scheme(self) -> dict:
|
def get_scheme(self) -> dict:
|
||||||
return {
|
return {
|
||||||
"hw": {
|
"hw": {
|
||||||
@ -188,7 +192,7 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes
|
|||||||
await func(*args)
|
await func(*args)
|
||||||
else:
|
else:
|
||||||
await aiotools.run_region_task(
|
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,
|
self.__region, self.__action_task_wrapper, name, func, *args,
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -197,12 +201,12 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes
|
|||||||
try:
|
try:
|
||||||
return (await func(*args))
|
return (await func(*args))
|
||||||
except GpioDriverOfflineError:
|
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
|
@aiotools.atomic_fg
|
||||||
async def __inner_switch(self, state: bool) -> None:
|
async def __inner_switch(self, state: bool) -> None:
|
||||||
await self.__write(state)
|
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)
|
await asyncio.sleep(self.__busy_delay)
|
||||||
|
|
||||||
@aiotools.atomic_fg
|
@aiotools.atomic_fg
|
||||||
@ -213,7 +217,7 @@ class _GpioOutput: # pylint: disable=too-many-instance-attributes
|
|||||||
finally:
|
finally:
|
||||||
await self.__write(False)
|
await self.__write(False)
|
||||||
await asyncio.sleep(self.__busy_delay)
|
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))
|
await self.__driver.write(self.__pin, (state ^ self.__inverted))
|
||||||
|
|
||||||
def __str__(self) -> str:
|
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__
|
__repr__ = __str__
|
||||||
|
|
||||||
@ -249,6 +253,8 @@ class UserGpio:
|
|||||||
self.__inputs: dict[str, _GpioInput] = {}
|
self.__inputs: dict[str, _GpioInput] = {}
|
||||||
self.__outputs: dict[str, _GpioOutput] = {}
|
self.__outputs: dict[str, _GpioOutput] = {}
|
||||||
|
|
||||||
|
self.gettext=Lanuages().gettext
|
||||||
|
|
||||||
for (channel, ch_config) in tools.sorted_kvs(config.scheme):
|
for (channel, ch_config) in tools.sorted_kvs(config.scheme):
|
||||||
driver = self.__drivers[ch_config.driver]
|
driver = self.__drivers[ch_config.driver]
|
||||||
if ch_config.mode == UserGpioModes.INPUT:
|
if ch_config.mode == UserGpioModes.INPUT:
|
||||||
@ -289,12 +295,12 @@ class UserGpio:
|
|||||||
await self.__notifier.wait()
|
await self.__notifier.wait()
|
||||||
|
|
||||||
def sysprep(self) -> None:
|
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):
|
for (_, driver) in tools.sorted_kvs(self.__drivers):
|
||||||
driver.prepare()
|
driver.prepare()
|
||||||
|
|
||||||
async def systask(self) -> None:
|
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(*[
|
await asyncio.gather(*[
|
||||||
driver.run()
|
driver.run()
|
||||||
for (_, driver) in tools.sorted_kvs(self.__drivers)
|
for (_, driver) in tools.sorted_kvs(self.__drivers)
|
||||||
@ -305,7 +311,7 @@ class UserGpio:
|
|||||||
try:
|
try:
|
||||||
await driver.cleanup()
|
await driver.cleanup()
|
||||||
except Exception:
|
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:
|
async def switch(self, channel: str, state: bool, wait: bool) -> None:
|
||||||
gout = self.__outputs.get(channel)
|
gout = self.__outputs.get(channel)
|
||||||
|
|||||||
@ -27,7 +27,9 @@ import json
|
|||||||
import time
|
import time
|
||||||
import argparse
|
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
|
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
|
# https://www.isticktoit.net/?p=1383
|
||||||
|
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
|
gettext=Lanuages().gettext
|
||||||
|
|
||||||
_check_config(config)
|
_check_config(config)
|
||||||
|
|
||||||
udc = usb.find_udc(config.otg.udc)
|
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)
|
gadget_path = usb.get_gadget_path(config.otg.gadget)
|
||||||
_mkdir(gadget_path)
|
_mkdir(gadget_path)
|
||||||
|
|
||||||
@ -248,39 +251,39 @@ def _cmd_start(config: Section) -> None: # pylint: disable=too-many-statements,
|
|||||||
cod = config.otg.devices
|
cod = config.otg.devices
|
||||||
|
|
||||||
if cod.serial.enabled:
|
if cod.serial.enabled:
|
||||||
logger.info("===== Serial =====")
|
logger.info(gettext("===== Serial ====="))
|
||||||
gc.add_serial(cod.serial.start)
|
gc.add_serial(cod.serial.start)
|
||||||
|
|
||||||
if cod.ethernet.enabled:
|
if cod.ethernet.enabled:
|
||||||
logger.info("===== Ethernet =====")
|
logger.info(gettext("===== Ethernet ====="))
|
||||||
gc.add_ethernet(**cod.ethernet._unpack(ignore=["enabled"]))
|
gc.add_ethernet(**cod.ethernet._unpack(ignore=["enabled"]))
|
||||||
|
|
||||||
if config.kvmd.hid.type == "otg":
|
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)
|
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)
|
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:
|
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)
|
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":
|
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())
|
gc.add_msd(cod.msd.start, config.otg.user, **cod.msd.default._unpack())
|
||||||
if cod.drives.enabled:
|
if cod.drives.enabled:
|
||||||
for count in range(cod.drives.count):
|
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())
|
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)
|
_write(join(gadget_path, "UDC"), udc)
|
||||||
time.sleep(config.otg.init_delay)
|
time.sleep(config.otg.init_delay)
|
||||||
_chown(join(gadget_path, "UDC"), config.otg.user)
|
_chown(join(gadget_path, "UDC"), config.otg.user)
|
||||||
_chown(profile_path, 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)
|
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")
|
_write(join(gadget_path, "UDC"), "\n")
|
||||||
|
|
||||||
_unlink(join(gadget_path, "os_desc", usb.G_PROFILE_NAME), optional=True)
|
_unlink(join(gadget_path, "os_desc", usb.G_PROFILE_NAME), optional=True)
|
||||||
|
|||||||
@ -26,6 +26,8 @@ import dataclasses
|
|||||||
import itertools
|
import itertools
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
|
from ...lanuages import Lanuages
|
||||||
|
|
||||||
from ...logging import get_logger
|
from ...logging import get_logger
|
||||||
|
|
||||||
from ...yamlconf import Section
|
from ...yamlconf import Section
|
||||||
@ -87,6 +89,8 @@ class _Service: # pylint: disable=too-many-instance-attributes
|
|||||||
self.__gadget: str = config.otg.gadget
|
self.__gadget: str = config.otg.gadget
|
||||||
self.__driver: str = config.otg.devices.ethernet.driver
|
self.__driver: str = config.otg.devices.ethernet.driver
|
||||||
|
|
||||||
|
self.gettext=Lanuages().gettext
|
||||||
|
|
||||||
def start(self) -> None:
|
def start(self) -> None:
|
||||||
asyncio.run(self.__run(True))
|
asyncio.run(self.__run(True))
|
||||||
|
|
||||||
@ -121,20 +125,20 @@ class _Service: # pylint: disable=too-many-instance-attributes
|
|||||||
for ctl in ctls:
|
for ctl in ctls:
|
||||||
if not (await self.__run_ctl(ctl, True)):
|
if not (await self.__run_ctl(ctl, True)):
|
||||||
raise SystemExit(1)
|
raise SystemExit(1)
|
||||||
get_logger(0).info("Ready to work")
|
get_logger(0).info(self.gettext("Ready to work"))
|
||||||
else:
|
else:
|
||||||
for ctl in reversed(ctls):
|
for ctl in reversed(ctls):
|
||||||
await self.__run_ctl(ctl, False)
|
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:
|
async def __run_ctl(self, ctl: BaseCtl, direct: bool) -> bool:
|
||||||
logger = get_logger()
|
logger = get_logger()
|
||||||
cmd = ctl.get_command(direct)
|
cmd = ctl.get_command(direct)
|
||||||
logger.info("CMD: %s", tools.cmdfmt(cmd))
|
logger.info(self.gettext("CMD: %s"), tools.cmdfmt(cmd))
|
||||||
try:
|
try:
|
||||||
return (not (await aioproc.log_process(cmd, logger)).returncode)
|
return (not (await aioproc.log_process(cmd, logger)).returncode)
|
||||||
except Exception as err:
|
except Exception as err:
|
||||||
logger.exception("Can't execute command: %s", err)
|
logger.exception(self.gettext("Can't execute command: %s"), err)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# =====
|
# =====
|
||||||
@ -143,10 +147,10 @@ class _Service: # pylint: disable=too-many-instance-attributes
|
|||||||
iface = self.__find_iface()
|
iface = self.__find_iface()
|
||||||
logger = get_logger()
|
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)
|
net = ipaddress.IPv4Network(self.__iface_net)
|
||||||
if net.prefixlen > 31:
|
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:
|
if net.prefixlen == 31:
|
||||||
iface_ip = str(net[0])
|
iface_ip = str(net[0])
|
||||||
@ -166,7 +170,7 @@ class _Service: # pylint: disable=too-many-instance-attributes
|
|||||||
dhcp_ip_end=dhcp_ip_end,
|
dhcp_ip_end=dhcp_ip_end,
|
||||||
dhcp_option_3=(f"3,{iface_ip}" if self.__forward_iface else "3"),
|
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
|
return netcfg
|
||||||
|
|
||||||
def __find_iface(self) -> str:
|
def __find_iface(self) -> str:
|
||||||
@ -175,10 +179,10 @@ class _Service: # pylint: disable=too-many-instance-attributes
|
|||||||
if self.__driver == "rndis5":
|
if self.__driver == "rndis5":
|
||||||
real_driver = "rndis"
|
real_driver = "rndis"
|
||||||
path = usb.get_gadget_path(self.__gadget, usb.G_FUNCTIONS, f"{real_driver}.usb0/ifname")
|
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:
|
with open(path) as file:
|
||||||
iface = file.read().strip()
|
iface = file.read().strip()
|
||||||
logger.info("Using OTG Ethernet interface %r ...", iface)
|
logger.info(self.gettext("Using OTG Ethernet interface %r ..."), iface)
|
||||||
assert iface
|
assert iface
|
||||||
return iface
|
return iface
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@ -7,8 +7,8 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\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: 2024-08-06 21:57+0800\n"
|
"PO-Revision-Date: 2024-08-12 22:07+0800\n"
|
||||||
"Last-Translator: \n"
|
"Last-Translator: \n"
|
||||||
"Language: zh\n"
|
"Language: zh\n"
|
||||||
"Language-Team: zh <LL@li.org>\n"
|
"Language-Team: zh <LL@li.org>\n"
|
||||||
@ -18,6 +18,35 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.15.0\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
|
#: kvmd/htclient.py:63
|
||||||
msgid "Can't determine filename"
|
msgid "Can't determine filename"
|
||||||
msgstr "无法确定文件名"
|
msgstr "无法确定文件名"
|
||||||
@ -91,58 +120,271 @@ msgstr "尝试使用 --help 选项来了解某项服务的功能。\n"
|
|||||||
msgid "Make sure you understand exactly what you are doing!"
|
msgid "Make sure you understand exactly what you are doing!"
|
||||||
msgstr "请确定你自己在做什么!"
|
msgstr "请确定你自己在做什么!"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/__init__.py:115
|
#: kvmd/apps/kvmd/__init__.py:115 kvmd/apps/otgnet/__init__.py:132
|
||||||
msgid "Bye-bye"
|
msgid "Bye-bye"
|
||||||
msgstr "再见"
|
msgstr "再见"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:57
|
#: kvmd/apps/kvmd/auth.py:58
|
||||||
msgid "AUTHORIZATION IS DISABLED"
|
msgid "AUTHORIZATION IS DISABLED"
|
||||||
msgstr "身份验证服务已被禁用"
|
msgstr "身份验证服务已被禁用"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:61
|
#: kvmd/apps/kvmd/auth.py:62
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Authorization is disabled for API %r"
|
msgid "Authorization is disabled for API %r"
|
||||||
msgstr "由于 API %r 身份验证服务已被禁用"
|
msgstr "由于 API %r 身份验证服务已被禁用"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:66
|
#: kvmd/apps/kvmd/auth.py:67
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Using internal auth service %r"
|
msgid "Using internal auth service %r"
|
||||||
msgstr "使用内部身份验证服务 %r"
|
msgstr "使用内部身份验证服务 %r"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:73
|
#: kvmd/apps/kvmd/auth.py:74
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Using external auth service %r"
|
msgid "Using external auth service %r"
|
||||||
msgstr "使用外部身份验证服务 %r"
|
msgstr "使用外部身份验证服务 %r"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:101
|
#: kvmd/apps/kvmd/auth.py:103
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Got access denied for user %r by TOTP"
|
msgid "Got access denied for user %r by TOTP"
|
||||||
msgstr "用户 %r 被 TOTP 拒绝访问"
|
msgstr "用户 %r 被 TOTP 拒绝访问"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:112
|
#: kvmd/apps/kvmd/auth.py:114
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Authorized user %r via auth service %r"
|
msgid "Authorized user %r via auth service %r"
|
||||||
msgstr "用户 %r 已通过身份认证服务 %r 授权"
|
msgstr "用户 %r 已通过身份认证服务 %r 授权"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:114
|
#: kvmd/apps/kvmd/auth.py:116
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Got access denied for user %r from auth service %r"
|
msgid "Got access denied for user %r from auth service %r"
|
||||||
msgstr "身份验证服务 %r 拒绝了用户 %r 的访问请求"
|
msgstr "身份验证服务 %r 拒绝了用户 %r 的访问请求"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:124
|
#: kvmd/apps/kvmd/auth.py:126
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Logged in user %r"
|
msgid "Logged in user %r"
|
||||||
msgstr "已登录用户 %r"
|
msgstr "已登录用户 %r"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:134
|
#: kvmd/apps/kvmd/auth.py:136
|
||||||
msgid "Can't generate new unique token"
|
msgid "Can't generate new unique token"
|
||||||
msgstr "无法生成新的唯一令牌"
|
msgstr "无法生成新的唯一令牌"
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:145
|
#: kvmd/apps/kvmd/auth.py:147
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Logged out user %r (%d)"
|
msgid "Logged out user %r (%d)"
|
||||||
msgstr "已注销用户 %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
|
#: kvmd/plugins/atx/__init__.py:45
|
||||||
msgid "Performing another ATX operation, please try again later"
|
msgid "Performing another ATX operation, please try again later"
|
||||||
msgstr "正在处理另一个 ATX 动作,请稍等"
|
msgstr "正在处理另一个 ATX 动作,请稍等"
|
||||||
@ -188,7 +430,7 @@ msgstr "正在启动 HID 守护程序......"
|
|||||||
|
|
||||||
#: kvmd/plugins/hid/bt/__init__.py:182 kvmd/plugins/hid/ch9329/__init__.py:141
|
#: kvmd/plugins/hid/bt/__init__.py:182 kvmd/plugins/hid/ch9329/__init__.py:141
|
||||||
msgid "Stopping HID daemon ..."
|
msgid "Stopping HID daemon ..."
|
||||||
msgstr "正在启停止 HID 守护程序......"
|
msgstr "正在停止 HID 守护程序......"
|
||||||
|
|
||||||
#: kvmd/plugins/hid/bt/__init__.py:231
|
#: kvmd/plugins/hid/bt/__init__.py:231
|
||||||
msgid "Unexpected HID error"
|
msgid "Unexpected HID error"
|
||||||
@ -197,7 +439,7 @@ msgstr "未知 HID 错误"
|
|||||||
#: kvmd/plugins/hid/bt/server.py:153
|
#: kvmd/plugins/hid/bt/server.py:153
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Listening [%s]:%d for %s ..."
|
msgid "Listening [%s]:%d for %s ..."
|
||||||
msgstr "监听 [%s]:%d for %s ..."
|
msgstr "监听 [%s]:%d for %s ......"
|
||||||
|
|
||||||
#: kvmd/plugins/hid/bt/server.py:190
|
#: kvmd/plugins/hid/bt/server.py:190
|
||||||
#, python-format
|
#, python-format
|
||||||
|
|||||||
@ -27,6 +27,8 @@ import importlib.machinery
|
|||||||
|
|
||||||
import Xlib.keysymdef
|
import Xlib.keysymdef
|
||||||
|
|
||||||
|
from ..lanuages import Lanuages
|
||||||
|
|
||||||
from ..logging import get_logger
|
from ..logging import get_logger
|
||||||
|
|
||||||
from .mappings import At1Key
|
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.ALTS and key.altgr)
|
||||||
or (web_name in WebModifiers.CTRLS and key.ctrl)
|
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
|
continue
|
||||||
|
|
||||||
modifiers = (
|
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)
|
def _read_keyboard_layout(path: str) -> dict[int, list[At1Key]]: # Keysym to evdev (at1)
|
||||||
logger = get_logger(0)
|
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:
|
with open(path) as file:
|
||||||
lines = list(map(str.strip, file.read().split("\n")))
|
lines = list(map(str.strip, file.read().split("\n")))
|
||||||
|
|||||||
@ -24,6 +24,8 @@ from typing import Iterable
|
|||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
|
from ....lanuages import Lanuages
|
||||||
|
|
||||||
from ....logging import get_logger
|
from ....logging import get_logger
|
||||||
|
|
||||||
from .... import aiomulti
|
from .... import aiomulti
|
||||||
@ -118,7 +120,7 @@ class Plugin(BaseHid): # pylint: disable=too-many-instance-attributes
|
|||||||
|
|
||||||
def sysprep(self) -> None:
|
def sysprep(self) -> None:
|
||||||
udc = usb.find_udc(self.__udc)
|
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.__keyboard_proc.start(udc)
|
||||||
self.__mouse_proc.start(udc)
|
self.__mouse_proc.start(udc)
|
||||||
if self.__mouse_alt_proc:
|
if self.__mouse_alt_proc:
|
||||||
|
|||||||
266
message.pot
266
message.pot
@ -8,7 +8,7 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PROJECT VERSION\n"
|
"Project-Id-Version: PROJECT VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\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"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
@ -17,6 +17,35 @@ msgstr ""
|
|||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"Generated-By: Babel 2.15.0\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
|
#: kvmd/htclient.py:63
|
||||||
msgid "Can't determine filename"
|
msgid "Can't determine filename"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
@ -90,58 +119,271 @@ msgstr ""
|
|||||||
msgid "Make sure you understand exactly what you are doing!"
|
msgid "Make sure you understand exactly what you are doing!"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/__init__.py:115
|
#: kvmd/apps/kvmd/__init__.py:115 kvmd/apps/otgnet/__init__.py:132
|
||||||
msgid "Bye-bye"
|
msgid "Bye-bye"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:57
|
#: kvmd/apps/kvmd/auth.py:58
|
||||||
msgid "AUTHORIZATION IS DISABLED"
|
msgid "AUTHORIZATION IS DISABLED"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:61
|
#: kvmd/apps/kvmd/auth.py:62
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Authorization is disabled for API %r"
|
msgid "Authorization is disabled for API %r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:66
|
#: kvmd/apps/kvmd/auth.py:67
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Using internal auth service %r"
|
msgid "Using internal auth service %r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:73
|
#: kvmd/apps/kvmd/auth.py:74
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Using external auth service %r"
|
msgid "Using external auth service %r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:101
|
#: kvmd/apps/kvmd/auth.py:103
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Got access denied for user %r by TOTP"
|
msgid "Got access denied for user %r by TOTP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:112
|
#: kvmd/apps/kvmd/auth.py:114
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Authorized user %r via auth service %r"
|
msgid "Authorized user %r via auth service %r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:114
|
#: kvmd/apps/kvmd/auth.py:116
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Got access denied for user %r from auth service %r"
|
msgid "Got access denied for user %r from auth service %r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:124
|
#: kvmd/apps/kvmd/auth.py:126
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Logged in user %r"
|
msgid "Logged in user %r"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:134
|
#: kvmd/apps/kvmd/auth.py:136
|
||||||
msgid "Can't generate new unique token"
|
msgid "Can't generate new unique token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: kvmd/apps/kvmd/auth.py:145
|
#: kvmd/apps/kvmd/auth.py:147
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Logged out user %r (%d)"
|
msgid "Logged out user %r (%d)"
|
||||||
msgstr ""
|
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
|
#: kvmd/plugins/atx/__init__.py:45
|
||||||
msgid "Performing another ATX operation, please try again later"
|
msgid "Performing another ATX operation, please try again later"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user