diff --git a/.github/workflows/ci/workflow_generate.py b/.github/workflows/ci/workflow_generate.py index 248e12376..a1b646d9c 100755 --- a/.github/workflows/ci/workflow_generate.py +++ b/.github/workflows/ci/workflow_generate.py @@ -11,7 +11,7 @@ class GithubActionsYamlLoader(yaml.SafeLoader): @staticmethod def _unsupported(kind, token): return SyntaxError( - "Github Actions does not support %s:\n%s" % (kind, token.start_mark) + f"Github Actions does not support {kind}:\n{token.start_mark}" ) def fetch_alias(self): @@ -41,13 +41,13 @@ def fetch_anchor(self): for j in context["jobs"]: base_type = j["type"].split("_")[0] - j["id"] = "%s_%s" % ( + j["id"] = "{}_{}".format( base_type, j["variant"].lower().replace(" ", "_").replace(".", ""), ) - j["name"] = "%s (%s)" % (base_type.capitalize(), j["variant"]) + j["name"] = "{} ({})".format(base_type.capitalize(), j["variant"]) j["needs"] = j.get("needs", []) - j["reqs"] = ["reqs/%s.txt" % r for r in j["reqs"]] + j["reqs"] = [f"reqs/{r}.txt" for r in j["reqs"]] j["cache_extra_deps"] = j.get("cache_extra_deps", []) if "python" not in j: j["python"] = context["default_python"] @@ -65,7 +65,7 @@ def fetch_anchor(self): v = "(" + " ".join(map(shlex.quote, v)) + ")" else: v = shlex.quote(v) - shell_definition.append("job_%s=%s" % (k, v)) + shell_definition.append(f"job_{k}={v}") j["shell_definition"] = "; ".join(shell_definition) # Render template. diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 49d188f09..2716380b5 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.14.8 # also update constraints.txt + rev: v0.16.0 # also update constraints.txt hooks: # Run the linter. - id: ruff-check diff --git a/doc/conf.py b/doc/conf.py index a2b3be8de..bd3b2c745 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -1,6 +1,8 @@ # Configuration file for the Sphinx documentation builder. -from pygments.lexer import RegexLexer, bygroups +from typing import ClassVar + from pygments import token as t +from pygments.lexer import RegexLexer, bygroups from sphinx.highlighting import lexers # -- Project information ----------------------------------------------------- @@ -78,7 +80,7 @@ class RTFLexer(RegexLexer): name = "rtf" - tokens = { + tokens: ClassVar[dict] = { "root": [ (r"(\\[a-z*\\_~\{\}]+)(-?\d+)?", bygroups(t.Keyword, t.Number.Integer)), (r"{\\\*\\cxcomment\s+", t.Comment.Multiline, "comment"), diff --git a/doc/design.md b/doc/design.md index 4ae16ee8c..f19e4ef79 100644 --- a/doc/design.md +++ b/doc/design.md @@ -195,15 +195,16 @@ and providing a callback function: ```python class MyExtension: - def __init__(self, engine: plover.engine.StenoEngine): - self.engine = engine + def __init__(self, engine: plover.engine.StenoEngine): + self.engine = engine - def start(self): - # Connect to the "stroked" hook - self.engine.hook_connect("stroked", self._on_stroked) + def start(self): + # Connect to the "stroked" hook + self.engine.hook_connect("stroked", self._on_stroked) - def _on_stroked(self, stroke: plover.steno.Stroke): - ... # Gets called after each stroke + def _on_stroked( + self, stroke: plover.steno.Stroke + ): ... # Gets called after each stroke ``` Events that occur within the Plover engine, such as machine disconnections, diff --git a/doc/dict_formats.md b/doc/dict_formats.md index 741ccc60c..27a8543f5 100644 --- a/doc/dict_formats.md +++ b/doc/dict_formats.md @@ -121,18 +121,18 @@ LONGEST_KEY = 1 def lookup(outline): - assert len(outline) == 1 + assert len(outline) == 1 - stroke = outline[0] - if stroke == "KP-PL": - return "example" - else: - raise KeyError + stroke = outline[0] + if stroke == "KP-PL": + return "example" + else: + raise KeyError def reverse_lookup(translation): - if translation == "example": - return [("KP-PL",)] - else: - return [] + if translation == "example": + return [("KP-PL",)] + else: + return [] ``` diff --git a/doc/hardware_communication.md b/doc/hardware_communication.md index 08e772caa..8f474d0fa 100644 --- a/doc/hardware_communication.md +++ b/doc/hardware_communication.md @@ -32,18 +32,18 @@ should translate platform-specific events into calls to ```python class MyKeyboardCapture(Capture): - def start(self): - self._thread = threading.Thread(target=self._run) - self._thread.start() - - def _run(self): - while True: - key, pressed = ... # wait for key event - - if pressed: - self.key_down(key) - else: - self.key_up(key) + def start(self): + self._thread = threading.Thread(target=self._run) + self._thread.start() + + def _run(self): + while True: + key, pressed = ... # wait for key event + + if pressed: + self.key_down(key) + else: + self.key_up(key) ``` Plover's engine handles translating these calls into steno strokes, as well as @@ -57,14 +57,11 @@ specified, by translating them to platform-specific input calls. ```python class MyKeyboardEmulation(Output): - def send_backspaces(self, num): - ... + def send_backspaces(self, num): ... - def send_string(self, s): - ... + def send_string(self, s): ... - def send_key_combination(self, combo): - ... + def send_key_combination(self, combo): ... ``` ## Serial Protocols @@ -81,12 +78,11 @@ and implement a way to parse each packet. ```python class MySerialMachine(SerialStenotypeBase): - KEYS_LAYOUT = """ + KEYS_LAYOUT = """ ... """ - def run(self): - ... + def run(self): ... ``` ## USB-based Protocols diff --git a/doc/i18n.md b/doc/i18n.md index b052a03bc..d321b767a 100644 --- a/doc/i18n.md +++ b/doc/i18n.md @@ -85,7 +85,7 @@ available for sub-modules: ```python from plover.i18n import Translator -_ = Translator(__package__, resource_dir='messages') +_ = Translator(__package__, resource_dir="messages") ``` Note: don't forget to add `Babel` to your build dependencies (in `pyproject.toml`). diff --git a/doc/plugin-dev/commands.md b/doc/plugin-dev/commands.md index 58dca9b64..319a0ed25 100644 --- a/doc/plugin-dev/commands.md +++ b/doc/plugin-dev/commands.md @@ -26,8 +26,9 @@ argument. If an argument is not passed in the dictionary entry, it will be ```python # plover_my_plugin/command.py + def example(engine, argument): - pass + pass ``` Commands can access any of the properties and methods in the engine object @@ -35,7 +36,7 @@ passed to it, such as in [`plover_system_switcher`](https://github.com/nsmarkop/ ```python def switch_system(engine, system): - engine.config = {"system_name": system} + engine.config = {"system_name": system} ``` They can also interact with the rest of the Python environment, and even other @@ -43,5 +44,5 @@ programs, such as [`plover_vlc_commands`](https://github.com/benoit-pierre/plove ```python def stop(_, _): - _vlc_request("?command=pl_stop") + _vlc_request("?command=pl_stop") ``` diff --git a/doc/plugin-dev/dictionaries.md b/doc/plugin-dev/dictionaries.md index 4daa19b24..898efe6da 100644 --- a/doc/plugin-dev/dictionaries.md +++ b/doc/plugin-dev/dictionaries.md @@ -19,17 +19,17 @@ write your desired dictionary format. from plover.steno_dictionary import StenoDictionary -class ExampleDictionary(StenoDictionary): - readonly = False +class ExampleDictionary(StenoDictionary): + readonly = False - def _load(self, filename): - # If you are not maintaining your own state format, self.update is usually - # called here to add strokes / definitions to the dictionary state. - pass + def _load(self, filename): + # If you are not maintaining your own state format, self.update is usually + # called here to add strokes / definitions to the dictionary state. + pass - def _save(self, filename): - pass + def _save(self, filename): + pass ``` Note that setting `readonly` to `True` on your dictionary class will make @@ -39,18 +39,17 @@ For example, a simplified version of the JSON dictionary implementation: ```python class JsonDictionary(StenoDictionary): + def _load(self, filename): + with open(filename) as fp: + d = dict(json.load(fp)) - def _load(self, filename): - with open(filename) as fp: - d = dict(json.load(fp)) - - # Inserts the entries into the dictionary - self.update((normalize_steno(k), v) for k, v in d.items()) + # Inserts the entries into the dictionary + self.update((normalize_steno(k), v) for k, v in d.items()) - def _save(self, filename): - with open(filename, "w") as fp: - entries = [("/".join(k), v) for k, v in self.items()] - json.dump(entries, fp) + def _save(self, filename): + with open(filename, "w") as fp: + entries = [("/".join(k), v) for k, v in self.items()] + json.dump(entries, fp) ``` Some dictionary formats, such as Python dictionaries, may require implementing diff --git a/doc/plugin-dev/extensions.md b/doc/plugin-dev/extensions.md index 9bfd3ad16..d337a5866 100644 --- a/doc/plugin-dev/extensions.md +++ b/doc/plugin-dev/extensions.md @@ -12,19 +12,20 @@ plover.extension = ```python # plover_my_plugin/extension.py + class Extension: - def __init__(self, engine): - # Called once to initialize an instance which lives until Plover exits. - self.engine = engine - - def start(self): - # Called to start the extension or when the user enables the extension. - # It can be used to start a new thread for example. - pass - - def stop(self): - # Called when Plover exits or the user disables the extension. - pass + def __init__(self, engine): + # Called once to initialize an instance which lives until Plover exits. + self.engine = engine + + def start(self): + # Called to start the extension or when the user enables the extension. + # It can be used to start a new thread for example. + pass + + def stop(self): + # Called when Plover exits or the user disables the extension. + pass ``` Extensions can interact with the engine through the @@ -36,20 +37,20 @@ using the {js:func}`stroked` hook: ```python class StrokeLogger: - def __init__(self, engine): - self.engine = engine - self.output_file = None + def __init__(self, engine): + self.engine = engine + self.output_file = None - def start(self): - self.output_file = open("strokes.txt") + def start(self): + self.output_file = open("strokes.txt") - # self.on_stroked gets called on every stroke - self.engine.hook_connect("stroked", self.on_stroked) + # self.on_stroked gets called on every stroke + self.engine.hook_connect("stroked", self.on_stroked) - def stop(self): - self.engine.hook_connect("stroked", self.on_stroked) - self.output_file.close() + def stop(self): + self.engine.hook_connect("stroked", self.on_stroked) + self.output_file.close() - def on_stroked(self, stroke): - print(stroke, file=self.output_file) + def on_stroked(self, stroke): + print(stroke, file=self.output_file) ``` diff --git a/doc/plugin-dev/gui_tools.md b/doc/plugin-dev/gui_tools.md index 05339e622..f5cd6a77f 100644 --- a/doc/plugin-dev/gui_tools.md +++ b/doc/plugin-dev/gui_tools.md @@ -9,8 +9,8 @@ from plover_build_utils.setup import BuildPy, BuildUi BuildPy.build_dependencies.append("build_ui") CMDCLASS = { - "build_py": BuildPy, - "build_ui": BuildUi, + "build_py": BuildPy, + "build_ui": BuildUi, } setup(cmdclass=CMDCLASS) @@ -44,18 +44,19 @@ GUI tools are implemented as Qt widget **classes** inheriting from from plover.gui_qt.tool import Tool + # You will also want to import / inherit for your Python class generated by # your .ui file if you are using Qt Designer for creating your UI rather # than only from code class Main(Tool): - TITLE = 'Example Tool' - ICON = '' - ROLE = 'example_tool' - - def __init__(self, engine): - super().__init__(engine) - # If you are inheriting from your .ui generated class, also call - # self.setupUi(self) before any additional setup code + TITLE = "Example Tool" + ICON = "" + ROLE = "example_tool" + + def __init__(self, engine): + super().__init__(engine) + # If you are inheriting from your .ui generated class, also call + # self.setupUi(self) before any additional setup code ``` Keep in mind that when you need to make changes to the UI, you will need to @@ -72,13 +73,13 @@ provides Qt signals to be used as hooks. ```python class StrokeLogger(Tool, Ui_StrokeLogger): - def __init__(self, engine): - super().__init__(engine) - self.setupUi(self) + def __init__(self, engine): + super().__init__(engine) + self.setupUi(self) - # Instead of engine.hook_connect - engine.signal_connect("stroked", self.on_stroked) + # Instead of engine.hook_connect + engine.signal_connect("stroked", self.on_stroked) - def on_stroked(self, stroke): - pass + def on_stroked(self, stroke): + pass ``` diff --git a/doc/plugin-dev/machines.md b/doc/plugin-dev/machines.md index 19ea5c532..169235c5c 100644 --- a/doc/plugin-dev/machines.md +++ b/doc/plugin-dev/machines.md @@ -22,27 +22,28 @@ classes depending on your needs. from plover.machine.base import ThreadedStenotypeBase + class ExampleMachine(ThreadedStenotypeBase): - KEYS_LAYOUT: str = '0 1 2 3 4 5 6 7 8 9 10' + KEYS_LAYOUT: str = "0 1 2 3 4 5 6 7 8 9 10" - def __init__(self, params): - super().__init__() - self._params = params + def __init__(self, params): + super().__init__() + self._params = params - def run(self): - self._ready() - while not self.finished.wait(1): - self._notify(self.keymap.keys_to_actions(['1'])) + def run(self): + self._ready() + while not self.finished.wait(1): + self._notify(self.keymap.keys_to_actions(["1"])) - def start_capture(self): - super().start_capture() + def start_capture(self): + super().start_capture() - def stop_capture(self): - super().stop_capture() + def stop_capture(self): + super().stop_capture() - @classmethod - def get_option_info(cls): - pass + @classmethod + def get_option_info(cls): + pass ``` The `_notify` method should be called whenever a stroke is received. It takes @@ -80,9 +81,10 @@ Machine options plugins are implemented as Qt widget **classes**: from PyQt5.QtWidgets import QWidget + class ExampleMachineOption(QWidget): - def setValue(self, value): - pass + def setValue(self, value): + pass ``` The process for developing these is similar to that for [GUI tools](gui_tools). diff --git a/doc/plugin-dev/macros.md b/doc/plugin-dev/macros.md index 2c5adf015..148c4cc23 100644 --- a/doc/plugin-dev/macros.md +++ b/doc/plugin-dev/macros.md @@ -25,8 +25,9 @@ If an argument is not passed in the dictionary entry, it will be `''`. ```python # plover_my_plugin/macro.py + def example(translator, stroke, argument): - pass + pass ``` Various methods of the translator can be used to either access or undo diff --git a/doc/plugin-dev/metas.md b/doc/plugin-dev/metas.md index a17ce2ef2..1ff470651 100644 --- a/doc/plugin-dev/metas.md +++ b/doc/plugin-dev/metas.md @@ -31,8 +31,9 @@ as the basis for the output value. Previously translated text can also be access ```python # plover_my_plugin/meta.py + def example(ctx, argument): - pass + pass ``` % TODO: diff --git a/linux/appimage/pyinfo.py b/linux/appimage/pyinfo.py index a30a8a2fe..87c4fbe23 100644 --- a/linux/appimage/pyinfo.py +++ b/linux/appimage/pyinfo.py @@ -1,9 +1,9 @@ -from distutils import sysconfig import sys +from distutils import sysconfig print( "; ".join( - "py%s=%r" % (k, v) + f"py{k}={v!r}" for k, v in sorted( { "exe": sys.executable, diff --git a/osx/dmg_resources/settings.py b/osx/dmg_resources/settings.py index ce96e7b25..c4358a01f 100644 --- a/osx/dmg_resources/settings.py +++ b/osx/dmg_resources/settings.py @@ -1,7 +1,5 @@ -# -*- coding: utf-8 -*- - -import plistlib import os.path +import plistlib # `defines` is injected by dmgbuild; default to empty for linters. defines = globals().get("defines", {}) diff --git a/osx/find_non_universal_wheels.py b/osx/find_non_universal_wheels.py old mode 100644 new mode 100755 diff --git a/plover/__main__.py b/plover/__main__.py index 53a5b3fe4..c0fdc7806 100644 --- a/plover/__main__.py +++ b/plover/__main__.py @@ -1,5 +1,4 @@ from plover.scripts.main import main - if __name__ == "__main__": main() diff --git a/plover/command/set_config.py b/plover/command/set_config.py index e4e242e73..3f71789e1 100644 --- a/plover/command/set_config.py +++ b/plover/command/set_config.py @@ -29,7 +29,7 @@ def _cmdline_to_dict(cmdline): return opt_dict except (AssertionError, SyntaxError, ValueError) as e: raise ValueError( - 'Bad command string "%s" for PLOVER:SET_CONFIG.\n' % cmdline + f'Bad command string "{cmdline}" for PLOVER:SET_CONFIG.\n' + "See for reference:\n\n" + set_config.__doc__ ) from e diff --git a/plover/config.py b/plover/config.py index b01ef2ddd..1fdaf2ac7 100644 --- a/plover/config.py +++ b/plover/config.py @@ -4,20 +4,19 @@ """This modules handles reading and writing Plover's configuration files, as well as updating the configuration on-the-fly while Plover is running.""" -from collections import ChainMap, namedtuple, OrderedDict import configparser import json import re -from typing import Any, Dict +from collections import ChainMap, OrderedDict, namedtuple +from typing import Any, ClassVar +from plover import log from plover.exception import InvalidConfigurationError -from plover.formatting import SPACE_PLACEMENT_BEFORE, SPACE_PLACEMENT_AFTER +from plover.formatting import SPACE_PLACEMENT_AFTER, SPACE_PLACEMENT_BEFORE from plover.machine.keymap import Keymap +from plover.misc import boolean, expand_path, shorten_path from plover.registry import registry from plover.resource import resource_update -from plover.misc import boolean, expand_path, shorten_path -from plover import log - # General configuration sections, options and defaults. APPEARANCE_CONFIG_SECTION = "Appearance" @@ -55,7 +54,7 @@ def short_path(self) -> str: """The shortened path to the dictionary file. This is automatically calculated from :attr:`path`.""" return shorten_path(self.path) - def to_dict(self) -> Dict[str, Any]: + def to_dict(self) -> dict[str, Any]: """Returns the ``dict`` representation of the dictionary configuration.""" # Note: do not use _asdict because of # https://bugs.python.org/issue24931 @@ -69,12 +68,12 @@ def replace(self, **kwargs) -> "DictionaryConfig": return self._replace(**kwargs) @staticmethod - def from_dict(d: Dict[str, Any]) -> "DictionaryConfig": + def from_dict(d: dict[str, Any]) -> "DictionaryConfig": """Returns a :class:`DictionaryConfig` constructed from its ``dict`` representation.""" return DictionaryConfig(**d) def __repr__(self): - return "DictionaryConfig(%r, %r)" % (self.short_path, self.enabled) + return f"DictionaryConfig({self.short_path!r}, {self.enabled!r})" ConfigOption = namedtuple( @@ -128,7 +127,7 @@ def getter(config, key): def setter(config, key, value): if isinstance(value, set): # JSON does not support sets. - value = list(sorted(value)) + value = sorted(value) config._set( section, option, json.dumps(value, sort_keys=True, ensure_ascii=False) ) @@ -153,7 +152,9 @@ def validate(config, key, value): if (minimum is not None and value < minimum) or ( maximum is not None and value > maximum ): - message = "%s not in [%s, %s]" % (value, minimum or "-∞", maximum or "∞") + message = "{} not in [{}, {}]".format( + value, minimum or "-∞", maximum or "∞" + ) raise InvalidConfigOption(value, default, message) return value @@ -352,7 +353,7 @@ def legacy_getter(config): options = config._config[LEGACY_DICTIONARY_CONFIG_SECTION].items() return [ {"path": value} - for name, value in reversed(sorted(options)) + for name, value in sorted(options, reverse=True) if re.match(r"dictionary_file\d*$", name) is not None ] @@ -418,9 +419,11 @@ def clear(self) -> None: def save(self) -> None: """Writes the current state of the configuration to the configuration file.""" - with resource_update(self.path) as temp_path: - with open(temp_path, mode="w", encoding="utf-8") as fp: - self._config.write(fp) + with ( + resource_update(self.path) as temp_path, + open(temp_path, mode="w", encoding="utf-8") as fp, + ): + self._config.write(fp) def _set(self, section, option, value): if not self._config.has_section(section): @@ -430,7 +433,7 @@ def _set(self, section, option, value): # Note: order matters, e.g. machine_type comes before # machine_specific_options and system_keymap because # the latter depend on the former. - _OPTIONS = OrderedDict( + _OPTIONS: ClassVar[OrderedDict] = OrderedDict( (opt.name, opt) for opt in [ # Output. @@ -532,7 +535,7 @@ def __setitem__(self, key: str, value: Any) -> None: opt.setter(self, key, value) self._cache[key] = value - def as_dict(self) -> Dict[str, Any]: + def as_dict(self) -> dict[str, Any]: """Returns the ``dict`` representation of the current state of the configuration. """ diff --git a/plover/dictionary/base.py b/plover/dictionary/base.py index b0c4e090a..9654f3c9a 100644 --- a/plover/dictionary/base.py +++ b/plover/dictionary/base.py @@ -7,9 +7,9 @@ """Common elements to all dictionary formats.""" -from os.path import splitext import functools import threading +from os.path import splitext from plover.registry import registry @@ -20,8 +20,7 @@ def _get_dictionary_class(filename): dict_module = registry.get_plugin("dictionary", extension).obj except KeyError: raise ValueError( - "Unsupported extension: %s. Supported extensions: %s" - % ( + "Unsupported extension: {}. Supported extensions: {}".format( extension, ", ".join( plugin.name for plugin in registry.list_plugins("dictionary") diff --git a/plover/dictionary/json_dict.py b/plover/dictionary/json_dict.py index eb7d04fe3..e3a6abe49 100644 --- a/plover/dictionary/json_dict.py +++ b/plover/dictionary/json_dict.py @@ -9,8 +9,8 @@ import json from plover.dictionary.helpers import StenoNormalizer -from plover.steno_dictionary import StenoDictionary from plover.steno import steno_to_sort_key +from plover.steno_dictionary import StenoDictionary class JsonDictionary(StenoDictionary): @@ -25,7 +25,7 @@ def _load(self, filename): else: break else: - raise ValueError("'%s' encoding could not be determined" % (filename,)) + raise ValueError(f"'{filename}' encoding could not be determined") d = dict(json.loads(contents)) with StenoNormalizer(filename) as normalize_steno: self.update((normalize_steno(x[0]), x[1]) for x in d.items()) diff --git a/plover/dictionary/loading_manager.py b/plover/dictionary/loading_manager.py index e4984256d..b46d98c69 100644 --- a/plover/dictionary/loading_manager.py +++ b/plover/dictionary/loading_manager.py @@ -6,9 +6,9 @@ import threading import time +from plover import log from plover.dictionary.base import load_dictionary from plover.resource import resource_timestamp -from plover import log class DictionaryLoadingManager: diff --git a/plover/dictionary/rtfcre_dict.py b/plover/dictionary/rtfcre_dict.py index 65f0be010..797aefb96 100644 --- a/plover/dictionary/rtfcre_dict.py +++ b/plover/dictionary/rtfcre_dict.py @@ -23,12 +23,11 @@ from .rtfcre_parse import parse_rtfcre - HEADER = ( r"{\rtf1\ansi{\*\cxrev100}" - r"\cxdict{\*\cxsystem Plover %s}" + rf"\cxdict{{\*\cxsystem Plover {plover_version}}}" r"{\stylesheet{\s0 Normal;}}" -) % plover_version +) class RegexFormatter: @@ -148,6 +147,6 @@ def _save(self, filename): for s, t in self.items(): s = "/".join(s) t = translation_formatter.format(t) - entry = r"{\*\cxs %s}%s" % (s, t) + entry = rf"{{\*\cxs {s}}}{t}" print(entry, file=fp) print("}", file=fp) diff --git a/plover/dictionary/rtfcre_parse.py b/plover/dictionary/rtfcre_parse.py index cafc5b9f8..520052522 100644 --- a/plover/dictionary/rtfcre_parse.py +++ b/plover/dictionary/rtfcre_parse.py @@ -1,6 +1,6 @@ -from collections import deque -import sys import re +import sys +from collections import deque from rtf_tokenize import RtfTokenizer @@ -9,7 +9,7 @@ class RtfParseError(Exception): def __init__(self, lnum, cnum, fmt, *fmt_args): - msg = "line %u, column %u: %s" % (lnum + 1, cnum + 1, fmt % fmt_args) + msg = f"line {lnum + 1}, column {cnum + 1}: {fmt % fmt_args}" super().__init__(msg) @@ -311,7 +311,7 @@ def main(todo, filename): token = tokenizer.next_token() if token is None: break - print("%3u:%-3u %r" % (tokenizer.lnum + 1, tokenizer.cnum + 1, token)) + print(f"{tokenizer.lnum + 1:3}:{tokenizer.cnum + 1:<3} {token!r}") elif todo == "dump_parse": for mapping in parse_rtfcre(text): print(mapping) diff --git a/plover/engine.py b/plover/engine.py index f1159b171..a1fd096e7 100644 --- a/plover/engine.py +++ b/plover/engine.py @@ -3,21 +3,22 @@ and dictionaries. """ -from collections import namedtuple, OrderedDict -from functools import wraps -from queue import Queue import functools import os import shutil import threading -from typing import Any, Callable, Dict, List, Optional, Tuple +from collections import OrderedDict, namedtuple +from collections.abc import Callable +from functools import wraps +from queue import Queue +from typing import Any, ClassVar from plover import log, system from plover.dictionary.loading_manager import DictionaryLoadingManager from plover.formatting import ( - Formatter, - SPACE_PLACEMENT_BEFORE, SPACE_PLACEMENT_AFTER, + SPACE_PLACEMENT_BEFORE, + Formatter, ) from plover.misc import shorten_path from plover.registry import registry @@ -27,14 +28,13 @@ from plover.suggestions import Suggestions from plover.translation import Translator - StartingStrokeState = namedtuple( "StartingStrokeState", "attach capitalize space_char space_placement", defaults=(False, False, " ", None), ) -StartingStrokeState.__doc__ = """An object representing the starting state of the formatter before any +StartingStrokeState.__doc__ = f"""An object representing the starting state of the formatter before any strokes are input. Attributes: @@ -46,10 +46,7 @@ space_placement (Optional[str]): The space placement to use for this state. One of ``{SPACE_PLACEMENT_BEFORE}`` or ``{SPACE_PLACEMENT_AFTER}``. If ``None``, the current engine configuration is used. -""".format( - SPACE_PLACEMENT_BEFORE=SPACE_PLACEMENT_BEFORE, - SPACE_PLACEMENT_AFTER=SPACE_PLACEMENT_AFTER, -) +""" MachineParams = namedtuple("MachineParams", "type options keymap") @@ -152,24 +149,24 @@ class StenoEngine: """ - HOOKS: List[str] = """ - stroked - translated - machine_state_changed - output_changed - config_changed - dictionaries_loaded - dictionary_state_changed - send_string - send_backspaces - send_key_combination - add_translation - focus - configure - lookup - suggestions - quit - """.split() + HOOKS: ClassVar[list[str]] = [ + "stroked", + "translated", + "machine_state_changed", + "output_changed", + "config_changed", + "dictionaries_loaded", + "dictionary_state_changed", + "send_string", + "send_backspaces", + "send_key_combination", + "add_translation", + "focus", + "configure", + "lookup", + "suggestions", + "quit", + ] def __init__(self, config: Any, controller: Any, keyboard_emulation: Any): self._config = config @@ -372,14 +369,13 @@ def _load_dictionaries(self): ) dictionaries = [] for d in self._dictionaries_manager.load(config_dictionaries.keys()): - if isinstance(d, ErroredDictionary): - # Only show an error if it's new. - if d != self._dictionaries.get(d.path): - log.error( - "loading dictionary `%s` failed: %s", - shorten_path(d.path), - str(d.exception), - ) + # Only show an error if it's new. + if isinstance(d, ErroredDictionary) and d != self._dictionaries.get(d.path): + log.error( + "loading dictionary `%s` failed: %s", + shorten_path(d.path), + str(d.exception), + ) d.enabled = config_dictionaries[d.path].enabled dictionaries.append(d) self._set_dictionaries(dictionaries) @@ -551,7 +547,7 @@ def set_output(self, enabled: bool) -> None: @property @with_lock - def machine_state(self) -> Optional[str]: + def machine_state(self) -> str | None: """The connection state of the current machine. One of ``stopped``, ``initializing``, ``connected`` or ``disconnected``. @@ -570,7 +566,7 @@ def output(self, enabled): @property @with_lock - def config(self) -> Dict[str, Any]: + def config(self) -> dict[str, Any]: """A dictionary containing configuration options.""" return self._config.as_dict() @@ -640,26 +636,26 @@ def join(self) -> int: return self.code @with_lock - def lookup(self, translation: Tuple[str, ...]) -> str: + def lookup(self, translation: tuple[str, ...]) -> str: """Returns the first translation for the steno outline ``translation`` using all the filters. """ return self._dictionaries.lookup(translation) @with_lock - def raw_lookup(self, translation: Tuple[str, ...]) -> str: + def raw_lookup(self, translation: tuple[str, ...]) -> str: """Like :meth:`lookup`, but without any of the filters.""" return self._dictionaries.raw_lookup(translation) @with_lock - def lookup_from_all(self, translation: Tuple[str, ...]): + def lookup_from_all(self, translation: tuple[str, ...]): """Returns all translations for the steno outline ``translation`` using all the filters. """ return self._dictionaries.lookup_from_all(translation) @with_lock - def raw_lookup_from_all(self, translation: Tuple[str, ...]): + def raw_lookup_from_all(self, translation: tuple[str, ...]): """Like :meth:`lookup_from_all`, but without any of the filters.""" return self._dictionaries.raw_lookup_from_all(translation) @@ -675,7 +671,7 @@ def casereverse_lookup(self, translation: str): @with_lock def add_dictionary_filter( - self, dictionary_filter: Callable[[Tuple[str, ...], str], bool] + self, dictionary_filter: Callable[[tuple[str, ...], str], bool] ) -> None: """Adds ``dictionary_filter`` to the list of dictionary filters. @@ -686,7 +682,7 @@ def add_dictionary_filter( @with_lock def remove_dictionary_filter( - self, dictionary_filter: Callable[[Tuple[str, ...], str], bool] + self, dictionary_filter: Callable[[tuple[str, ...], str], bool] ) -> None: """Removes ``dictionary_filter`` from the list of dictionary filters.""" self._dictionaries.remove_filter(dictionary_filter) @@ -752,9 +748,9 @@ def starting_stroke_state(self, state): @with_lock def add_translation( self, - strokes: Tuple[str, ...], + strokes: tuple[str, ...], translation: str, - dictionary_path: Optional[str] = None, + dictionary_path: str | None = None, ) -> None: """Adds a steno entry mapping the steno outline ``strokes`` to ``translation`` in the dictionary at ``dictionary_path``, if specified, diff --git a/plover/exception.py b/plover/exception.py index 1aeb83623..d2e327bd0 100644 --- a/plover/exception.py +++ b/plover/exception.py @@ -11,5 +11,3 @@ class InvalidConfigurationError(Exception): "Raised when there is something wrong in the configuration." - - pass diff --git a/plover/formatting.py b/plover/formatting.py index 7f9ae825a..5eb2e49c9 100644 --- a/plover/formatting.py +++ b/plover/formatting.py @@ -7,27 +7,26 @@ """ -from enum import Enum -from os.path import commonprefix -from collections import namedtuple import re import string +from collections import namedtuple +from enum import Enum +from os.path import commonprefix from plover.registry import registry - Case = Enum( "case", ( (c, c.lower()) - for c in """ - CAP_FIRST_WORD - LOWER - LOWER_FIRST_CHAR - TITLE - UPPER - UPPER_FIRST_WORD - """.split() + for c in [ + "CAP_FIRST_WORD", + "LOWER", + "LOWER_FIRST_CHAR", + "TITLE", + "UPPER", + "UPPER_FIRST_WORD", + ] ), ) @@ -134,31 +133,15 @@ def parse(meta): ATOM_RE = re.compile( - r"""(?:%s%s|%s%s|[^%s%s])+ # One or more of anything - # other than unescaped { or } + rf"""(?:{RE_META_ESCAPE}{META_START}|{RE_META_ESCAPE}{META_END}|[^{META_START}{META_END}])+ # One or more of anything + # other than unescaped {{ or }} # | # or # - %s(?:%s%s|%s%s|[^%s%s])*%s # Anything of the form {X} + {META_START}(?:{RE_META_ESCAPE}{META_START}|{RE_META_ESCAPE}{META_END}|[^{META_START}{META_END}])*{META_END} # Anything of the form {{X}} # where X doesn't contain - # unescaped { or } - """ - % ( - RE_META_ESCAPE, - META_START, - RE_META_ESCAPE, - META_END, - META_START, - META_END, - META_START, - RE_META_ESCAPE, - META_START, - RE_META_ESCAPE, - META_END, - META_START, - META_END, - META_END, - ), + # unescaped {{ or }} + """, re.VERBOSE, ) @@ -751,11 +734,11 @@ def __ne__(self, other): def __str__(self): kwargs = [ - "%s=%r" % (k, v) + f"{k}={v!r}" for k, v in self.__dict__.items() if v != self.DEFAULT.__dict__[k] ] - return "Action(%s)" % ", ".join(sorted(kwargs)) + return "Action({})".format(", ".join(sorted(kwargs))) def __repr__(self): return str(self) @@ -783,7 +766,7 @@ def __getattr__(self, name): return getattr(self.action, name) def __str__(self): - return "LookAheadAction(%s)" % str(self.__dict__) + return f"LookAheadAction({self.__dict__!s})" def _translation_to_actions(translation, ctx): @@ -922,7 +905,7 @@ def apply_case(text, case): return lower_first_character(text) if case == Case.UPPER_FIRST_WORD: return upper_first_word(text) - raise ValueError("%r is not a valid case" % case) + raise ValueError(f"{case!r} is not a valid case") def apply_mode(text, case, space_char, begin, last_action): @@ -952,7 +935,7 @@ def apply_mode_case(text, case, appended): if appended: return text return capitalize_all_words(text) - raise ValueError("%r is not a valid case" % case) + raise ValueError(f"{case!r} is not a valid case") def apply_mode_space_char(text, space_char): diff --git a/plover/gui_none/engine.py b/plover/gui_none/engine.py index 5153b4939..b9f6aead4 100644 --- a/plover/gui_none/engine.py +++ b/plover/gui_none/engine.py @@ -1,7 +1,6 @@ from threading import Thread, current_thread from plover.engine import StenoEngine - from plover.gui_none.add_translation import AddTranslation diff --git a/plover/gui_none/main.py b/plover/gui_none/main.py index b562c2e77..6548b313b 100644 --- a/plover/gui_none/main.py +++ b/plover/gui_none/main.py @@ -1,12 +1,11 @@ from threading import Event -from plover.oslayer.keyboardcontrol import KeyboardEmulation - from plover.gui_none.engine import Engine +from plover.oslayer.keyboardcontrol import KeyboardEmulation def show_error(title, message): - print("%s: %s" % (title, message)) + print(f"{title}: {message}") def main(config, controller): diff --git a/plover/gui_qt/about_dialog.py b/plover/gui_qt/about_dialog.py index 4ce99b48a..8878e1185 100644 --- a/plover/gui_qt/about_dialog.py +++ b/plover/gui_qt/about_dialog.py @@ -3,7 +3,6 @@ from PySide6.QtWidgets import QDialog import plover - from plover.gui_qt.about_dialog_ui import Ui_AboutDialog @@ -19,28 +18,27 @@ def __init__(self, engine): self.text.setHtml( """ -

-

%(name)s %(version)s

-

%(description)s

-

Copyright %(copyright)s

-

License: %(license)s

-

Project Homepage: %(url)s

+

+

{name} {version}

+

{description}

+

Copyright {copyright}

+

License: {license}

+

Project Homepage: {url}

Credits:

-

%(credits)s

- """ - % { - "icon": ":/resources/plover.png", - "name": plover.__name__.capitalize(), - "version": plover.__version__, - "description": plover.__long_description__, - "copyright": plover.__copyright__.replace("(C)", "©"), - "license": plover.__license__, - "license_url": "https://www.gnu.org/licenses/gpl-2.0-standalone.html", - "url": plover.__download_url__, - "credits": credits, - } +

{credits}

+ """.format( + icon=":/resources/plover.png", + name=plover.__name__.capitalize(), + version=plover.__version__, + description=plover.__long_description__, + copyright=plover.__copyright__.replace("(C)", "©"), + license=plover.__license__, + license_url="https://www.gnu.org/licenses/gpl-2.0-standalone.html", + url=plover.__download_url__, + credits=credits, + ) ) diff --git a/plover/gui_qt/add_translation_dialog.py b/plover/gui_qt/add_translation_dialog.py index 364f83e26..60b1401a7 100644 --- a/plover/gui_qt/add_translation_dialog.py +++ b/plover/gui_qt/add_translation_dialog.py @@ -1,7 +1,6 @@ from PySide6.QtWidgets import QDialogButtonBox from plover import _ - from plover.gui_qt.add_translation_dialog_ui import Ui_AddTranslationDialog from plover.gui_qt.tool import Tool diff --git a/plover/gui_qt/add_translation_widget.py b/plover/gui_qt/add_translation_widget.py index b26c79dbd..97444b4e9 100644 --- a/plover/gui_qt/add_translation_widget.py +++ b/plover/gui_qt/add_translation_widget.py @@ -7,16 +7,14 @@ from PySide6.QtWidgets import QApplication, QWidget from plover import _ -from plover.misc import shorten_path -from plover.steno import normalize_steno, sort_steno_strokes from plover.engine import StartingStrokeState -from plover.translation import escape_translation, unescape_translation -from plover.formatting import RetroFormatter -from plover.resource import resource_filename - -from plover.formatting import SPACE_PLACEMENT_BEFORE +from plover.formatting import SPACE_PLACEMENT_BEFORE, RetroFormatter from plover.gui_qt.add_translation_widget_ui import Ui_AddTranslationWidget from plover.gui_qt.steno_validator import StenoValidator +from plover.misc import shorten_path +from plover.resource import resource_filename +from plover.steno import normalize_steno, sort_steno_strokes +from plover.translation import escape_translation, unescape_translation class AddTranslationWidget(QWidget, Ui_AddTranslationWidget): @@ -109,9 +107,11 @@ def eventFilter(self, watched, event): self._focus_strokes() elif watched == self.translation: self._focus_translation() - elif event.type() == QEvent.Type.FocusOut: - if watched in (self.strokes, self.translation): - self._unfocus() + elif event.type() == QEvent.Type.FocusOut and watched in ( + self.strokes, + self.translation, + ): + self._unfocus() return False def _set_engine_state(self, state): diff --git a/plover/gui_qt/appearance.py b/plover/gui_qt/appearance.py index e2cc0e8e2..3acf6437e 100644 --- a/plover/gui_qt/appearance.py +++ b/plover/gui_qt/appearance.py @@ -1,15 +1,14 @@ -from typing import Optional -from plover import log - from PySide6.QtCore import Qt from PySide6.QtGui import QGuiApplication +from plover import log + MODE_SYSTEM = "system" MODE_LIGHT = "light" MODE_DARK = "dark" -def _set_mode(mode: Optional[str]) -> None: +def _set_mode(mode: str | None) -> None: """Apply the requested mode to the current Qt application. This function tweaks Qt's idea of the platform color scheme via diff --git a/plover/gui_qt/config_window.py b/plover/gui_qt/config_window.py index 9fce08622..006c4f0ad 100644 --- a/plover/gui_qt/config_window.py +++ b/plover/gui_qt/config_window.py @@ -7,8 +7,6 @@ Signal, Slot, ) -from typing import Set - from PySide6.QtWidgets import ( QAbstractScrollArea, QCheckBox, @@ -18,8 +16,8 @@ QFileDialog, QFormLayout, QFrame, - QHeaderView, QGroupBox, + QHeaderView, QLabel, QScrollArea, QSizePolicy, @@ -30,16 +28,15 @@ ) from plover import _ -from plover.formatting import SPACE_PLACEMENT_BEFORE, SPACE_PLACEMENT_AFTER -from plover.config import MINIMUM_UNDO_LEVELS, MINIMUM_TIME_BETWEEN_KEY_PRESSES +from plover.config import MINIMUM_TIME_BETWEEN_KEY_PRESSES, MINIMUM_UNDO_LEVELS +from plover.formatting import SPACE_PLACEMENT_AFTER, SPACE_PLACEMENT_BEFORE from plover.gui_qt import appearance -from plover.misc import expand_path, shorten_path -from plover.registry import registry -from plover.oslayer.config import PLATFORM - -from plover.gui_qt.config_window_ui import Ui_ConfigWindow from plover.gui_qt.config_file_widget_ui import Ui_FileWidget +from plover.gui_qt.config_window_ui import Ui_ConfigWindow from plover.gui_qt.utils import WindowStateMixin +from plover.misc import expand_path, shorten_path +from plover.oslayer.config import PLATFORM +from plover.registry import registry class NopeOption(QLabel): @@ -229,7 +226,7 @@ def __init__(self, choices=None, labels=None): super().__init__() if labels is None: labels = self.LABELS - self._value: Set[str] = set() + self._value: set[str] = set() self._updating = False self._choices = {} if choices is None else choices self._reversed_choices = { @@ -323,7 +320,7 @@ def __init__( widget_class, help_text="", dependents=(), - additional_widget_classes=[], + additional_widget_classes=(), ): self.display_name = display_name self.option_name = option_name @@ -711,7 +708,7 @@ def _machine_option(self, *args): for klass in machine_class.mro(): # Look for `module_name:class_name` before `class_name`. for name in ( - "%s:%s" % (klass.__module__, klass.__name__), + f"{klass.__module__}:{klass.__name__}", klass.__name__, ): opt_class = machine_options.get(name) diff --git a/plover/gui_qt/console_widget.py b/plover/gui_qt/console_widget.py index 8e2208938..2b47e3eee 100644 --- a/plover/gui_qt/console_widget.py +++ b/plover/gui_qt/console_widget.py @@ -12,8 +12,8 @@ from plover.gui_qt.console_widget_ui import Ui_ConsoleWidget - -NULL = open(os.devnull, "r+b") +# Deliberately kept open for the widget's whole lifetime. +NULL = open(os.devnull, "r+b") # noqa: SIM115 class ConsoleWidget(QWidget, Ui_ConsoleWidget): @@ -67,8 +67,7 @@ def _subprocess(self): if not line: break line = line.decode() - if line.endswith(os.linesep): - line = line[: -len(os.linesep)] + line = line.removesuffix(os.linesep) print(line) self.textOutput.emit(line) self.processFinished.emit(self._proc.wait()) diff --git a/plover/gui_qt/dictionaries_widget.py b/plover/gui_qt/dictionaries_widget.py index 19eb78eaf..5e4a885b2 100644 --- a/plover/gui_qt/dictionaries_widget.py +++ b/plover/gui_qt/dictionaries_widget.py @@ -1,5 +1,6 @@ -from contextlib import contextmanager import os +from contextlib import contextmanager +from typing import ClassVar from PySide6.QtCore import ( QAbstractListModel, @@ -22,13 +23,12 @@ from plover.config import DictionaryConfig from plover.dictionary.base import create_dictionary from plover.engine import ErroredDictionary -from plover.misc import normalize_path -from plover.oslayer.config import CONFIG_DIR -from plover.registry import registry - from plover.gui_qt.dictionaries_widget_ui import Ui_DictionariesWidget from plover.gui_qt.dictionary_editor import DictionaryEditor from plover.gui_qt.utils import ToolBar +from plover.misc import normalize_path +from plover.oslayer.config import CONFIG_DIR +from plover.registry import registry def _dictionary_formats(include_readonly=True): @@ -62,12 +62,12 @@ def _new_dictionary(filename): yield d d.save() except Exception as e: - raise Exception("creating dictionary %s failed. %s" % (filename, e)) from e + raise RuntimeError(f"creating dictionary {filename} failed. {e}") from e class DictionariesModel(QAbstractListModel): class DictionaryItem: - __slots__ = "row path enabled short_path _loaded state".split() + __slots__ = ["_loaded", "enabled", "path", "row", "short_path", "state"] def __init__(self, row, config, loaded=None): self.row = row @@ -101,7 +101,7 @@ def config(self): def is_loaded(self): return self.state not in {"loading", "error"} - SUPPORTED_ROLES = [ + SUPPORTED_ROLES: ClassVar[list] = [ Qt.ItemDataRole.AccessibleTextRole, Qt.ItemDataRole.CheckStateRole, Qt.ItemDataRole.DecorationRole, @@ -370,7 +370,9 @@ def undo(self): # Model API. - def rowCount(self, parent=QModelIndex()): + def rowCount(self, parent=None): + if parent is None: + parent = QModelIndex() return 0 if parent.isValid() else len(self._from_row) def flags(self, index): @@ -523,8 +525,8 @@ def setup(self, engine): self._model = DictionariesModel( engine, { - name: QIcon(":resources/dictionary_%s.svg" % name) - for name in "favorite loading error readonly normal".split() + name: QIcon(f":resources/dictionary_{name}.svg") + for name in ["favorite", "loading", "error", "readonly", "normal"] }, ) self._model.has_undo_changed.connect(self.toggle_undo_action) diff --git a/plover/gui_qt/dictionary_editor.py b/plover/gui_qt/dictionary_editor.py index 04781b34e..4d51c88a5 100644 --- a/plover/gui_qt/dictionary_editor.py +++ b/plover/gui_qt/dictionary_editor.py @@ -1,6 +1,7 @@ -from operator import attrgetter, itemgetter from collections import namedtuple from itertools import chain +from operator import attrgetter, itemgetter + from PySide6.QtCore import QAbstractTableModel, QModelIndex, Qt, Slot from PySide6.QtGui import QIcon from PySide6.QtWidgets import ( @@ -10,14 +11,12 @@ ) from plover import _ -from plover.translation import escape_translation, unescape_translation -from plover.misc import expand_path, shorten_path -from plover.steno import normalize_steno, steno_to_sort_key - from plover.gui_qt.dictionary_editor_ui import Ui_DictionaryEditor from plover.gui_qt.steno_validator import StenoValidator from plover.gui_qt.utils import ToolBar, WindowStateMixin - +from plover.misc import expand_path, shorten_path +from plover.steno import normalize_steno, steno_to_sort_key +from plover.translation import escape_translation, unescape_translation _COL_STENO, _COL_TRANS, _COL_DICT, _COL_COUNT = range(3 + 1) @@ -256,11 +255,15 @@ def setData(self, index, value, role=Qt.ItemDataRole.EditRole, record=True): del old_item.dictionary[old_item.strokes] except KeyError: pass - if not old_item.strokes and not old_item.translation: - # Merge operations when editing a newly added row. - if self._operations and self._operations[-1] == [(None, old_item)]: - self._operations.pop() - old_item = None + # Merge operations when editing a newly added row. + if ( + not old_item.strokes + and not old_item.translation + and self._operations + and self._operations[-1] == [(None, old_item)] + ): + self._operations.pop() + old_item = None new_item = DictionaryItem(steno, translation, dictionary) self._entries[row] = new_item dictionary[strokes] = translation @@ -326,12 +329,11 @@ def __init__(self, engine, dictionary_paths): background = self.table.palette().highlightedText().color().name() text_color = self.table.palette().highlight().color().name() self.table.setStyleSheet( - """ - QTableView::item:focus { - background-color: %s; - color: %s; - }""" - % (background, text_color) + f""" + QTableView::item:focus {{ + background-color: {background}; + color: {text_color}; + }}""" ) self.table.setFocus() for action in ( @@ -353,8 +355,8 @@ def __init__(self, engine, dictionary_paths): @property def _selection(self): - return list( - sorted(index.row() for index in self.table.selectionModel().selectedRows(0)) + return sorted( + index.row() for index in self.table.selectionModel().selectedRows(0) ) def _select(self, row, edit=False): diff --git a/plover/gui_qt/info_browser.py b/plover/gui_qt/info_browser.py index 41bf9e41a..fc9f5451b 100644 --- a/plover/gui_qt/info_browser.py +++ b/plover/gui_qt/info_browser.py @@ -1,11 +1,11 @@ -from PySide6.QtGui import QImage, QTextDocument import re -from PySide6.QtWidgets import QTextBrowser -from PySide6.QtCore import QUrl, Signal -from plover.plugins_manager.requests import CachedSession, CachedFuturesSession +from PySide6.QtCore import QUrl, Signal +from PySide6.QtGui import QImage, QTextDocument +from PySide6.QtWidgets import QTextBrowser from plover import log +from plover.plugins_manager.requests import CachedFuturesSession, CachedSession class InfoBrowser(QTextBrowser): diff --git a/plover/gui_qt/lookup_dialog.py b/plover/gui_qt/lookup_dialog.py index 51727784b..e828d9c9e 100644 --- a/plover/gui_qt/lookup_dialog.py +++ b/plover/gui_qt/lookup_dialog.py @@ -1,10 +1,9 @@ from PySide6.QtCore import QEvent, Qt, Slot from plover import _ -from plover.translation import unescape_translation - from plover.gui_qt.lookup_dialog_ui import Ui_LookupDialog from plover.gui_qt.tool import Tool +from plover.translation import unescape_translation class LookupDialog(Tool, Ui_LookupDialog): @@ -26,12 +25,10 @@ def __init__(self, engine): self.finished.connect(self.save_state) def eventFilter(self, watched, event): - if event.type() == QEvent.Type.KeyPress and event.key() in ( - Qt.Key.Key_Enter, - Qt.Key.Key_Return, - ): - return True - return False + return bool( + event.type() == QEvent.Type.KeyPress + and event.key() in (Qt.Key.Key_Enter, Qt.Key.Key_Return) + ) def _update_suggestions(self, suggestion_list): self.suggestions.clear() diff --git a/plover/gui_qt/machine_options.py b/plover/gui_qt/machine_options.py index 9f3bc83b6..08a61edc7 100644 --- a/plover/gui_qt/machine_options.py +++ b/plover/gui_qt/machine_options.py @@ -5,10 +5,10 @@ from PySide6.QtGui import ( QIntValidator, QTextCharFormat, - QTextFrameFormat, - QTextListFormat, QTextCursor, QTextDocument, + QTextFrameFormat, + QTextListFormat, ) from PySide6.QtWidgets import ( QGroupBox, @@ -16,18 +16,16 @@ QStyledItemDelegate, QToolTip, ) - from serial import Serial from serial.tools.list_ports import comports from plover import _ -from plover.oslayer.serial import patch_ports_info -from plover.oslayer.config import PLATFORM -from plover.oslayer.linux.display_server import DISPLAY_SERVER - from plover.gui_qt.config_keyboard_widget_ui import Ui_KeyboardWidget -from plover.gui_qt.config_serial_widget_ui import Ui_SerialWidget from plover.gui_qt.config_plover_hid_widget_ui import Ui_PloverHidWidget +from plover.gui_qt.config_serial_widget_ui import Ui_SerialWidget +from plover.oslayer.config import PLATFORM +from plover.oslayer.linux.display_server import DISPLAY_SERVER +from plover.oslayer.serial import patch_ports_info def serial_port_details(port_info): @@ -43,7 +41,7 @@ def serial_port_details(port_info): if value not in global_ignore: parts.append(fmt.format(value=value)) local_ignore.add(value) - description = getattr(port_info, "description") + description = port_info.description if description not in local_ignore: parts.insert(0, _("description: {value}").format(value=description)) if not parts: diff --git a/plover/gui_qt/main.py b/plover/gui_qt/main.py index ed639411a..15cc61a2e 100644 --- a/plover/gui_qt/main.py +++ b/plover/gui_qt/main.py @@ -1,24 +1,23 @@ -from pathlib import Path import signal import sys +from pathlib import Path from PySide6.QtCore import ( QCoreApplication, QLibraryInfo, QTimer, - QTranslator, QtMsgType, + QTranslator, qInstallMessageHandler, ) from PySide6.QtWidgets import QApplication, QMessageBox -from plover import _, __name__ as __software_name__, __version__, log +from plover import _, __version__, log +from plover import __name__ as __software_name__ +from plover.gui_qt.engine import Engine from plover.oslayer.config import CONFIG_DIR from plover.oslayer.keyboardcontrol import KeyboardEmulation -from plover.gui_qt.engine import Engine - - # Disable input hook to avoid getting spammed when using the debugger. # import pdb # pdb.set_trace() @@ -86,7 +85,7 @@ def run(self): def show_error(title, message): - print("%s: %s" % (title, message)) + print(f"{title}: {message}") app = QApplication([]) QMessageBox.critical(None, title, message) del app @@ -104,11 +103,11 @@ def default_message_handler(msg_type, msg_log_context, msg_string): }.get(msg_type, log.error) details = [] if msg_log_context.file is not None: - details.append("%s:%u" % (msg_log_context.file, msg_log_context.line)) + details.append(f"{msg_log_context.file}:{msg_log_context.line}") if msg_log_context.function is not None: details.append(msg_log_context.function) if details: - details = " [%s]" % ", ".join(details) + details = " [{}]".format(", ".join(details)) else: details = "" log_fn("Qt: %s%s", msg_string, details) diff --git a/plover/gui_qt/main_window.py b/plover/gui_qt/main_window.py index c653cb843..5bc87bedd 100644 --- a/plover/gui_qt/main_window.py +++ b/plover/gui_qt/main_window.py @@ -1,7 +1,7 @@ -from functools import partial import json import os import subprocess +from functools import partial from PySide6.QtCore import QCoreApplication, Qt, Slot from PySide6.QtGui import QCursor, QIcon, QKeySequence @@ -11,18 +11,16 @@ ) from plover import _, log -from plover.oslayer import wmctrl -from plover.oslayer.config import CONFIG_DIR, PLATFORM -from plover.registry import registry - -from plover.gui_qt import utils +from plover.gui_qt import appearance, utils +from plover.gui_qt.about_dialog import AboutDialog +from plover.gui_qt.config_window import ConfigWindow from plover.gui_qt.log_qt import NotificationHandler from plover.gui_qt.main_window_ui import Ui_MainWindow -from plover.gui_qt.config_window import ConfigWindow -from plover.gui_qt.about_dialog import AboutDialog from plover.gui_qt.trayicon import TrayIcon from plover.gui_qt.utils import WindowStateMixin -from plover.gui_qt import appearance +from plover.oslayer import wmctrl +from plover.oslayer.config import CONFIG_DIR, PLATFORM +from plover.registry import registry class MainWindow(QMainWindow, Ui_MainWindow, WindowStateMixin): @@ -227,7 +225,7 @@ def _save_state(self, settings): if not action.isChecked() } settings.setValue( - "hidden_toolbar_tools", json.dumps(list(sorted(hidden_toolbar_tools))) + "hidden_toolbar_tools", json.dumps(sorted(hidden_toolbar_tools)) ) def _update_machine(self, machine_type): diff --git a/plover/gui_qt/paper_tape.py b/plover/gui_qt/paper_tape.py index f6242828c..7267c2ae9 100644 --- a/plover/gui_qt/paper_tape.py +++ b/plover/gui_qt/paper_tape.py @@ -13,17 +13,14 @@ QFontDialog, QMessageBox, ) - from wcwidth import wcwidth from plover import _, system -from plover.steno import Stroke - from plover.gui_qt import utils from plover.gui_qt.paper_tape_ui import Ui_PaperTape -from plover.gui_qt.utils import ActionCopyViewSelectionToClipboard, ToolBar from plover.gui_qt.tool import Tool - +from plover.gui_qt.utils import ActionCopyViewSelectionToClipboard, ToolBar +from plover.steno import Stroke STYLE_PAPER, STYLE_RAW = ( # i18n: Paper tape style. @@ -249,7 +246,9 @@ def clear(self): @Slot() def save(self): - filename_suggestion = "steno-notes-%s.txt" % time.strftime("%Y-%m-%d-%H-%M") + filename_suggestion = "steno-notes-{}.txt".format( + time.strftime("%Y-%m-%d-%H-%M") + ) filename = QFileDialog.getSaveFileName( self, _("Save Paper Tape"), diff --git a/plover/gui_qt/plugins_manager.py b/plover/gui_qt/plugins_manager.py index aa6430141..c8b5dda50 100644 --- a/plover/gui_qt/plugins_manager.py +++ b/plover/gui_qt/plugins_manager.py @@ -1,25 +1,25 @@ -from threading import Thread import atexit import html import os import sys +from threading import Thread from PySide6.QtCore import Qt, Signal, Slot from PySide6.QtWidgets import ( QDialog, + QInputDialog, QMessageBox, QTableWidgetItem, - QInputDialog, ) from plover import _, log -from plover.gui_qt.tool import Tool from plover.gui_qt.info_browser import InfoBrowser from plover.gui_qt.plugins_manager_ui import Ui_PluginsManager from plover.gui_qt.run_dialog import RunDialog +from plover.gui_qt.tool import Tool +from plover.plugins_manager.__main__ import pip from plover.plugins_manager.registry import Registry from plover.plugins_manager.utils import description_to_html -from plover.plugins_manager.__main__ import pip class PluginsManager(Tool, Ui_PluginsManager): @@ -66,7 +66,7 @@ def _update_table(self): self.table.setSortingEnabled(False) self.table.setRowCount(len(self._packages)) for row, state in enumerate(self._packages): - for column, attr in enumerate("status name version summary".split()): + for column, attr in enumerate(["status", "name", "version", "summary"]): value = getattr(state, attr, "N/A") if attr == "status": if value: @@ -118,9 +118,8 @@ def handle_selection_change(self): metadata = self._get_state(current_item.row()).metadata if metadata is None or metadata.name is None: return - prologue = "

%s (%s)

" % ( - html.escape(metadata.name), - html.escape(metadata.version), + prologue = ( + f"

{html.escape(metadata.name)} ({html.escape(metadata.version)})

" ) if metadata.author and metadata.author_email: # i18n: Metadata field. diff --git a/plover/gui_qt/run_dialog.py b/plover/gui_qt/run_dialog.py index d585093fd..a974dc885 100644 --- a/plover/gui_qt/run_dialog.py +++ b/plover/gui_qt/run_dialog.py @@ -1,4 +1,4 @@ -from PySide6.QtWidgets import QDialogButtonBox, QDialog +from PySide6.QtWidgets import QDialog, QDialogButtonBox from plover.gui_qt.console_widget import ConsoleWidget from plover.gui_qt.run_dialog_ui import Ui_RunDialog @@ -33,6 +33,7 @@ def reject(self): if __name__ == "__main__": import sys + from PySide6.QtWidgets import QApplication app = QApplication([]) diff --git a/plover/gui_qt/suggestions_dialog.py b/plover/gui_qt/suggestions_dialog.py index 40fca6917..717c0a6e3 100644 --- a/plover/gui_qt/suggestions_dialog.py +++ b/plover/gui_qt/suggestions_dialog.py @@ -12,13 +12,12 @@ ) from plover import _ -from plover.suggestions import Suggestion from plover.formatting import RetroFormatter - from plover.gui_qt import utils from plover.gui_qt.suggestions_dialog_ui import Ui_SuggestionsDialog -from plover.gui_qt.utils import ToolBar from plover.gui_qt.tool import Tool +from plover.gui_qt.utils import ToolBar +from plover.suggestions import Suggestion class SuggestionsDialog(Tool, Ui_SuggestionsDialog): diff --git a/plover/gui_qt/suggestions_widget.py b/plover/gui_qt/suggestions_widget.py index d0d43ac9c..faebfd188 100644 --- a/plover/gui_qt/suggestions_widget.py +++ b/plover/gui_qt/suggestions_widget.py @@ -22,7 +22,6 @@ from .utils import ActionCopyViewSelectionToClipboard - # i18n: Widget: “SuggestionsWidget”. NO_SUGGESTIONS_STRING = _("no suggestions") MAX_SUGGESTIONS_COUNT = 10 diff --git a/plover/gui_qt/trayicon.py b/plover/gui_qt/trayicon.py index 6a2b354de..50ac2288c 100644 --- a/plover/gui_qt/trayicon.py +++ b/plover/gui_qt/trayicon.py @@ -2,13 +2,13 @@ from PySide6.QtGui import QIcon from PySide6.QtWidgets import QMessageBox, QSystemTrayIcon -from plover import _, __name__ as __software_name__ -from plover import log -from plover.oslayer.config import PLATFORM +from plover import _, log +from plover import __name__ as __software_name__ from plover.machine.base import ( STATE_INITIALIZING, STATE_RUNNING, ) +from plover.oslayer.config import PLATFORM class TrayIcon(QObject): @@ -24,7 +24,7 @@ def __init__(self): "disabled", "enabled", ): - icon = QIcon(":resources/state-%s.svg" % state) + icon = QIcon(f":resources/state-{state}.svg") if hasattr(icon, "setIsMask"): icon.setIsMask(True) self._state_icons[state] = icon @@ -128,7 +128,7 @@ def _update_state(self): self._trayicon.setIcon(icon) self._trayicon.setToolTip( # i18n: Tray icon tooltip. - "Plover:\n- %s\n- %s." % (output_state, machine_state) + f"Plover:\n- {output_state}\n- {machine_state}." ) def _on_activated(self, reason): diff --git a/plover/gui_qt/utils.py b/plover/gui_qt/utils.py index 5320c9d76..16d5087f9 100644 --- a/plover/gui_qt/utils.py +++ b/plover/gui_qt/utils.py @@ -5,11 +5,11 @@ QKeySequence, ) from PySide6.QtWidgets import ( + QApplication, QMainWindow, QToolBar, QToolButton, QWidget, - QApplication, ) from plover import _ @@ -65,7 +65,6 @@ def _save_state(self, settings): """ To be overwritten by subclasses to save additional state. """ - pass def save_state(self): assert self.ROLE @@ -85,7 +84,6 @@ def _restore_state(self, settings): """ To be overwritten by subclasses to restore additional state. """ - pass def restore_state(self): assert self.ROLE diff --git a/plover/i18n.py b/plover/i18n.py index f17044431..53ac1b803 100644 --- a/plover/i18n.py +++ b/plover/i18n.py @@ -1,5 +1,5 @@ -import os import gettext +import os from plover.oslayer.config import CONFIG_DIR from plover.oslayer.i18n import get_system_language diff --git a/plover/key_combo.py b/plover/key_combo.py index 583c70634..b7d5e96c1 100644 --- a/plover/key_combo.py +++ b/plover/key_combo.py @@ -1,8 +1,5 @@ -# -*- coding: utf-8 -*- - import re - # Mapping of "standard" keynames (derived from X11 keysym names) to Unicode. # fmt: off KEYNAME_TO_CHAR = { @@ -104,14 +101,14 @@ "quoteleft" : "`", # ` "quoteright" : "'", # ' "registered" : "\xae", # ® - "return" : "\r", # + "return" : "\r", "section" : "\xa7", # § "semicolon" : ";", # ; "slash" : "/", # / - "space" : " ", # + "space" : " ", "ssharp" : "\xdf", # ß "sterling" : "\xa3", # £ - "tab" : "\t", # + "tab" : "\t", "thorn" : "\xfe", # þ "threequarters" : "\xbe", # ¾ "threesuperior" : "\xb3", # ³ @@ -146,7 +143,7 @@ def key_name_to_key_code(key_name): count = 0 def _raise_error(exception, details): - msg = '%s in "%s"' % ( + msg = '{} in "{}"'.format( details, combo_string[:count] + "[" @@ -175,7 +172,7 @@ def _raise_error(exception, details): if key_code is None: _raise_error(ValueError, "unknown key") elif key_code in down_keys: - _raise_error(ValueError, 'key "%s" already pressed' % key_name) + _raise_error(ValueError, f'key "{key_name}" already pressed') key_events.append((key_code, True)) @@ -191,7 +188,7 @@ def _raise_error(exception, details): key_events.append((key_code, False)) else: - _raise_error(SyntaxError, 'invalid character "%s"' % token) + _raise_error(SyntaxError, f'invalid character "{token}"') count += len(token) diff --git a/plover/log.py b/plover/log.py index 6275823b5..6a39d2c78 100644 --- a/plover/log.py +++ b/plover/log.py @@ -3,17 +3,15 @@ """A module to handle logging.""" +import logging import os import sys -import logging import traceback - -from logging.handlers import RotatingFileHandler from logging import INFO, WARNING +from logging.handlers import RotatingFileHandler from plover.oslayer.config import CONFIG_DIR - LOG_FORMAT = "%(asctime)s [%(threadName)s] %(levelname)s: %(message)s" LOG_FILENAME = os.path.realpath(os.path.join(CONFIG_DIR, "plover.log")) LOG_MAX_BYTES = 10000000 @@ -36,7 +34,7 @@ def format(self, record): record.exc_text = orig_exc_text def formatException(self, exc_info): - etype, evalue, tb = exc_info + etype, evalue, _tb = exc_info lines = traceback.format_exception_only(etype, evalue) return "".join(lines) diff --git a/plover/machine/base.py b/plover/machine/base.py index 2955c9602..8d98ee721 100644 --- a/plover/machine/base.py +++ b/plover/machine/base.py @@ -8,6 +8,7 @@ import binascii import threading +from typing import ClassVar import serial @@ -15,7 +16,6 @@ from plover.machine.keymap import Keymap from plover.misc import boolean - # i18n: Machine state. STATE_STOPPED = _("stopped") # i18n: Machine state. @@ -52,11 +52,9 @@ def set_keymap(self, keymap): def start_capture(self): """Begin listening for output from the stenotype machine.""" - pass def stop_capture(self): """Stop listening for output from the stenotype machine.""" - pass def add_stroke_callback(self, callback): """Subscribe to output from the stenotype machine. @@ -101,7 +99,6 @@ def set_suppression(self, enabled): This is only of use for the keyboard machine, to suppress the keyboard when then engine is running. """ - pass def suppress_last_stroke(self, send_backspaces): """Suppress the last stroke key events after the fact. @@ -113,7 +110,6 @@ def suppress_last_stroke(self, send_backspaces): send_backspaces -- The function to use to send backspaces. """ - pass def _set_state(self, state): self.state = state @@ -171,7 +167,6 @@ def invoke_excepthook(self): def run(self): """This method should be overridden by a subclass.""" - pass def start_capture(self): """Begin listening for output from the stenotype machine.""" @@ -199,7 +194,7 @@ class SerialStenotypeBase(ThreadedStenotypeBase): """ # Default serial parameters. - SERIAL_PARAMS = { + SERIAL_PARAMS: ClassVar[dict] = { "port": None, "baudrate": 9600, "bytesize": 8, diff --git a/plover/machine/gemini_pr.py b/plover/machine/gemini_pr.py index 21b1e8b18..2374300b0 100644 --- a/plover/machine/gemini_pr.py +++ b/plover/machine/gemini_pr.py @@ -8,7 +8,6 @@ from plover import log from plover.machine.base import SerialStenotypeBase - # In the Gemini PR protocol, each packet consists of exactly six bytes # and the most significant bit (MSB) of every byte is used exclusively # to indicate whether that byte is the first byte of the packet diff --git a/plover/machine/keyboard.py b/plover/machine/keyboard.py index 47a4e567c..cf57d3111 100644 --- a/plover/machine/keyboard.py +++ b/plover/machine/keyboard.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2010 Joshua Harlan Lifton. # See LICENSE.txt for details. @@ -7,11 +6,10 @@ from plover import _ from plover.machine.base import StenotypeBase from plover.misc import boolean -from plover.oslayer.keyboardcontrol import KeyboardCapture from plover.oslayer.config import PLATFORM +from plover.oslayer.keyboardcontrol import KeyboardCapture from plover.oslayer.linux.display_server import DISPLAY_SERVER - # i18n: Machine name. _._("Keyboard") diff --git a/plover/machine/keyboard_capture/__init__.py b/plover/machine/keyboard_capture/__init__.py index 462ee043e..c5d1b1664 100644 --- a/plover/machine/keyboard_capture/__init__.py +++ b/plover/machine/keyboard_capture/__init__.py @@ -34,8 +34,8 @@ def suppress(self, suppressed_keys: Sequence[str] = ()) -> None: # Callbacks for keyboard press/release events. def key_down(self, key: str) -> None: """Notifies Plover that a key was pressed down.""" - return None + return def key_up(self, key: str) -> None: """Notifies Plover that a key was released.""" - return None + return diff --git a/plover/machine/keymap.py b/plover/machine/keymap.py index 4f93d33bc..8f1424179 100644 --- a/plover/machine/keymap.py +++ b/plover/machine/keymap.py @@ -107,7 +107,7 @@ def set_mappings(self, mappings: Any) -> None: if not key_list: # Not an issue if 'no-op' is not mapped... if action != "no-op": - errors.append("action %s is not bound" % action) + errors.append(f"action {action} is not bound") # Add dummy mapping for each missing action # so it's shown in the configurator. self._mappings[action] = () @@ -117,7 +117,7 @@ def set_mappings(self, mappings: Any) -> None: valid_key_list = [] for key in key_list: if key not in self._keys: - errors.append("invalid key %s bound to action %s" % (key, action)) + errors.append(f"invalid key {key} bound to action {action}") continue valid_key_list.append(key) bound_keys[key].append(action) @@ -128,13 +128,13 @@ def set_mappings(self, mappings: Any) -> None: if isinstance(key_list, str): key_list = (key_list,) errors.append( - "invalid action %s mapped to key(s) %s" % (action, " ".join(key_list)) + "invalid action {} mapped to key(s) {}".format( + action, " ".join(key_list) + ) ) for key, action_list in bound_keys.items(): if len(action_list) > 1: - errors.append( - "key %s is bound multiple times: %s" % (key, str(action_list)) - ) + errors.append(f"key {key} is bound multiple times: {action_list!s}") if len(errors) > 0: log.warning( "Keymap is invalid, behavior undefined:\n\n- " + "\n- ".join(errors) @@ -160,7 +160,7 @@ def keys_to_actions(self, key_list: list[str] | tuple[str, ...]) -> list[str]: """ action_list = [] for key in key_list: - assert key in self._keys, "'%s' not in %s" % (key, self._keys) + assert key in self._keys, f"'{key}' not in {self._keys}" action = self._bindings.get(key, "no-op") if "no-op" != action: action_list.append(action) @@ -199,12 +199,10 @@ def __setitem__(self, action, key_list): valid_key_list = [] for key in key_list: if key not in self._keys: - errors.append("invalid key %s bound to action %s" % (key, action)) + errors.append(f"invalid key {key} bound to action {action}") continue if key in self._bindings: - errors.append( - "key %s is already bound to: %s" % (key, self._bindings[key]) - ) + errors.append(f"key {key} is already bound to: {self._bindings[key]}") continue valid_key_list.append(key) self._bindings[key] = action diff --git a/plover/machine/passport.py b/plover/machine/passport.py index 6279391bd..034d5e545 100644 --- a/plover/machine/passport.py +++ b/plover/machine/passport.py @@ -4,6 +4,7 @@ "Thread-based monitoring of a stenotype machine using the passport protocol." from itertools import zip_longest +from typing import ClassVar from plover.machine.base import SerialStenotypeBase @@ -22,7 +23,7 @@ class Passport(SerialStenotypeBase): ! ^ + """ - SERIAL_PARAMS = dict(SerialStenotypeBase.SERIAL_PARAMS) + SERIAL_PARAMS: ClassVar[dict] = dict(SerialStenotypeBase.SERIAL_PARAMS) SERIAL_PARAMS.update(baudrate=38400) def __init__(self, params): @@ -61,4 +62,4 @@ def grouper(iterable, n, fillvalue=None): "Collect data into fixed-length chunks or blocks" # grouper('ABCDEFG', 3, 'x') --> ABC DEF Gxx args = [iter(iterable)] * n - return zip_longest(fillvalue=fillvalue, *args) + return zip_longest(*args, fillvalue=fillvalue) diff --git a/plover/machine/plover_hid.py b/plover/machine/plover_hid.py index 27019454e..3664fbbe9 100644 --- a/plover/machine/plover_hid.py +++ b/plover/machine/plover_hid.py @@ -8,18 +8,19 @@ of the steno machine every time that state changes. """ -from plover.machine.base import ThreadedStenotypeBase -from plover.misc import boolean -from plover import log - -import hid -import time +import ctypes import platform import threading -import ctypes -from queue import Queue, Empty -from typing import Any, Dict +import time from dataclasses import dataclass +from queue import Empty, Queue +from typing import Any + +import hid + +from plover import log +from plover.machine.base import ThreadedStenotypeBase +from plover.misc import boolean def _darwin_disable_exclusive_open() -> None: @@ -101,10 +102,10 @@ class PloverHid(ThreadedStenotypeBase): ''' # fmt: on - def __init__(self, params: Dict[str, Any]) -> None: + def __init__(self, params: dict[str, Any]) -> None: super().__init__() self._params = params - self._devices: Dict[bytes, HidDeviceRecord] = {} + self._devices: dict[bytes, HidDeviceRecord] = {} self._report_queue: Queue[bytes] = Queue() self._lock: threading.Lock = threading.Lock() self._device_watcher: threading.Thread | None = None @@ -141,14 +142,12 @@ def _remove_device(self, path: bytes) -> None: device.close() except Exception: log.debug("failed to close HID device") - pass # Join the reader if we're not currently in that same thread. try: if thread is not None and thread is not threading.current_thread(): thread.join(timeout=0.2) except Exception: log.debug("failed kill device read thread") - pass # If nothing left and we're not shutting down, show Disconnected in the UI if not self._devices and not self.finished.is_set(): self._error() @@ -201,7 +200,6 @@ def _read_from_device_loop(self, path: bytes, device: hid.device) -> None: self._report_queue.put_nowait(report_bytes) except Exception: log.debug("failed to put report in queue") - pass self._remove_device(path) def _parse(self, report: bytes) -> int: @@ -306,20 +304,20 @@ def stop_capture(self) -> None: if t_watch is not None: try: t_watch.join(timeout=0.3) - except Exception: + except Exception: # noqa: S110 pass self._device_watcher = None # Remove all devices via common teardown for path in list(self._devices.keys()): try: self._remove_device(path) - except Exception: + except Exception: # noqa: S110 pass # Drain the report queue best-effort try: while True: self._report_queue.get_nowait() - except Exception: + except Exception: # noqa: S110 pass @classmethod diff --git a/plover/machine/procat.py b/plover/machine/procat.py index f5306750d..c1a25cf69 100644 --- a/plover/machine/procat.py +++ b/plover/machine/procat.py @@ -5,7 +5,6 @@ from plover import log from plover.machine.base import SerialStenotypeBase - # ProCAT machines send 4 bytes per stroke, with the last byte only consisting of # FF. So we need only look at the first 3 bytes to see our steno. The leading # bit is 0. @@ -44,7 +43,7 @@ def process_steno_packet(raw): # Raw packet has 4 bytes, we only care about the first 3 steno_keys = [] for i, b in enumerate(raw[:3]): - for j in range(0, 8): + for j in range(8): if b & 0x80 >> j: key = STENO_KEY_CHART[i * 8 + j] steno_keys.append(key) diff --git a/plover/machine/stentura.py b/plover/machine/stentura.py index 6930c01b5..7c6cbe184 100644 --- a/plover/machine/stentura.py +++ b/plover/machine/stentura.py @@ -4,8 +4,8 @@ import struct -from plover import log import plover.machine.base +from plover import log # TODO: Come up with a mechanism to communicate back to the engine when there # is a connection error. @@ -167,26 +167,18 @@ def _allocate_buffer(): class _ProtocolViolationException(Exception): """Something has happened that is doesn't follow the protocol.""" - pass - class _StopException(Exception): """The thread was asked to stop.""" - pass - class _TimeoutException(Exception): """An operation has timed out.""" - pass - class _ConnectionLostException(Exception): """Cannot communicate with the machine.""" - pass - # fmt: off _CRC_TABLE = [ @@ -314,11 +306,11 @@ def _parse_strokes(data): strokes = [] if (len(data) % 4) != 0: raise _ProtocolViolationException( - "Data size is not divisible by 4: %d" % (len(data)) + f"Data size is not divisible by 4: {len(data)}" ) for b in data: if (b & 0b11000000) != 0b11000000: - raise _ProtocolViolationException("Data is not stroke: 0x%X" % (b)) + raise _ProtocolViolationException(f"Data is not stroke: 0x{b:X}") for a, b, c, d in zip(*([iter(data)] * 4)): strokes.append(_parse_stroke(a, b, c, d)) return strokes diff --git a/plover/macro/retro.py b/plover/macro/retro.py index bdfbada9c..c4010b0dc 100644 --- a/plover/macro/retro.py +++ b/plover/macro/retro.py @@ -1,6 +1,6 @@ -from plover.translation import Translation -from plover.steno import Stroke from plover import system +from plover.steno import Stroke +from plover.translation import Translation def toggle_asterisk(translator, stroke, cmdline): @@ -33,7 +33,7 @@ def delete_space(translator, stroke, cmdline): if t.english is not None: english.append(t.english) elif len(t.rtfcre) == 1 and t.rtfcre[0].isdigit(): - english.append("{&%s}" % t.rtfcre[0]) + english.append(f"{{&{t.rtfcre[0]}}}") if len(english) > 1: t = Translation([stroke], "{^~|^}".join(english)) t.replaced = replaced diff --git a/plover/macro/undo.py b/plover/macro/undo.py index 173589e30..4830a7c9c 100644 --- a/plover/macro/undo.py +++ b/plover/macro/undo.py @@ -1,6 +1,5 @@ -from plover.translation import Translation from plover.oslayer.config import PLATFORM - +from plover.translation import Translation if PLATFORM == "mac": BACK_STRING = "{#Alt_L(BackSpace)}{^}" diff --git a/plover/messages/es/LC_MESSAGES/plover.po b/plover/messages/es/LC_MESSAGES/plover.po index 2535fe207..56389d152 100644 --- a/plover/messages/es/LC_MESSAGES/plover.po +++ b/plover/messages/es/LC_MESSAGES/plover.po @@ -3,7 +3,7 @@ msgid "" msgstr "" "Project-Id-Version: plover 5.4.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-07-10 08:01+0200\n" +"POT-Creation-Date: 2026-07-26 08:22+0200\n" "PO-Revision-Date: 2026-03-08 12:00+0100\n" "Last-Translator: Gemini CLI\n" "Language: es\n" @@ -73,12 +73,12 @@ msgstr "Plover: Acerca de" #. Widget: “AddTranslationDialog”, tooltip. #. Widget: “AddTranslationWidget”, tooltip. -#: plover/gui_qt/add_translation_dialog.py:11 -#: plover/gui_qt/add_translation_widget.py:24 +#: plover/gui_qt/add_translation_dialog.py:10 +#: plover/gui_qt/add_translation_widget.py:22 msgid "Add a new translation to the dictionary." msgstr "Añadir una nueva traducción al diccionario." -#: plover/gui_qt/add_translation_dialog.py:13 +#: plover/gui_qt/add_translation_dialog.py:12 msgid "Add Translation" msgstr "Añadir traducción" @@ -125,7 +125,7 @@ msgstr "Acordes:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:132 -#: plover/gui_qt/dictionary_editor.py:170 +#: plover/gui_qt/dictionary_editor.py:169 msgid "Strokes" msgstr "Acordes" @@ -137,7 +137,7 @@ msgstr "Traducción:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:138 -#: plover/gui_qt/dictionary_editor.py:173 +#: plover/gui_qt/dictionary_editor.py:172 msgid "Translation" msgstr "Traducción" @@ -149,7 +149,7 @@ msgstr "Diccionario:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:144 -#: plover/gui_qt/dictionary_editor.py:176 +#: plover/gui_qt/dictionary_editor.py:175 msgid "Dictionary" msgstr "Diccionario" @@ -374,51 +374,51 @@ msgstr "RTS/CTS" #. Widget: “NopeOption” (empty config option message, #. e.g. the machine option when selecting the Treal machine). -#: plover/gui_qt/config_window.py:52 +#: plover/gui_qt/config_window.py:49 msgid "Nothing to see here!" msgstr "¡Aquí no hay nada para ver!" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:174 +#: plover/gui_qt/config_window.py:171 msgid "Key" msgstr "Tecla" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:176 +#: plover/gui_qt/config_window.py:173 msgid "Action" msgstr "Acción" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:222 +#: plover/gui_qt/config_window.py:219 msgid "Selected" msgstr "Seleccionado" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:224 +#: plover/gui_qt/config_window.py:221 msgid "Choice" msgstr "Opción" -#: plover/gui_qt/config_window.py:355 +#: plover/gui_qt/config_window.py:352 msgid "Interface" msgstr "Interfaz" -#: plover/gui_qt/config_window.py:358 +#: plover/gui_qt/config_window.py:355 msgid "Appearance:" msgstr "Apariencia:" -#: plover/gui_qt/config_window.py:363 plover/gui_qt/config_window.py:587 +#: plover/gui_qt/config_window.py:360 plover/gui_qt/config_window.py:584 msgid "System" msgstr "Sistema" -#: plover/gui_qt/config_window.py:364 +#: plover/gui_qt/config_window.py:361 msgid "Light" msgstr "Claro" -#: plover/gui_qt/config_window.py:365 +#: plover/gui_qt/config_window.py:362 msgid "Dark" msgstr "Oscuro" -#: plover/gui_qt/config_window.py:369 +#: plover/gui_qt/config_window.py:366 msgid "" "Set the application appearance:\n" "- System: follow the operating system mode\n" @@ -430,35 +430,35 @@ msgstr "" "- Claro: forzar el modo claro\n" "- Oscuro: forzar el modo oscuro" -#: plover/gui_qt/config_window.py:376 +#: plover/gui_qt/config_window.py:373 msgid "Start minimized:" msgstr "Iniciar minimizado:" -#: plover/gui_qt/config_window.py:379 +#: plover/gui_qt/config_window.py:376 msgid "Minimize the main window to systray on startup." msgstr "Minimizar la ventana principal a la bandeja del sistema al arrancar." -#: plover/gui_qt/config_window.py:382 +#: plover/gui_qt/config_window.py:379 msgid "Show paper tape:" msgstr "Mostrar tira de papel:" -#: plover/gui_qt/config_window.py:385 +#: plover/gui_qt/config_window.py:382 msgid "Open the paper tape on startup." msgstr "Abrir la tira de papel al arrancar." -#: plover/gui_qt/config_window.py:388 +#: plover/gui_qt/config_window.py:385 msgid "Show suggestions:" msgstr "Mostrar sugerencias:" -#: plover/gui_qt/config_window.py:391 +#: plover/gui_qt/config_window.py:388 msgid "Open the suggestions dialog on startup." msgstr "Abrir el diálogo de sugerencias al arrancar." -#: plover/gui_qt/config_window.py:394 +#: plover/gui_qt/config_window.py:391 msgid "Add translation dialog opacity:" msgstr "Añadir opacidad para el diálogo de traducción:" -#: plover/gui_qt/config_window.py:398 +#: plover/gui_qt/config_window.py:395 msgid "" "Set the translation dialog opacity:\n" "- 0 makes the dialog invisible.\n" @@ -468,19 +468,19 @@ msgstr "" "- 0 hace invisible el diálogo.\n" "- 100 es totalmente opaco." -#: plover/gui_qt/config_window.py:404 +#: plover/gui_qt/config_window.py:401 msgid "Dictionaries display order:" msgstr "Orden para visualización de diccionarios:" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "top-down" msgstr "hacia abajo" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "bottom-up" msgstr "hacia arriba" -#: plover/gui_qt/config_window.py:410 +#: plover/gui_qt/config_window.py:407 msgid "" "Set the display order for dictionaries:\n" "- top-down: Match the search order; highest priority first.\n" @@ -492,77 +492,77 @@ msgstr "" "- de abajo arriba: invertir el orden de búsqueda; primero el de menor " "prioridad.\n" -#: plover/gui_qt/config_window.py:419 +#: plover/gui_qt/config_window.py:416 msgid "Logging" msgstr "Registro" -#: plover/gui_qt/config_window.py:422 +#: plover/gui_qt/config_window.py:419 msgid "Log file:" msgstr "Fichero de registro:" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Select a log file" msgstr "Seleccionar un fichero de registro" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Log files (*.log)" msgstr "Ficheros de registro (*.log)" -#: plover/gui_qt/config_window.py:427 +#: plover/gui_qt/config_window.py:424 msgid "File to use for logging strokes/translations." msgstr "Fichero para usar en el registro de acordes/traducciones." -#: plover/gui_qt/config_window.py:430 +#: plover/gui_qt/config_window.py:427 msgid "Log strokes:" msgstr "Registrar acordes:" -#: plover/gui_qt/config_window.py:433 +#: plover/gui_qt/config_window.py:430 msgid "Save strokes to the logfile." msgstr "Guardar acordes en el fichero de registro." -#: plover/gui_qt/config_window.py:436 +#: plover/gui_qt/config_window.py:433 msgid "Log translations:" msgstr "Registrar traducciones:" -#: plover/gui_qt/config_window.py:439 +#: plover/gui_qt/config_window.py:436 msgid "Save translations to the logfile." msgstr "Guardar traducciones en el fichero de registro." #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:445 plover/gui_qt/main_window_ui.py:260 +#: plover/gui_qt/config_window.py:442 plover/gui_qt/main_window_ui.py:260 msgid "Machine" msgstr "Máquina" -#: plover/gui_qt/config_window.py:448 +#: plover/gui_qt/config_window.py:445 msgid "Machine:" msgstr "Máquina:" -#: plover/gui_qt/config_window.py:460 +#: plover/gui_qt/config_window.py:457 msgid "Options:" msgstr "Opciones:" -#: plover/gui_qt/config_window.py:462 +#: plover/gui_qt/config_window.py:459 msgid "Keymap:" msgstr "Asignaciones de teclas:" #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:467 plover/gui_qt/main_window_ui.py:292 +#: plover/gui_qt/config_window.py:464 plover/gui_qt/main_window_ui.py:292 msgid "Output" msgstr "Salida" -#: plover/gui_qt/config_window.py:470 +#: plover/gui_qt/config_window.py:467 msgid "Enable at start:" msgstr "Activar al inicio:" -#: plover/gui_qt/config_window.py:473 +#: plover/gui_qt/config_window.py:470 msgid "Enable output on startup." msgstr "Activar la salida al arrancar." -#: plover/gui_qt/config_window.py:476 +#: plover/gui_qt/config_window.py:473 msgid "Start attached:" msgstr "Suprimir espacio inicial:" -#: plover/gui_qt/config_window.py:480 +#: plover/gui_qt/config_window.py:477 msgid "" "Disable preceding space on first output.\n" "\n" @@ -572,37 +572,37 @@ msgstr "" "\n" "Esta opción solo es aplicable cuando los espacios se colocan antes." -#: plover/gui_qt/config_window.py:486 +#: plover/gui_qt/config_window.py:483 msgid "Start capitalized:" msgstr "Inicio en mayúscula:" -#: plover/gui_qt/config_window.py:489 +#: plover/gui_qt/config_window.py:486 msgid "Capitalize the first word." msgstr "Poner en mayúscula la primera palabra." -#: plover/gui_qt/config_window.py:492 +#: plover/gui_qt/config_window.py:489 msgid "Space placement:" msgstr "Ubicación de espacio:" -#: plover/gui_qt/config_window.py:497 +#: plover/gui_qt/config_window.py:494 msgid "Before Output" msgstr "Antes de la salida" -#: plover/gui_qt/config_window.py:498 +#: plover/gui_qt/config_window.py:495 msgid "After Output" msgstr "Después de la salida" -#: plover/gui_qt/config_window.py:501 +#: plover/gui_qt/config_window.py:498 msgid "Set automatic space placement: before or after each word." msgstr "" "Establecer la ubicación automática del espacio: antes o después de cada " "palabra." -#: plover/gui_qt/config_window.py:504 +#: plover/gui_qt/config_window.py:501 msgid "Undo levels:" msgstr "Niveles para deshacer:" -#: plover/gui_qt/config_window.py:508 +#: plover/gui_qt/config_window.py:505 msgid "" "Set how many preceding strokes can be undone.\n" "\n" @@ -614,11 +614,11 @@ msgstr "" "Nota: el valor efectivo tendrá en cuenta \n" "la entrada de diccionarios con el máximo número de acordes." -#: plover/gui_qt/config_window.py:515 +#: plover/gui_qt/config_window.py:512 msgid "Key press delay (ms):" msgstr "Retraso de pulsación de tecla (ms):" -#: plover/gui_qt/config_window.py:523 +#: plover/gui_qt/config_window.py:520 msgid "" "Set the delay between emulated key presses (in milliseconds).\n" "\n" @@ -638,11 +638,11 @@ msgstr "" "Establecer el retraso demasiado alto afectará negativamente al\n" "rendimiento de la salida de las pulsaciones de teclas." -#: plover/gui_qt/config_window.py:533 +#: plover/gui_qt/config_window.py:530 msgid "Linux keyboard layout:" msgstr "Disposición del teclado de Linux:" -#: plover/gui_qt/config_window.py:547 +#: plover/gui_qt/config_window.py:544 msgid "" "Set the keyboard layout configured in your system.\n" "This only applies when using Linux/BSD and not using X11.\n" @@ -658,7 +658,7 @@ msgstr "" "puede detectar la primera disposición del teclado\n" "y no puede detectar cambios de disposición." -#: plover/gui_qt/config_window.py:557 +#: plover/gui_qt/config_window.py:554 msgid "" "When Wayland auto detect is selected, Plover is only able to detect the " "first keyboard layout and can not detect layout switches." @@ -667,29 +667,29 @@ msgstr "" "puede detectar la primera disposición del teclado y no puede detectar " "cambios de disposición." -#: plover/gui_qt/config_window.py:568 +#: plover/gui_qt/config_window.py:565 msgid "Plugins" msgstr "Complementos" -#: plover/gui_qt/config_window.py:571 +#: plover/gui_qt/config_window.py:568 msgid "Extensions:" msgstr "Extensiones:" #. Widget: “MainWindow”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/main_window_ui.py:294 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/main_window_ui.py:294 msgid "Enabled" msgstr "Habilitado" #. Widget: “PluginsManager”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/plugins_manager_ui.py:137 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/plugins_manager_ui.py:137 msgid "Name" msgstr "Nombre" -#: plover/gui_qt/config_window.py:581 +#: plover/gui_qt/config_window.py:578 msgid "Configure enabled plugin extensions." msgstr "Configurar extensiones de complementos habilitadas." -#: plover/gui_qt/config_window.py:590 +#: plover/gui_qt/config_window.py:587 msgid "System:" msgstr "Sistema:" @@ -716,83 +716,83 @@ msgid "{format} dictionaries ({extensions})" msgstr "Diccionarios {format} ({extensions})" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:391 +#: plover/gui_qt/dictionaries_widget.py:393 msgid "disabled" msgstr "deshabilitado" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:394 +#: plover/gui_qt/dictionaries_widget.py:396 msgid "favorite" msgstr "favorito" -#: plover/gui_qt/dictionaries_widget.py:398 +#: plover/gui_qt/dictionaries_widget.py:400 #, python-brace-format msgid "errored: {exception}." msgstr "con error: {exception}." #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:402 +#: plover/gui_qt/dictionaries_widget.py:404 msgid "loading" msgstr "se está cargando" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:405 +#: plover/gui_qt/dictionaries_widget.py:407 msgid "read-only" msgstr "solo lectura" #. Widget: “DictionariesWidget”, tooltip. -#: plover/gui_qt/dictionaries_widget.py:411 +#: plover/gui_qt/dictionaries_widget.py:413 #, python-brace-format msgid "Full path: {path}." msgstr "Ruta completa: {path}." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:414 +#: plover/gui_qt/dictionaries_widget.py:416 msgid "This dictionary is marked as the favorite." msgstr "Este diccionario está marcado como el favorito." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:417 +#: plover/gui_qt/dictionaries_widget.py:419 msgid "This dictionary is being loaded." msgstr "Este diccionario se está cargando." -#: plover/gui_qt/dictionaries_widget.py:421 +#: plover/gui_qt/dictionaries_widget.py:423 #, python-brace-format msgid "Loading this dictionary failed: {exception}." msgstr "La carga de este diccionario falló: {exception}." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:427 +#: plover/gui_qt/dictionaries_widget.py:429 msgid "This dictionary is read-only." msgstr "Este diccionario es de solo lectura." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:618 +#: plover/gui_qt/dictionaries_widget.py:620 #, python-brace-format msgid "Save a copy of {name} as..." msgstr "Guardar una copia de {name} como..." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:620 +#: plover/gui_qt/dictionaries_widget.py:622 #, python-brace-format msgid "{name} - Copy" msgstr "{name} - Copiar" #. Widget: “DictionariesWidget”, “save as merge” file picker. -#: plover/gui_qt/dictionaries_widget.py:642 +#: plover/gui_qt/dictionaries_widget.py:644 #, python-brace-format msgid "Merge {names} as..." msgstr "Fusionar {names} como..." #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:671 +#: plover/gui_qt/dictionaries_widget.py:673 #: plover/gui_qt/dictionaries_widget_ui.py:203 msgid "Load dictionaries" msgstr "Cargar diccionarios" #. Widget: “DictionariesWidget”, “new” file picker. #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:683 +#: plover/gui_qt/dictionaries_widget.py:685 #: plover/gui_qt/dictionaries_widget_ui.py:205 msgid "Create dictionary" msgstr "Crear diccionario" @@ -1018,11 +1018,11 @@ msgid "Mappings" msgstr "Asignaciones" #. Widget: “LookupDialog”, tooltip. -#: plover/gui_qt/lookup_dialog.py:12 +#: plover/gui_qt/lookup_dialog.py:11 msgid "Search the dictionary for translations." msgstr "Buscar traducciones en el diccionario." -#: plover/gui_qt/lookup_dialog.py:14 +#: plover/gui_qt/lookup_dialog.py:13 msgid "Lookup" msgstr "Buscar" @@ -1046,27 +1046,27 @@ msgstr "Patrón de traducción para buscar." msgid "Results" msgstr "Resultados" -#: plover/gui_qt/machine_options.py:38 +#: plover/gui_qt/machine_options.py:36 #, python-brace-format msgid "product: {value}" msgstr "producto: {value}" -#: plover/gui_qt/machine_options.py:39 +#: plover/gui_qt/machine_options.py:37 #, python-brace-format msgid "manufacturer: {value}" msgstr "fabricante: {value}" -#: plover/gui_qt/machine_options.py:40 +#: plover/gui_qt/machine_options.py:38 #, python-brace-format msgid "serial number: {value}" msgstr "número de serie: {value}" -#: plover/gui_qt/machine_options.py:48 +#: plover/gui_qt/machine_options.py:46 #, python-brace-format msgid "description: {value}" msgstr "descripción: {value}" -#: plover/gui_qt/machine_options.py:201 +#: plover/gui_qt/machine_options.py:199 msgid "" "Arpeggiate allows using non-NKRO keyboards.\n" "\n" @@ -1077,7 +1077,7 @@ msgstr "" "\n" "Cada tecla puede pulsarse por separado y el espacio envía el acorde." -#: plover/gui_qt/main_window.py:312 +#: plover/gui_qt/main_window.py:310 msgid "Application is still running." msgstr "La aplicación ya se está ejecutando." @@ -1230,34 +1230,34 @@ msgid "Plover: Toolbar" msgstr "Plover: Barra de herramientas" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:30 +#: plover/gui_qt/paper_tape.py:27 msgid "Paper" msgstr "Papel" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:32 +#: plover/gui_qt/paper_tape.py:29 msgid "Raw" msgstr "Sin procesar" #. Widget: “PaperTape”, tooltip. -#: plover/gui_qt/paper_tape.py:122 +#: plover/gui_qt/paper_tape.py:119 msgid "Paper tape display of strokes." msgstr "Visualización de acordes en la tira de papel." -#: plover/gui_qt/paper_tape.py:124 +#: plover/gui_qt/paper_tape.py:121 msgid "Paper Tape" msgstr "Tira de papel" -#: plover/gui_qt/paper_tape.py:237 +#: plover/gui_qt/paper_tape.py:234 msgid "Do you want to clear the paper tape?" msgstr "¿Quieres limpiar la tira de papel?" -#: plover/gui_qt/paper_tape.py:255 +#: plover/gui_qt/paper_tape.py:254 msgid "Save Paper Tape" msgstr "Guardar tira de papel" #. Paper tape, "save" file picker. -#: plover/gui_qt/paper_tape.py:258 +#: plover/gui_qt/paper_tape.py:257 msgid "Text files (*.txt)" msgstr "Ficheros de texto (*.txt)" @@ -1347,22 +1347,22 @@ msgid "N/A" msgstr "N/D" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:127 +#: plover/gui_qt/plugins_manager.py:126 #, python-format msgid "

Author: %s

" msgstr "

Autor: %s

" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:133 +#: plover/gui_qt/plugins_manager.py:132 #, python-format msgid "

Home page: %s

" msgstr "

Página principal: %s

" -#: plover/gui_qt/plugins_manager.py:180 +#: plover/gui_qt/plugins_manager.py:179 msgid "Install from Git repo" msgstr "Instalar desde un repositorio Git" -#: plover/gui_qt/plugins_manager.py:182 +#: plover/gui_qt/plugins_manager.py:181 msgid "" "WARNING: Installing plugins is a security risk.
A plugin from a Git" " repo can contain malicious code.
Only install it if you got it from a" @@ -1376,12 +1376,12 @@ msgstr "" "complemento
(se verá similar a " "https://github.com/usuario/repositorio.git):
" -#: plover/gui_qt/plugins_manager.py:204 +#: plover/gui_qt/plugins_manager.py:203 #, python-brace-format msgid "Install {packages}" msgstr "Instalar {packages}" -#: plover/gui_qt/plugins_manager.py:206 +#: plover/gui_qt/plugins_manager.py:205 msgid "" "Installing plugins is a security risk. A plugin can contain " "virus/malware. Only install it if you got it from a trusted source. Are " @@ -1391,12 +1391,12 @@ msgstr "" "complemento puede contener virus o malware. Solo instálelo si lo obtuvo " "de una fuente confiable. ¿Está seguro de que desea continuar?" -#: plover/gui_qt/plugins_manager.py:233 +#: plover/gui_qt/plugins_manager.py:232 #, python-brace-format msgid "Uninstall {packages}" msgstr "Desinstalar {packages}" -#: plover/gui_qt/plugins_manager.py:234 +#: plover/gui_qt/plugins_manager.py:233 msgid "Are you sure you want to proceed?" msgstr "¿Está seguro de que desea continuar?" @@ -1437,23 +1437,23 @@ msgid "..." msgstr "..." #. Widget: “SuggestionsDialog”, tooltip. -#: plover/gui_qt/suggestions_dialog.py:26 +#: plover/gui_qt/suggestions_dialog.py:25 msgid "Suggest possible strokes for the last written words." msgstr "Sugerir posibles acordes para las últimas palabras escritas." #. Widget: “SuggestionsDialog”, accessible name. -#: plover/gui_qt/suggestions_dialog.py:28 +#: plover/gui_qt/suggestions_dialog.py:27 #: plover/gui_qt/suggestions_dialog_ui.py:97 msgid "Suggestions" msgstr "Sugerencias" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:62 +#: plover/gui_qt/suggestions_dialog.py:61 msgid "&Text" msgstr "&Texto" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:64 +#: plover/gui_qt/suggestions_dialog.py:63 msgid "&Strokes" msgstr "Acorde&s" @@ -1463,7 +1463,7 @@ msgid "Clear the history." msgstr "Vaciar el historial." #. Widget: “SuggestionsWidget”. -#: plover/gui_qt/suggestions_widget.py:27 +#: plover/gui_qt/suggestions_widget.py:26 msgid "no suggestions" msgstr "no hay sugerencias" @@ -1507,7 +1507,7 @@ msgid "disconnected" msgstr "desconectada" #. Machine name. -#: plover/machine/keyboard.py:16 +#: plover/machine/keyboard.py:14 msgid "Keyboard" msgstr "Teclado" diff --git a/plover/messages/fr/LC_MESSAGES/plover.po b/plover/messages/fr/LC_MESSAGES/plover.po index 1fe2ea1d3..d70e13cfb 100644 --- a/plover/messages/fr/LC_MESSAGES/plover.po +++ b/plover/messages/fr/LC_MESSAGES/plover.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: plover 5.4.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-07-10 08:01+0200\n" +"POT-Creation-Date: 2026-07-26 08:22+0200\n" "PO-Revision-Date: 2026-03-08 12:00+0100\n" "Last-Translator: Gemini CLI\n" "Language: fr\n" @@ -76,12 +76,12 @@ msgstr "Plover: À propos" #. Widget: “AddTranslationDialog”, tooltip. #. Widget: “AddTranslationWidget”, tooltip. -#: plover/gui_qt/add_translation_dialog.py:11 -#: plover/gui_qt/add_translation_widget.py:24 +#: plover/gui_qt/add_translation_dialog.py:10 +#: plover/gui_qt/add_translation_widget.py:22 msgid "Add a new translation to the dictionary." msgstr "Ajoute une nouvelle traduction au dictionnaire." -#: plover/gui_qt/add_translation_dialog.py:13 +#: plover/gui_qt/add_translation_dialog.py:12 msgid "Add Translation" msgstr "Ajouter une traduction" @@ -128,7 +128,7 @@ msgstr "Accords :" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:132 -#: plover/gui_qt/dictionary_editor.py:170 +#: plover/gui_qt/dictionary_editor.py:169 msgid "Strokes" msgstr "Accords" @@ -140,7 +140,7 @@ msgstr "Traduction :" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:138 -#: plover/gui_qt/dictionary_editor.py:173 +#: plover/gui_qt/dictionary_editor.py:172 msgid "Translation" msgstr "Traduction" @@ -152,7 +152,7 @@ msgstr "Dictionnaire:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:144 -#: plover/gui_qt/dictionary_editor.py:176 +#: plover/gui_qt/dictionary_editor.py:175 msgid "Dictionary" msgstr "Dictionnaire" @@ -380,51 +380,51 @@ msgstr "RTS/CTS" #. Widget: “NopeOption” (empty config option message, #. e.g. the machine option when selecting the Treal machine). -#: plover/gui_qt/config_window.py:52 +#: plover/gui_qt/config_window.py:49 msgid "Nothing to see here!" msgstr "Rien à voir ici !" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:174 +#: plover/gui_qt/config_window.py:171 msgid "Key" msgstr "Touche" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:176 +#: plover/gui_qt/config_window.py:173 msgid "Action" msgstr "Action" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:222 +#: plover/gui_qt/config_window.py:219 msgid "Selected" msgstr "Sélectionné" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:224 +#: plover/gui_qt/config_window.py:221 msgid "Choice" msgstr "Choix" -#: plover/gui_qt/config_window.py:355 +#: plover/gui_qt/config_window.py:352 msgid "Interface" msgstr "Interface" -#: plover/gui_qt/config_window.py:358 +#: plover/gui_qt/config_window.py:355 msgid "Appearance:" msgstr "Apparence :" -#: plover/gui_qt/config_window.py:363 plover/gui_qt/config_window.py:587 +#: plover/gui_qt/config_window.py:360 plover/gui_qt/config_window.py:584 msgid "System" msgstr "Système" -#: plover/gui_qt/config_window.py:364 +#: plover/gui_qt/config_window.py:361 msgid "Light" msgstr "Clair" -#: plover/gui_qt/config_window.py:365 +#: plover/gui_qt/config_window.py:362 msgid "Dark" msgstr "Sombre" -#: plover/gui_qt/config_window.py:369 +#: plover/gui_qt/config_window.py:366 msgid "" "Set the application appearance:\n" "- System: follow the operating system mode\n" @@ -436,35 +436,35 @@ msgstr "" "- Clair : force le mode clair\n" "- Sombre : force le mode sombre" -#: plover/gui_qt/config_window.py:376 +#: plover/gui_qt/config_window.py:373 msgid "Start minimized:" msgstr "Démarrer minimisé :" -#: plover/gui_qt/config_window.py:379 +#: plover/gui_qt/config_window.py:376 msgid "Minimize the main window to systray on startup." msgstr "Minimise la fenêtre principale au démarrage." -#: plover/gui_qt/config_window.py:382 +#: plover/gui_qt/config_window.py:379 msgid "Show paper tape:" msgstr "Afficher la bande papier :" -#: plover/gui_qt/config_window.py:385 +#: plover/gui_qt/config_window.py:382 msgid "Open the paper tape on startup." msgstr "Ouvre la bande papier au démarrage." -#: plover/gui_qt/config_window.py:388 +#: plover/gui_qt/config_window.py:385 msgid "Show suggestions:" msgstr "Afficher les suggestions :" -#: plover/gui_qt/config_window.py:391 +#: plover/gui_qt/config_window.py:388 msgid "Open the suggestions dialog on startup." msgstr "Ouvre la fenêtre des suggestions au démarrage." -#: plover/gui_qt/config_window.py:394 +#: plover/gui_qt/config_window.py:391 msgid "Add translation dialog opacity:" msgstr "Opacité de la fenêtre d'ajout de traduction :" -#: plover/gui_qt/config_window.py:398 +#: plover/gui_qt/config_window.py:395 msgid "" "Set the translation dialog opacity:\n" "- 0 makes the dialog invisible.\n" @@ -474,19 +474,19 @@ msgstr "" "- 0 pour la rendre invisible.\n" "- 100 pour une fenêtre complètement opaque." -#: plover/gui_qt/config_window.py:404 +#: plover/gui_qt/config_window.py:401 msgid "Dictionaries display order:" msgstr "Sens d'affichage des dictionnaires :" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "top-down" msgstr "haut-en-bas" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "bottom-up" msgstr "bas-en-haut" -#: plover/gui_qt/config_window.py:410 +#: plover/gui_qt/config_window.py:407 msgid "" "Set the display order for dictionaries:\n" "- top-down: Match the search order; highest priority first.\n" @@ -498,77 +498,77 @@ msgstr "" "- bas-en-haut : Dans l'ordre inverse de recherche ; par priorité " "croissante.\n" -#: plover/gui_qt/config_window.py:419 +#: plover/gui_qt/config_window.py:416 msgid "Logging" msgstr "Journal" -#: plover/gui_qt/config_window.py:422 +#: plover/gui_qt/config_window.py:419 msgid "Log file:" msgstr "Fichier :" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Select a log file" msgstr "Sélectionner un fichier de journal" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Log files (*.log)" msgstr "Fichiers de journal (*.log)" -#: plover/gui_qt/config_window.py:427 +#: plover/gui_qt/config_window.py:424 msgid "File to use for logging strokes/translations." msgstr "Fichier à utiliser pour la journalisation des accords/traductions." -#: plover/gui_qt/config_window.py:430 +#: plover/gui_qt/config_window.py:427 msgid "Log strokes:" msgstr "Enregistrer les accords :" -#: plover/gui_qt/config_window.py:433 +#: plover/gui_qt/config_window.py:430 msgid "Save strokes to the logfile." msgstr "Enregistre les accords dans le journal." -#: plover/gui_qt/config_window.py:436 +#: plover/gui_qt/config_window.py:433 msgid "Log translations:" msgstr "Enregistrer les traductions :" -#: plover/gui_qt/config_window.py:439 +#: plover/gui_qt/config_window.py:436 msgid "Save translations to the logfile." msgstr "Enregistre les traductions dans le journal." #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:445 plover/gui_qt/main_window_ui.py:260 +#: plover/gui_qt/config_window.py:442 plover/gui_qt/main_window_ui.py:260 msgid "Machine" msgstr "Machine" -#: plover/gui_qt/config_window.py:448 +#: plover/gui_qt/config_window.py:445 msgid "Machine:" msgstr "Machine :" -#: plover/gui_qt/config_window.py:460 +#: plover/gui_qt/config_window.py:457 msgid "Options:" msgstr "Paramètres :" -#: plover/gui_qt/config_window.py:462 +#: plover/gui_qt/config_window.py:459 msgid "Keymap:" msgstr "Disposition :" #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:467 plover/gui_qt/main_window_ui.py:292 +#: plover/gui_qt/config_window.py:464 plover/gui_qt/main_window_ui.py:292 msgid "Output" msgstr "Sortie" -#: plover/gui_qt/config_window.py:470 +#: plover/gui_qt/config_window.py:467 msgid "Enable at start:" msgstr "Activer au démarrage :" -#: plover/gui_qt/config_window.py:473 +#: plover/gui_qt/config_window.py:470 msgid "Enable output on startup." msgstr "Active la sortie au démarrage." -#: plover/gui_qt/config_window.py:476 +#: plover/gui_qt/config_window.py:473 msgid "Start attached:" msgstr "Supprimer l'espace initial :" -#: plover/gui_qt/config_window.py:480 +#: plover/gui_qt/config_window.py:477 msgid "" "Disable preceding space on first output.\n" "\n" @@ -579,35 +579,35 @@ msgstr "" "Cette option n'a de sens que lorsque le placement\n" "des espaces s'effectue avant chaque mot." -#: plover/gui_qt/config_window.py:486 +#: plover/gui_qt/config_window.py:483 msgid "Start capitalized:" msgstr "Capitaliser le premier mot :" -#: plover/gui_qt/config_window.py:489 +#: plover/gui_qt/config_window.py:486 msgid "Capitalize the first word." msgstr "Capitalise le premier mot." -#: plover/gui_qt/config_window.py:492 +#: plover/gui_qt/config_window.py:489 msgid "Space placement:" msgstr "Placement de l'espace :" -#: plover/gui_qt/config_window.py:497 +#: plover/gui_qt/config_window.py:494 msgid "Before Output" msgstr "Avant la traduction" -#: plover/gui_qt/config_window.py:498 +#: plover/gui_qt/config_window.py:495 msgid "After Output" msgstr "Après la traduction" -#: plover/gui_qt/config_window.py:501 +#: plover/gui_qt/config_window.py:498 msgid "Set automatic space placement: before or after each word." msgstr "Définie le placement automatique des espaces: avant ou après chaque mot." -#: plover/gui_qt/config_window.py:504 +#: plover/gui_qt/config_window.py:501 msgid "Undo levels:" msgstr "Niveaux d'annulation :" -#: plover/gui_qt/config_window.py:508 +#: plover/gui_qt/config_window.py:505 msgid "" "Set how many preceding strokes can be undone.\n" "\n" @@ -620,11 +620,11 @@ msgstr "" "N.B.: le nombre effectif prend en compte l'entrée des dictionnaires " "nécessitant le plus d'accords." -#: plover/gui_qt/config_window.py:515 +#: plover/gui_qt/config_window.py:512 msgid "Key press delay (ms):" msgstr "Délai de pression des touches (ms) :" -#: plover/gui_qt/config_window.py:523 +#: plover/gui_qt/config_window.py:520 msgid "" "Set the delay between emulated key presses (in milliseconds).\n" "\n" @@ -644,11 +644,11 @@ msgstr "" "Définir un délai trop élevé aura un impact négatif sur les\n" "performances de sortie des touches." -#: plover/gui_qt/config_window.py:533 +#: plover/gui_qt/config_window.py:530 msgid "Linux keyboard layout:" msgstr "Disposition du clavier Linux :" -#: plover/gui_qt/config_window.py:547 +#: plover/gui_qt/config_window.py:544 msgid "" "Set the keyboard layout configured in your system.\n" "This only applies when using Linux/BSD and not using X11.\n" @@ -665,7 +665,7 @@ msgstr "" "peut détecter que la première disposition du clavier\n" "et ne peut pas détecter les changements de disposition." -#: plover/gui_qt/config_window.py:557 +#: plover/gui_qt/config_window.py:554 msgid "" "When Wayland auto detect is selected, Plover is only able to detect the " "first keyboard layout and can not detect layout switches." @@ -674,29 +674,29 @@ msgstr "" "peut détecter que la première disposition du clavier et ne peut pas " "détecter les changements de disposition." -#: plover/gui_qt/config_window.py:568 +#: plover/gui_qt/config_window.py:565 msgid "Plugins" msgstr "Greffons" -#: plover/gui_qt/config_window.py:571 +#: plover/gui_qt/config_window.py:568 msgid "Extensions:" msgstr "Extensions :" #. Widget: “MainWindow”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/main_window_ui.py:294 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/main_window_ui.py:294 msgid "Enabled" msgstr "Activée" #. Widget: “PluginsManager”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/plugins_manager_ui.py:137 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/plugins_manager_ui.py:137 msgid "Name" msgstr "Nom" -#: plover/gui_qt/config_window.py:581 +#: plover/gui_qt/config_window.py:578 msgid "Configure enabled plugin extensions." msgstr "Configure les extensions activées." -#: plover/gui_qt/config_window.py:590 +#: plover/gui_qt/config_window.py:587 msgid "System:" msgstr "Système :" @@ -723,84 +723,84 @@ msgid "{format} dictionaries ({extensions})" msgstr "Dictionnaires {format} ({extensions})" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:391 +#: plover/gui_qt/dictionaries_widget.py:393 msgid "disabled" msgstr "désactivé" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:394 +#: plover/gui_qt/dictionaries_widget.py:396 msgid "favorite" msgstr "favori" -#: plover/gui_qt/dictionaries_widget.py:398 +#: plover/gui_qt/dictionaries_widget.py:400 #, python-brace-format msgid "errored: {exception}." msgstr "erreur : {exception}" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:402 +#: plover/gui_qt/dictionaries_widget.py:404 msgid "loading" msgstr "chargement" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:405 +#: plover/gui_qt/dictionaries_widget.py:407 msgid "read-only" msgstr "lecture seule" #. Widget: “DictionariesWidget”, tooltip. -#: plover/gui_qt/dictionaries_widget.py:411 +#: plover/gui_qt/dictionaries_widget.py:413 #, python-brace-format msgid "Full path: {path}." msgstr "Chemin complet : {path}." # | msgid "This dictionary is marked as a favorite." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:414 +#: plover/gui_qt/dictionaries_widget.py:416 msgid "This dictionary is marked as the favorite." msgstr "Ce dictionnaire est marqué comme favori." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:417 +#: plover/gui_qt/dictionaries_widget.py:419 msgid "This dictionary is being loaded." msgstr "Ce dictionnaire est en cours de chargement." -#: plover/gui_qt/dictionaries_widget.py:421 +#: plover/gui_qt/dictionaries_widget.py:423 #, python-brace-format msgid "Loading this dictionary failed: {exception}." msgstr "Erreur lors du chargement du dictionnaire : {exception}." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:427 +#: plover/gui_qt/dictionaries_widget.py:429 msgid "This dictionary is read-only." msgstr "Ce dictionnaire est en lecture-seule." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:618 +#: plover/gui_qt/dictionaries_widget.py:620 #, python-brace-format msgid "Save a copy of {name} as..." msgstr "Enregistrez une copie de {name} sous..." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:620 +#: plover/gui_qt/dictionaries_widget.py:622 #, python-brace-format msgid "{name} - Copy" msgstr "{name} - Copie" #. Widget: “DictionariesWidget”, “save as merge” file picker. -#: plover/gui_qt/dictionaries_widget.py:642 +#: plover/gui_qt/dictionaries_widget.py:644 #, python-brace-format msgid "Merge {names} as..." msgstr "Fusionner {names} sous..." #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:671 +#: plover/gui_qt/dictionaries_widget.py:673 #: plover/gui_qt/dictionaries_widget_ui.py:203 msgid "Load dictionaries" msgstr "Charger des dictionnaires" #. Widget: “DictionariesWidget”, “new” file picker. #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:683 +#: plover/gui_qt/dictionaries_widget.py:685 #: plover/gui_qt/dictionaries_widget_ui.py:205 msgid "Create dictionary" msgstr "Créer un dictionnaire" @@ -1026,11 +1026,11 @@ msgid "Mappings" msgstr "Traductions" #. Widget: “LookupDialog”, tooltip. -#: plover/gui_qt/lookup_dialog.py:12 +#: plover/gui_qt/lookup_dialog.py:11 msgid "Search the dictionary for translations." msgstr "Cherche les traductions du dictionnaire." -#: plover/gui_qt/lookup_dialog.py:14 +#: plover/gui_qt/lookup_dialog.py:13 msgid "Lookup" msgstr "Recherche" @@ -1054,27 +1054,27 @@ msgstr "Motif de traduction à rechercher." msgid "Results" msgstr "Résultats" -#: plover/gui_qt/machine_options.py:38 +#: plover/gui_qt/machine_options.py:36 #, python-brace-format msgid "product: {value}" msgstr "produit : {value}" -#: plover/gui_qt/machine_options.py:39 +#: plover/gui_qt/machine_options.py:37 #, python-brace-format msgid "manufacturer: {value}" msgstr "fabricant : {value}" -#: plover/gui_qt/machine_options.py:40 +#: plover/gui_qt/machine_options.py:38 #, python-brace-format msgid "serial number: {value}" msgstr "numéro de série : {value}" -#: plover/gui_qt/machine_options.py:48 +#: plover/gui_qt/machine_options.py:46 #, python-brace-format msgid "description: {value}" msgstr "description : {value}" -#: plover/gui_qt/machine_options.py:201 +#: plover/gui_qt/machine_options.py:199 msgid "" "Arpeggiate allows using non-NKRO keyboards.\n" "\n" @@ -1086,7 +1086,7 @@ msgstr "" "Chaque touche peut alors être frappée individuellement,\n" "et la barre d'espace utilisée pour terminer l'accord." -#: plover/gui_qt/main_window.py:312 +#: plover/gui_qt/main_window.py:310 msgid "Application is still running." msgstr "L'application est encore en cours d'exécution." @@ -1239,34 +1239,34 @@ msgid "Plover: Toolbar" msgstr "Plover: Bar d'outils" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:30 +#: plover/gui_qt/paper_tape.py:27 msgid "Paper" msgstr "Papier" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:32 +#: plover/gui_qt/paper_tape.py:29 msgid "Raw" msgstr "Brut" #. Widget: “PaperTape”, tooltip. -#: plover/gui_qt/paper_tape.py:122 +#: plover/gui_qt/paper_tape.py:119 msgid "Paper tape display of strokes." msgstr "Affichage des entrées du ruban." -#: plover/gui_qt/paper_tape.py:124 +#: plover/gui_qt/paper_tape.py:121 msgid "Paper Tape" msgstr "Bande papier" -#: plover/gui_qt/paper_tape.py:237 +#: plover/gui_qt/paper_tape.py:234 msgid "Do you want to clear the paper tape?" msgstr "Voulez vous effacer l'historique de la bande papier?" -#: plover/gui_qt/paper_tape.py:255 +#: plover/gui_qt/paper_tape.py:254 msgid "Save Paper Tape" msgstr "Enregistrer la bande papier" #. Paper tape, "save" file picker. -#: plover/gui_qt/paper_tape.py:258 +#: plover/gui_qt/paper_tape.py:257 msgid "Text files (*.txt)" msgstr "Fichiers texte (*.txt)" @@ -1356,22 +1356,22 @@ msgid "N/A" msgstr "N/A" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:127 +#: plover/gui_qt/plugins_manager.py:126 #, python-format msgid "

Author: %s

" msgstr "

Auteur : %s

" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:133 +#: plover/gui_qt/plugins_manager.py:132 #, python-format msgid "

Home page: %s

" msgstr "

Page d'accueil : %s

" -#: plover/gui_qt/plugins_manager.py:180 +#: plover/gui_qt/plugins_manager.py:179 msgid "Install from Git repo" msgstr "Installer depuis un dépôt Git" -#: plover/gui_qt/plugins_manager.py:182 +#: plover/gui_qt/plugins_manager.py:181 msgid "" "WARNING: Installing plugins is a security risk.
A plugin from a Git" " repo can contain malicious code.
Only install it if you got it from a" @@ -1384,12 +1384,12 @@ msgstr "" "fiable.


Entrez le lien du dépôt pour le " "greffon
(ressemblera à https://github.com/user/repository.git) :
" -#: plover/gui_qt/plugins_manager.py:204 +#: plover/gui_qt/plugins_manager.py:203 #, python-brace-format msgid "Install {packages}" msgstr "Installer {packages}" -#: plover/gui_qt/plugins_manager.py:206 +#: plover/gui_qt/plugins_manager.py:205 msgid "" "Installing plugins is a security risk. A plugin can contain " "virus/malware. Only install it if you got it from a trusted source. Are " @@ -1400,12 +1400,12 @@ msgstr "" "l'installez que si vous l'avez obtenu d'une source fiable. Êtes-vous sûr " "de vouloir continuer ?" -#: plover/gui_qt/plugins_manager.py:233 +#: plover/gui_qt/plugins_manager.py:232 #, python-brace-format msgid "Uninstall {packages}" msgstr "Désinstaller {packages}" -#: plover/gui_qt/plugins_manager.py:234 +#: plover/gui_qt/plugins_manager.py:233 msgid "Are you sure you want to proceed?" msgstr "Êtes-vous sûr de vouloir continuer ?" @@ -1446,23 +1446,23 @@ msgid "..." msgstr "..." #. Widget: “SuggestionsDialog”, tooltip. -#: plover/gui_qt/suggestions_dialog.py:26 +#: plover/gui_qt/suggestions_dialog.py:25 msgid "Suggest possible strokes for the last written words." msgstr "Suggère des accords possibles pour les derniers mots écrits." #. Widget: “SuggestionsDialog”, accessible name. -#: plover/gui_qt/suggestions_dialog.py:28 +#: plover/gui_qt/suggestions_dialog.py:27 #: plover/gui_qt/suggestions_dialog_ui.py:97 msgid "Suggestions" msgstr "Suggestions" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:62 +#: plover/gui_qt/suggestions_dialog.py:61 msgid "&Text" msgstr "&Texte" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:64 +#: plover/gui_qt/suggestions_dialog.py:63 msgid "&Strokes" msgstr "&Accords" @@ -1472,7 +1472,7 @@ msgid "Clear the history." msgstr "Efface l'historique." #. Widget: “SuggestionsWidget”. -#: plover/gui_qt/suggestions_widget.py:27 +#: plover/gui_qt/suggestions_widget.py:26 msgid "no suggestions" msgstr "pas de suggestions" @@ -1516,7 +1516,7 @@ msgid "disconnected" msgstr "déconnectée" #. Machine name. -#: plover/machine/keyboard.py:16 +#: plover/machine/keyboard.py:14 msgid "Keyboard" msgstr "Clavier" diff --git a/plover/messages/it/LC_MESSAGES/plover.po b/plover/messages/it/LC_MESSAGES/plover.po index b51096faa..0a4424fd1 100644 --- a/plover/messages/it/LC_MESSAGES/plover.po +++ b/plover/messages/it/LC_MESSAGES/plover.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: plover 5.4.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-07-10 08:01+0200\n" +"POT-Creation-Date: 2026-07-26 08:22+0200\n" "PO-Revision-Date: 2026-03-08 12:00+0100\n" "Last-Translator: Gemini CLI\n" "Language: it\n" @@ -76,12 +76,12 @@ msgstr "Plover: Informazioni" #. Widget: “AddTranslationDialog”, tooltip. #. Widget: “AddTranslationWidget”, tooltip. -#: plover/gui_qt/add_translation_dialog.py:11 -#: plover/gui_qt/add_translation_widget.py:24 +#: plover/gui_qt/add_translation_dialog.py:10 +#: plover/gui_qt/add_translation_widget.py:22 msgid "Add a new translation to the dictionary." msgstr "Aggiungi una nuova traduzione al dizionario." -#: plover/gui_qt/add_translation_dialog.py:13 +#: plover/gui_qt/add_translation_dialog.py:12 msgid "Add Translation" msgstr "Aggiungi traduzione" @@ -128,7 +128,7 @@ msgstr "Battute:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:132 -#: plover/gui_qt/dictionary_editor.py:170 +#: plover/gui_qt/dictionary_editor.py:169 msgid "Strokes" msgstr "Battute" @@ -140,7 +140,7 @@ msgstr "Traduzione:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:138 -#: plover/gui_qt/dictionary_editor.py:173 +#: plover/gui_qt/dictionary_editor.py:172 msgid "Translation" msgstr "Traduzione" @@ -152,7 +152,7 @@ msgstr "Dizionario:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:144 -#: plover/gui_qt/dictionary_editor.py:176 +#: plover/gui_qt/dictionary_editor.py:175 msgid "Dictionary" msgstr "Dizionario" @@ -379,51 +379,51 @@ msgstr "RTS/CTS" #. Widget: “NopeOption” (empty config option message, #. e.g. the machine option when selecting the Treal machine). -#: plover/gui_qt/config_window.py:52 +#: plover/gui_qt/config_window.py:49 msgid "Nothing to see here!" msgstr "Nulla da vedere qui!" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:174 +#: plover/gui_qt/config_window.py:171 msgid "Key" msgstr "Tasto" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:176 +#: plover/gui_qt/config_window.py:173 msgid "Action" msgstr "Azione" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:222 +#: plover/gui_qt/config_window.py:219 msgid "Selected" msgstr "Selezionato" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:224 +#: plover/gui_qt/config_window.py:221 msgid "Choice" msgstr "Scelta" -#: plover/gui_qt/config_window.py:355 +#: plover/gui_qt/config_window.py:352 msgid "Interface" msgstr "Interfaccia" -#: plover/gui_qt/config_window.py:358 +#: plover/gui_qt/config_window.py:355 msgid "Appearance:" msgstr "Aspetto:" -#: plover/gui_qt/config_window.py:363 plover/gui_qt/config_window.py:587 +#: plover/gui_qt/config_window.py:360 plover/gui_qt/config_window.py:584 msgid "System" msgstr "Sistema" -#: plover/gui_qt/config_window.py:364 +#: plover/gui_qt/config_window.py:361 msgid "Light" msgstr "Chiaro" -#: plover/gui_qt/config_window.py:365 +#: plover/gui_qt/config_window.py:362 msgid "Dark" msgstr "Scuro" -#: plover/gui_qt/config_window.py:369 +#: plover/gui_qt/config_window.py:366 msgid "" "Set the application appearance:\n" "- System: follow the operating system mode\n" @@ -435,35 +435,35 @@ msgstr "" "- Chiaro: forza la modalità chiara\n" "- Scuro: forza la modalità scura" -#: plover/gui_qt/config_window.py:376 +#: plover/gui_qt/config_window.py:373 msgid "Start minimized:" msgstr "Avvia ridotto a icona:" -#: plover/gui_qt/config_window.py:379 +#: plover/gui_qt/config_window.py:376 msgid "Minimize the main window to systray on startup." msgstr "Riduci la finestra principale nella systray all'avvio." -#: plover/gui_qt/config_window.py:382 +#: plover/gui_qt/config_window.py:379 msgid "Show paper tape:" msgstr "Mostra nastro di carta:" -#: plover/gui_qt/config_window.py:385 +#: plover/gui_qt/config_window.py:382 msgid "Open the paper tape on startup." msgstr "Apri il nastro di carta all'avvio." -#: plover/gui_qt/config_window.py:388 +#: plover/gui_qt/config_window.py:385 msgid "Show suggestions:" msgstr "Mostra suggerimenti:" -#: plover/gui_qt/config_window.py:391 +#: plover/gui_qt/config_window.py:388 msgid "Open the suggestions dialog on startup." msgstr "Apri la finestra dei suggerimenti all'avvio." -#: plover/gui_qt/config_window.py:394 +#: plover/gui_qt/config_window.py:391 msgid "Add translation dialog opacity:" msgstr "Opacità finestra aggiunta traduzione:" -#: plover/gui_qt/config_window.py:398 +#: plover/gui_qt/config_window.py:395 msgid "" "Set the translation dialog opacity:\n" "- 0 makes the dialog invisible.\n" @@ -473,19 +473,19 @@ msgstr "" "- 0 rende la finestra invisibile.\n" "- 100 è completamente opaco." -#: plover/gui_qt/config_window.py:404 +#: plover/gui_qt/config_window.py:401 msgid "Dictionaries display order:" msgstr "Ordine di visualizzazione dizionari:" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "top-down" msgstr "dall'alto in basso" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "bottom-up" msgstr "dal basso in alto" -#: plover/gui_qt/config_window.py:410 +#: plover/gui_qt/config_window.py:407 msgid "" "Set the display order for dictionaries:\n" "- top-down: Match the search order; highest priority first.\n" @@ -497,77 +497,77 @@ msgstr "" "- dal basso in alto: Ordine di ricerca inverso; priorità più bassa per " "prima.\n" -#: plover/gui_qt/config_window.py:419 +#: plover/gui_qt/config_window.py:416 msgid "Logging" msgstr "Log" -#: plover/gui_qt/config_window.py:422 +#: plover/gui_qt/config_window.py:419 msgid "Log file:" msgstr "File di log:" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Select a log file" msgstr "Seleziona un file di log" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Log files (*.log)" msgstr "File di log (*.log)" -#: plover/gui_qt/config_window.py:427 +#: plover/gui_qt/config_window.py:424 msgid "File to use for logging strokes/translations." msgstr "File da utilizzare per il log di battute/traduzioni." -#: plover/gui_qt/config_window.py:430 +#: plover/gui_qt/config_window.py:427 msgid "Log strokes:" msgstr "Log battute:" -#: plover/gui_qt/config_window.py:433 +#: plover/gui_qt/config_window.py:430 msgid "Save strokes to the logfile." msgstr "Salva le battute nel file di log." -#: plover/gui_qt/config_window.py:436 +#: plover/gui_qt/config_window.py:433 msgid "Log translations:" msgstr "Log traduzioni:" -#: plover/gui_qt/config_window.py:439 +#: plover/gui_qt/config_window.py:436 msgid "Save translations to the logfile." msgstr "Salva le traduzioni nel file di log." #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:445 plover/gui_qt/main_window_ui.py:260 +#: plover/gui_qt/config_window.py:442 plover/gui_qt/main_window_ui.py:260 msgid "Machine" msgstr "Macchina" -#: plover/gui_qt/config_window.py:448 +#: plover/gui_qt/config_window.py:445 msgid "Machine:" msgstr "Macchina:" -#: plover/gui_qt/config_window.py:460 +#: plover/gui_qt/config_window.py:457 msgid "Options:" msgstr "Opzioni:" -#: plover/gui_qt/config_window.py:462 +#: plover/gui_qt/config_window.py:459 msgid "Keymap:" msgstr "Mappatura tasti:" #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:467 plover/gui_qt/main_window_ui.py:292 +#: plover/gui_qt/config_window.py:464 plover/gui_qt/main_window_ui.py:292 msgid "Output" msgstr "Uscita" -#: plover/gui_qt/config_window.py:470 +#: plover/gui_qt/config_window.py:467 msgid "Enable at start:" msgstr "Abilita all'avvio:" -#: plover/gui_qt/config_window.py:473 +#: plover/gui_qt/config_window.py:470 msgid "Enable output on startup." msgstr "Abilita l'uscita all'avvio." -#: plover/gui_qt/config_window.py:476 +#: plover/gui_qt/config_window.py:473 msgid "Start attached:" msgstr "Inizia senza spazio:" -#: plover/gui_qt/config_window.py:480 +#: plover/gui_qt/config_window.py:477 msgid "" "Disable preceding space on first output.\n" "\n" @@ -577,37 +577,37 @@ msgstr "" "\n" "Questa opzione è applicabile solo quando gli spazi sono posizionati prima." -#: plover/gui_qt/config_window.py:486 +#: plover/gui_qt/config_window.py:483 msgid "Start capitalized:" msgstr "Inizia con la maiuscola:" -#: plover/gui_qt/config_window.py:489 +#: plover/gui_qt/config_window.py:486 msgid "Capitalize the first word." msgstr "Scrivi la prima parola con la maiuscola." -#: plover/gui_qt/config_window.py:492 +#: plover/gui_qt/config_window.py:489 msgid "Space placement:" msgstr "Posizionamento spazio:" -#: plover/gui_qt/config_window.py:497 +#: plover/gui_qt/config_window.py:494 msgid "Before Output" msgstr "Prima dell'uscita" -#: plover/gui_qt/config_window.py:498 +#: plover/gui_qt/config_window.py:495 msgid "After Output" msgstr "Dopo l'uscita" -#: plover/gui_qt/config_window.py:501 +#: plover/gui_qt/config_window.py:498 msgid "Set automatic space placement: before or after each word." msgstr "" "Imposta il posizionamento automatico dello spazio: prima o dopo ogni " "parola." -#: plover/gui_qt/config_window.py:504 +#: plover/gui_qt/config_window.py:501 msgid "Undo levels:" msgstr "Livelli di annullamento:" -#: plover/gui_qt/config_window.py:508 +#: plover/gui_qt/config_window.py:505 msgid "" "Set how many preceding strokes can be undone.\n" "\n" @@ -619,11 +619,11 @@ msgstr "" "Nota: il valore effettivo terrà conto della voce\n" "dei dizionari con il numero massimo di battute." -#: plover/gui_qt/config_window.py:515 +#: plover/gui_qt/config_window.py:512 msgid "Key press delay (ms):" msgstr "Ritardo pressione tasti (ms):" -#: plover/gui_qt/config_window.py:523 +#: plover/gui_qt/config_window.py:520 msgid "" "Set the delay between emulated key presses (in milliseconds).\n" "\n" @@ -642,11 +642,11 @@ msgstr "" "Impostare un ritardo troppo alto influirà negativamente sulle\n" "prestazioni dell'uscita delle battute." -#: plover/gui_qt/config_window.py:533 +#: plover/gui_qt/config_window.py:530 msgid "Linux keyboard layout:" msgstr "Layout tastiera Linux:" -#: plover/gui_qt/config_window.py:547 +#: plover/gui_qt/config_window.py:544 msgid "" "Set the keyboard layout configured in your system.\n" "This only applies when using Linux/BSD and not using X11.\n" @@ -663,7 +663,7 @@ msgstr "" "grado di rilevare solo il primo layout di tastiera\n" "e non può rilevare i cambi di layout." -#: plover/gui_qt/config_window.py:557 +#: plover/gui_qt/config_window.py:554 msgid "" "When Wayland auto detect is selected, Plover is only able to detect the " "first keyboard layout and can not detect layout switches." @@ -672,29 +672,29 @@ msgstr "" "grado di rilevare solo il primo layout di tastiera e non può rilevare i " "cambi di layout." -#: plover/gui_qt/config_window.py:568 +#: plover/gui_qt/config_window.py:565 msgid "Plugins" msgstr "Plugin" -#: plover/gui_qt/config_window.py:571 +#: plover/gui_qt/config_window.py:568 msgid "Extensions:" msgstr "Estensioni:" #. Widget: “MainWindow”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/main_window_ui.py:294 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/main_window_ui.py:294 msgid "Enabled" msgstr "Abilitata" #. Widget: “PluginsManager”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/plugins_manager_ui.py:137 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/plugins_manager_ui.py:137 msgid "Name" msgstr "Nome" -#: plover/gui_qt/config_window.py:581 +#: plover/gui_qt/config_window.py:578 msgid "Configure enabled plugin extensions." msgstr "Configura le estensioni dei plugin abilitate." -#: plover/gui_qt/config_window.py:590 +#: plover/gui_qt/config_window.py:587 msgid "System:" msgstr "Sistema:" @@ -721,83 +721,83 @@ msgid "{format} dictionaries ({extensions})" msgstr "Dizionari {format} ({extensions})" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:391 +#: plover/gui_qt/dictionaries_widget.py:393 msgid "disabled" msgstr "disabilitato" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:394 +#: plover/gui_qt/dictionaries_widget.py:396 msgid "favorite" msgstr "preferito" -#: plover/gui_qt/dictionaries_widget.py:398 +#: plover/gui_qt/dictionaries_widget.py:400 #, python-brace-format msgid "errored: {exception}." msgstr "errore: {exception}." #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:402 +#: plover/gui_qt/dictionaries_widget.py:404 msgid "loading" msgstr "caricamento" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:405 +#: plover/gui_qt/dictionaries_widget.py:407 msgid "read-only" msgstr "sola lettura" #. Widget: “DictionariesWidget”, tooltip. -#: plover/gui_qt/dictionaries_widget.py:411 +#: plover/gui_qt/dictionaries_widget.py:413 #, python-brace-format msgid "Full path: {path}." msgstr "Percorso completo: {path}." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:414 +#: plover/gui_qt/dictionaries_widget.py:416 msgid "This dictionary is marked as the favorite." msgstr "Questo dizionario è contrassegnato come preferito." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:417 +#: plover/gui_qt/dictionaries_widget.py:419 msgid "This dictionary is being loaded." msgstr "Caricamento di questo dizionario in corso." -#: plover/gui_qt/dictionaries_widget.py:421 +#: plover/gui_qt/dictionaries_widget.py:423 #, python-brace-format msgid "Loading this dictionary failed: {exception}." msgstr "Caricamento di questo dizionario fallito: {exception}." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:427 +#: plover/gui_qt/dictionaries_widget.py:429 msgid "This dictionary is read-only." msgstr "Questo dizionario è in sola lettura." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:618 +#: plover/gui_qt/dictionaries_widget.py:620 #, python-brace-format msgid "Save a copy of {name} as..." msgstr "Salva una copia di {name} come..." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:620 +#: plover/gui_qt/dictionaries_widget.py:622 #, python-brace-format msgid "{name} - Copy" msgstr "{name} - Copia" #. Widget: “DictionariesWidget”, “save as merge” file picker. -#: plover/gui_qt/dictionaries_widget.py:642 +#: plover/gui_qt/dictionaries_widget.py:644 #, python-brace-format msgid "Merge {names} as..." msgstr "Unisci {names} come..." #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:671 +#: plover/gui_qt/dictionaries_widget.py:673 #: plover/gui_qt/dictionaries_widget_ui.py:203 msgid "Load dictionaries" msgstr "Carica dizionari" #. Widget: “DictionariesWidget”, “new” file picker. #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:683 +#: plover/gui_qt/dictionaries_widget.py:685 #: plover/gui_qt/dictionaries_widget_ui.py:205 msgid "Create dictionary" msgstr "Crea dizionario" @@ -1023,11 +1023,11 @@ msgid "Mappings" msgstr "Associazioni" #. Widget: “LookupDialog”, tooltip. -#: plover/gui_qt/lookup_dialog.py:12 +#: plover/gui_qt/lookup_dialog.py:11 msgid "Search the dictionary for translations." msgstr "Cerca le traduzioni nel dizionario." -#: plover/gui_qt/lookup_dialog.py:14 +#: plover/gui_qt/lookup_dialog.py:13 msgid "Lookup" msgstr "Ricerca" @@ -1051,27 +1051,27 @@ msgstr "Modello di traduzione da cercare." msgid "Results" msgstr "Risultati" -#: plover/gui_qt/machine_options.py:38 +#: plover/gui_qt/machine_options.py:36 #, python-brace-format msgid "product: {value}" msgstr "prodotto: {value}" -#: plover/gui_qt/machine_options.py:39 +#: plover/gui_qt/machine_options.py:37 #, python-brace-format msgid "manufacturer: {value}" msgstr "produttore: {value}" -#: plover/gui_qt/machine_options.py:40 +#: plover/gui_qt/machine_options.py:38 #, python-brace-format msgid "serial number: {value}" msgstr "numero di serie: {value}" -#: plover/gui_qt/machine_options.py:48 +#: plover/gui_qt/machine_options.py:46 #, python-brace-format msgid "description: {value}" msgstr "descrizione: {value}" -#: plover/gui_qt/machine_options.py:201 +#: plover/gui_qt/machine_options.py:199 msgid "" "Arpeggiate allows using non-NKRO keyboards.\n" "\n" @@ -1083,7 +1083,7 @@ msgstr "" "Ogni tasto può essere premuto separatamente e la\n" "barra spaziatrice viene premuta per inviare la battuta." -#: plover/gui_qt/main_window.py:312 +#: plover/gui_qt/main_window.py:310 msgid "Application is still running." msgstr "L'applicazione è ancora in esecuzione." @@ -1236,34 +1236,34 @@ msgid "Plover: Toolbar" msgstr "Plover: Barra degli strumenti" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:30 +#: plover/gui_qt/paper_tape.py:27 msgid "Paper" msgstr "Carta" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:32 +#: plover/gui_qt/paper_tape.py:29 msgid "Raw" msgstr "Grezzo" #. Widget: “PaperTape”, tooltip. -#: plover/gui_qt/paper_tape.py:122 +#: plover/gui_qt/paper_tape.py:119 msgid "Paper tape display of strokes." msgstr "Visualizzazione delle battute sul nastro di carta." -#: plover/gui_qt/paper_tape.py:124 +#: plover/gui_qt/paper_tape.py:121 msgid "Paper Tape" msgstr "Nastro di carta" -#: plover/gui_qt/paper_tape.py:237 +#: plover/gui_qt/paper_tape.py:234 msgid "Do you want to clear the paper tape?" msgstr "Vuoi cancellare il nastro di carta?" -#: plover/gui_qt/paper_tape.py:255 +#: plover/gui_qt/paper_tape.py:254 msgid "Save Paper Tape" msgstr "Salva nastro di carta" #. Paper tape, "save" file picker. -#: plover/gui_qt/paper_tape.py:258 +#: plover/gui_qt/paper_tape.py:257 msgid "Text files (*.txt)" msgstr "File di testo (*.txt)" @@ -1353,22 +1353,22 @@ msgid "N/A" msgstr "N/D" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:127 +#: plover/gui_qt/plugins_manager.py:126 #, python-format msgid "

Author: %s

" msgstr "

Autore: %s

" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:133 +#: plover/gui_qt/plugins_manager.py:132 #, python-format msgid "

Home page: %s

" msgstr "

Pagina iniziale: %s

" -#: plover/gui_qt/plugins_manager.py:180 +#: plover/gui_qt/plugins_manager.py:179 msgid "Install from Git repo" msgstr "Installa da repository Git" -#: plover/gui_qt/plugins_manager.py:182 +#: plover/gui_qt/plugins_manager.py:181 msgid "" "WARNING: Installing plugins is a security risk.
A plugin from a Git" " repo can contain malicious code.
Only install it if you got it from a" @@ -1381,12 +1381,12 @@ msgstr "" "attendibile.


Inserisci il link del repository per il " "plugin
(sarà simile a https://github.com/utente/repository.git):
" -#: plover/gui_qt/plugins_manager.py:204 +#: plover/gui_qt/plugins_manager.py:203 #, python-brace-format msgid "Install {packages}" msgstr "Installa {packages}" -#: plover/gui_qt/plugins_manager.py:206 +#: plover/gui_qt/plugins_manager.py:205 msgid "" "Installing plugins is a security risk. A plugin can contain " "virus/malware. Only install it if you got it from a trusted source. Are " @@ -1396,12 +1396,12 @@ msgstr "" " può contenere virus/malware. Installalo solo se lo hai ottenuto da una " "fonte attendibile. Sei sicuro di voler procedere?" -#: plover/gui_qt/plugins_manager.py:233 +#: plover/gui_qt/plugins_manager.py:232 #, python-brace-format msgid "Uninstall {packages}" msgstr "Disinstalla {packages}" -#: plover/gui_qt/plugins_manager.py:234 +#: plover/gui_qt/plugins_manager.py:233 msgid "Are you sure you want to proceed?" msgstr "Sei sicuro di voler procedere?" @@ -1442,23 +1442,23 @@ msgid "..." msgstr "..." #. Widget: “SuggestionsDialog”, tooltip. -#: plover/gui_qt/suggestions_dialog.py:26 +#: plover/gui_qt/suggestions_dialog.py:25 msgid "Suggest possible strokes for the last written words." msgstr "Suggerisce le possibili battute per le ultime parole scritte." #. Widget: “SuggestionsDialog”, accessible name. -#: plover/gui_qt/suggestions_dialog.py:28 +#: plover/gui_qt/suggestions_dialog.py:27 #: plover/gui_qt/suggestions_dialog_ui.py:97 msgid "Suggestions" msgstr "Suggerimenti" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:62 +#: plover/gui_qt/suggestions_dialog.py:61 msgid "&Text" msgstr "&Testo" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:64 +#: plover/gui_qt/suggestions_dialog.py:63 msgid "&Strokes" msgstr "&Battute" @@ -1468,7 +1468,7 @@ msgid "Clear the history." msgstr "Cancella la cronologia." #. Widget: “SuggestionsWidget”. -#: plover/gui_qt/suggestions_widget.py:27 +#: plover/gui_qt/suggestions_widget.py:26 msgid "no suggestions" msgstr "nessun suggerimento" @@ -1512,7 +1512,7 @@ msgid "disconnected" msgstr "disconnessa" #. Machine name. -#: plover/machine/keyboard.py:16 +#: plover/machine/keyboard.py:14 msgid "Keyboard" msgstr "Tastiera" diff --git a/plover/messages/nl/LC_MESSAGES/plover.po b/plover/messages/nl/LC_MESSAGES/plover.po index bc24995bd..9b2b5ed4a 100644 --- a/plover/messages/nl/LC_MESSAGES/plover.po +++ b/plover/messages/nl/LC_MESSAGES/plover.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: plover 5.4.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-07-10 08:01+0200\n" +"POT-Creation-Date: 2026-07-26 08:22+0200\n" "PO-Revision-Date: 2026-03-08 12:00+0100\n" "Last-Translator: Gemini CLI\n" "Language: nl\n" @@ -78,12 +78,12 @@ msgstr "Plover: Over" #. Widget: “AddTranslationDialog”, tooltip. #. Widget: “AddTranslationWidget”, tooltip. -#: plover/gui_qt/add_translation_dialog.py:11 -#: plover/gui_qt/add_translation_widget.py:24 +#: plover/gui_qt/add_translation_dialog.py:10 +#: plover/gui_qt/add_translation_widget.py:22 msgid "Add a new translation to the dictionary." msgstr "Voeg een nieuwe vertaling toe aan het woordenboek." -#: plover/gui_qt/add_translation_dialog.py:13 +#: plover/gui_qt/add_translation_dialog.py:12 msgid "Add Translation" msgstr "Vertaling toevoegen" @@ -130,7 +130,7 @@ msgstr "Aanslagen:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:132 -#: plover/gui_qt/dictionary_editor.py:170 +#: plover/gui_qt/dictionary_editor.py:169 msgid "Strokes" msgstr "Aanslagen" @@ -142,7 +142,7 @@ msgstr "Vertaling:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:138 -#: plover/gui_qt/dictionary_editor.py:173 +#: plover/gui_qt/dictionary_editor.py:172 msgid "Translation" msgstr "Vertaling" @@ -154,7 +154,7 @@ msgstr "Woordenboek:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:144 -#: plover/gui_qt/dictionary_editor.py:176 +#: plover/gui_qt/dictionary_editor.py:175 msgid "Dictionary" msgstr "Woordenboek" @@ -383,51 +383,51 @@ msgstr "RTS/CTS" #. Widget: “NopeOption” (empty config option message, #. e.g. the machine option when selecting the Treal machine). -#: plover/gui_qt/config_window.py:52 +#: plover/gui_qt/config_window.py:49 msgid "Nothing to see here!" msgstr "Niks te zien hier!" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:174 +#: plover/gui_qt/config_window.py:171 msgid "Key" msgstr "Toets" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:176 +#: plover/gui_qt/config_window.py:173 msgid "Action" msgstr "Actie" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:222 +#: plover/gui_qt/config_window.py:219 msgid "Selected" msgstr "Geselecteerd" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:224 +#: plover/gui_qt/config_window.py:221 msgid "Choice" msgstr "Keuze" -#: plover/gui_qt/config_window.py:355 +#: plover/gui_qt/config_window.py:352 msgid "Interface" msgstr "Interface" -#: plover/gui_qt/config_window.py:358 +#: plover/gui_qt/config_window.py:355 msgid "Appearance:" msgstr "Uiterlijk:" -#: plover/gui_qt/config_window.py:363 plover/gui_qt/config_window.py:587 +#: plover/gui_qt/config_window.py:360 plover/gui_qt/config_window.py:584 msgid "System" msgstr "Systeem" -#: plover/gui_qt/config_window.py:364 +#: plover/gui_qt/config_window.py:361 msgid "Light" msgstr "Licht" -#: plover/gui_qt/config_window.py:365 +#: plover/gui_qt/config_window.py:362 msgid "Dark" msgstr "Donker" -#: plover/gui_qt/config_window.py:369 +#: plover/gui_qt/config_window.py:366 msgid "" "Set the application appearance:\n" "- System: follow the operating system mode\n" @@ -439,35 +439,35 @@ msgstr "" "- Licht: forceer lichte modus\n" "- Donker: forceer donkere modus" -#: plover/gui_qt/config_window.py:376 +#: plover/gui_qt/config_window.py:373 msgid "Start minimized:" msgstr "Start geminimaliseerd:" -#: plover/gui_qt/config_window.py:379 +#: plover/gui_qt/config_window.py:376 msgid "Minimize the main window to systray on startup." msgstr "Minimaliseer bij het opstarten het hoofdvenster naar de systray." -#: plover/gui_qt/config_window.py:382 +#: plover/gui_qt/config_window.py:379 msgid "Show paper tape:" msgstr "Papierstrook weergeven:" -#: plover/gui_qt/config_window.py:385 +#: plover/gui_qt/config_window.py:382 msgid "Open the paper tape on startup." msgstr "Open de papierstrook bij het opstarten." -#: plover/gui_qt/config_window.py:388 +#: plover/gui_qt/config_window.py:385 msgid "Show suggestions:" msgstr "Suggesties weergeven:" -#: plover/gui_qt/config_window.py:391 +#: plover/gui_qt/config_window.py:388 msgid "Open the suggestions dialog on startup." msgstr "Open het venster met suggesties bij het opstarten." -#: plover/gui_qt/config_window.py:394 +#: plover/gui_qt/config_window.py:391 msgid "Add translation dialog opacity:" msgstr "Doorzichtigheid van het vertalingsvenster:" -#: plover/gui_qt/config_window.py:398 +#: plover/gui_qt/config_window.py:395 msgid "" "Set the translation dialog opacity:\n" "- 0 makes the dialog invisible.\n" @@ -477,19 +477,19 @@ msgstr "" "- 0 maakt het venster onzichtbaar.\n" "- 100 is volledig ondoorzichtig." -#: plover/gui_qt/config_window.py:404 +#: plover/gui_qt/config_window.py:401 msgid "Dictionaries display order:" msgstr "Volgorde woordenboeken:" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "top-down" msgstr "boven naar onder" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "bottom-up" msgstr "onder naar boven" -#: plover/gui_qt/config_window.py:410 +#: plover/gui_qt/config_window.py:407 msgid "" "Set the display order for dictionaries:\n" "- top-down: Match the search order; highest priority first.\n" @@ -501,77 +501,77 @@ msgstr "" "- onder naar boven: Andersom dan de zoekvolgorde, laagste prioriteit " "eerst.\n" -#: plover/gui_qt/config_window.py:419 +#: plover/gui_qt/config_window.py:416 msgid "Logging" msgstr "Logs" -#: plover/gui_qt/config_window.py:422 +#: plover/gui_qt/config_window.py:419 msgid "Log file:" msgstr "Logbestand:" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Select a log file" msgstr "Selecteer een logbestand" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Log files (*.log)" msgstr "Logbestanden (*.log)" -#: plover/gui_qt/config_window.py:427 +#: plover/gui_qt/config_window.py:424 msgid "File to use for logging strokes/translations." msgstr "Bestand om aanslagen en vertalingen naar te schrijven." -#: plover/gui_qt/config_window.py:430 +#: plover/gui_qt/config_window.py:427 msgid "Log strokes:" msgstr "Aanslagen loggen:" -#: plover/gui_qt/config_window.py:433 +#: plover/gui_qt/config_window.py:430 msgid "Save strokes to the logfile." msgstr "Sla aanslagen op in het logbestand." -#: plover/gui_qt/config_window.py:436 +#: plover/gui_qt/config_window.py:433 msgid "Log translations:" msgstr "Vertalingen loggen:" -#: plover/gui_qt/config_window.py:439 +#: plover/gui_qt/config_window.py:436 msgid "Save translations to the logfile." msgstr "Sla vertalingen op in het logbestand." #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:445 plover/gui_qt/main_window_ui.py:260 +#: plover/gui_qt/config_window.py:442 plover/gui_qt/main_window_ui.py:260 msgid "Machine" msgstr "Machine" -#: plover/gui_qt/config_window.py:448 +#: plover/gui_qt/config_window.py:445 msgid "Machine:" msgstr "Machine:" -#: plover/gui_qt/config_window.py:460 +#: plover/gui_qt/config_window.py:457 msgid "Options:" msgstr "Opties:" -#: plover/gui_qt/config_window.py:462 +#: plover/gui_qt/config_window.py:459 msgid "Keymap:" msgstr "Toetsenmapping:" #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:467 plover/gui_qt/main_window_ui.py:292 +#: plover/gui_qt/config_window.py:464 plover/gui_qt/main_window_ui.py:292 msgid "Output" msgstr "Uitvoer" -#: plover/gui_qt/config_window.py:470 +#: plover/gui_qt/config_window.py:467 msgid "Enable at start:" msgstr "Inschakelen bij starten:" -#: plover/gui_qt/config_window.py:473 +#: plover/gui_qt/config_window.py:470 msgid "Enable output on startup." msgstr "Schakel uitvoer in bij het opstarten." -#: plover/gui_qt/config_window.py:476 +#: plover/gui_qt/config_window.py:473 msgid "Start attached:" msgstr "Start aaneengeschreven:" -#: plover/gui_qt/config_window.py:480 +#: plover/gui_qt/config_window.py:477 msgid "" "Disable preceding space on first output.\n" "\n" @@ -581,35 +581,35 @@ msgstr "" "\n" "Deze optie is alleen van toepassing als spaties ervoor worden geplaatst." -#: plover/gui_qt/config_window.py:486 +#: plover/gui_qt/config_window.py:483 msgid "Start capitalized:" msgstr "Start met hoofdletter:" -#: plover/gui_qt/config_window.py:489 +#: plover/gui_qt/config_window.py:486 msgid "Capitalize the first word." msgstr "Schrijf het eerste woord met een hoofdletter." -#: plover/gui_qt/config_window.py:492 +#: plover/gui_qt/config_window.py:489 msgid "Space placement:" msgstr "Spatieplaatsing:" -#: plover/gui_qt/config_window.py:497 +#: plover/gui_qt/config_window.py:494 msgid "Before Output" msgstr "Voor uitvoer" -#: plover/gui_qt/config_window.py:498 +#: plover/gui_qt/config_window.py:495 msgid "After Output" msgstr "Na uitvoer" -#: plover/gui_qt/config_window.py:501 +#: plover/gui_qt/config_window.py:498 msgid "Set automatic space placement: before or after each word." msgstr "Stelt de automatische plaatsing van spaties in: voor of na ieder woord." -#: plover/gui_qt/config_window.py:504 +#: plover/gui_qt/config_window.py:501 msgid "Undo levels:" msgstr "Aantal ongedaan-maak-stappen:" -#: plover/gui_qt/config_window.py:508 +#: plover/gui_qt/config_window.py:505 msgid "" "Set how many preceding strokes can be undone.\n" "\n" @@ -621,11 +621,11 @@ msgstr "" "Let op: de daadwerkelijke waarde hangt ook of van de regel\n" "in het woordenboek met de meeste aanslagen." -#: plover/gui_qt/config_window.py:515 +#: plover/gui_qt/config_window.py:512 msgid "Key press delay (ms):" msgstr "Toetsaanslagvertraging (ms):" -#: plover/gui_qt/config_window.py:523 +#: plover/gui_qt/config_window.py:520 msgid "" "Set the delay between emulated key presses (in milliseconds).\n" "\n" @@ -645,11 +645,11 @@ msgstr "" "Een te hoge vertraging zal de prestaties van de uitvoer nadelig " "beïnvloeden." -#: plover/gui_qt/config_window.py:533 +#: plover/gui_qt/config_window.py:530 msgid "Linux keyboard layout:" msgstr "Linux-toetsenbordindeling:" -#: plover/gui_qt/config_window.py:547 +#: plover/gui_qt/config_window.py:544 msgid "" "Set the keyboard layout configured in your system.\n" "This only applies when using Linux/BSD and not using X11.\n" @@ -665,7 +665,7 @@ msgstr "" "toetsenbordindeling detecteren\n" "en geen wijzigingen in de indeling detecteren." -#: plover/gui_qt/config_window.py:557 +#: plover/gui_qt/config_window.py:554 msgid "" "When Wayland auto detect is selected, Plover is only able to detect the " "first keyboard layout and can not detect layout switches." @@ -674,29 +674,29 @@ msgstr "" "toetsenbordindeling detecteren en geen wijzigingen in de indeling " "detecteren." -#: plover/gui_qt/config_window.py:568 +#: plover/gui_qt/config_window.py:565 msgid "Plugins" msgstr "Plug-ins" -#: plover/gui_qt/config_window.py:571 +#: plover/gui_qt/config_window.py:568 msgid "Extensions:" msgstr "Extensies:" #. Widget: “MainWindow”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/main_window_ui.py:294 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/main_window_ui.py:294 msgid "Enabled" msgstr "Ingeschakeld" #. Widget: “PluginsManager”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/plugins_manager_ui.py:137 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/plugins_manager_ui.py:137 msgid "Name" msgstr "Naam" -#: plover/gui_qt/config_window.py:581 +#: plover/gui_qt/config_window.py:578 msgid "Configure enabled plugin extensions." msgstr "Stel in welke plug-in-extensies ingeschakeld zijn." -#: plover/gui_qt/config_window.py:590 +#: plover/gui_qt/config_window.py:587 msgid "System:" msgstr "Systeem:" @@ -723,83 +723,83 @@ msgid "{format} dictionaries ({extensions})" msgstr "{format} woordenboeken ({extensions})" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:391 +#: plover/gui_qt/dictionaries_widget.py:393 msgid "disabled" msgstr "uitgeschakeld" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:394 +#: plover/gui_qt/dictionaries_widget.py:396 msgid "favorite" msgstr "favoriet" -#: plover/gui_qt/dictionaries_widget.py:398 +#: plover/gui_qt/dictionaries_widget.py:400 #, python-brace-format msgid "errored: {exception}." msgstr "fout: {exception}." #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:402 +#: plover/gui_qt/dictionaries_widget.py:404 msgid "loading" msgstr "laden..." #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:405 +#: plover/gui_qt/dictionaries_widget.py:407 msgid "read-only" msgstr "alleen-lezen" #. Widget: “DictionariesWidget”, tooltip. -#: plover/gui_qt/dictionaries_widget.py:411 +#: plover/gui_qt/dictionaries_widget.py:413 #, python-brace-format msgid "Full path: {path}." msgstr "Volledig pad: {path}." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:414 +#: plover/gui_qt/dictionaries_widget.py:416 msgid "This dictionary is marked as the favorite." msgstr "Dit woordenboek is gemarkeerd als favoriet." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:417 +#: plover/gui_qt/dictionaries_widget.py:419 msgid "This dictionary is being loaded." msgstr "Dit woordenboek wordt momenteel geladen." -#: plover/gui_qt/dictionaries_widget.py:421 +#: plover/gui_qt/dictionaries_widget.py:423 #, python-brace-format msgid "Loading this dictionary failed: {exception}." msgstr "Laden van dit woordenboek is mislukt: {exception}." #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:427 +#: plover/gui_qt/dictionaries_widget.py:429 msgid "This dictionary is read-only." msgstr "Dit woordenboek is alleen-lezen." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:618 +#: plover/gui_qt/dictionaries_widget.py:620 #, python-brace-format msgid "Save a copy of {name} as..." msgstr "Sla een kopie van {name} op als..." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:620 +#: plover/gui_qt/dictionaries_widget.py:622 #, python-brace-format msgid "{name} - Copy" msgstr "{name} - Kopie" #. Widget: “DictionariesWidget”, “save as merge” file picker. -#: plover/gui_qt/dictionaries_widget.py:642 +#: plover/gui_qt/dictionaries_widget.py:644 #, python-brace-format msgid "Merge {names} as..." msgstr "Voeg {names} samen als..." #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:671 +#: plover/gui_qt/dictionaries_widget.py:673 #: plover/gui_qt/dictionaries_widget_ui.py:203 msgid "Load dictionaries" msgstr "Woordenboeken laden" #. Widget: “DictionariesWidget”, “new” file picker. #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:683 +#: plover/gui_qt/dictionaries_widget.py:685 #: plover/gui_qt/dictionaries_widget_ui.py:205 msgid "Create dictionary" msgstr "Woordenboek maken" @@ -1025,11 +1025,11 @@ msgid "Mappings" msgstr "Toewijzingen" #. Widget: “LookupDialog”, tooltip. -#: plover/gui_qt/lookup_dialog.py:12 +#: plover/gui_qt/lookup_dialog.py:11 msgid "Search the dictionary for translations." msgstr "Zoek in het woordenboek naar vertalingen." -#: plover/gui_qt/lookup_dialog.py:14 +#: plover/gui_qt/lookup_dialog.py:13 msgid "Lookup" msgstr "Opzoeken" @@ -1053,27 +1053,27 @@ msgstr "Vertalingspatroon om op te zoeken." msgid "Results" msgstr "Resultaten" -#: plover/gui_qt/machine_options.py:38 +#: plover/gui_qt/machine_options.py:36 #, python-brace-format msgid "product: {value}" msgstr "product: {value}" -#: plover/gui_qt/machine_options.py:39 +#: plover/gui_qt/machine_options.py:37 #, python-brace-format msgid "manufacturer: {value}" msgstr "fabrikant: {value}" -#: plover/gui_qt/machine_options.py:40 +#: plover/gui_qt/machine_options.py:38 #, python-brace-format msgid "serial number: {value}" msgstr "serienummer: {value}" -#: plover/gui_qt/machine_options.py:48 +#: plover/gui_qt/machine_options.py:46 #, python-brace-format msgid "description: {value}" msgstr "beschrijving: {value}" -#: plover/gui_qt/machine_options.py:201 +#: plover/gui_qt/machine_options.py:199 msgid "" "Arpeggiate allows using non-NKRO keyboards.\n" "\n" @@ -1086,7 +1086,7 @@ msgstr "" "Iedere toets kan één voor één ingedrukt worden,\n" "waarna de spatiebalk de aanslag verzendt." -#: plover/gui_qt/main_window.py:312 +#: plover/gui_qt/main_window.py:310 msgid "Application is still running." msgstr "Applicatie is nog steeds in uitvoering." @@ -1239,34 +1239,34 @@ msgid "Plover: Toolbar" msgstr "Plover: Werkbalk" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:30 +#: plover/gui_qt/paper_tape.py:27 msgid "Paper" msgstr "Papier" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:32 +#: plover/gui_qt/paper_tape.py:29 msgid "Raw" msgstr "Ruw" #. Widget: “PaperTape”, tooltip. -#: plover/gui_qt/paper_tape.py:122 +#: plover/gui_qt/paper_tape.py:119 msgid "Paper tape display of strokes." msgstr "Papierstrookweergave van aanslagen." -#: plover/gui_qt/paper_tape.py:124 +#: plover/gui_qt/paper_tape.py:121 msgid "Paper Tape" msgstr "Papierstrook" -#: plover/gui_qt/paper_tape.py:237 +#: plover/gui_qt/paper_tape.py:234 msgid "Do you want to clear the paper tape?" msgstr "De papierstrook echt wissen?" -#: plover/gui_qt/paper_tape.py:255 +#: plover/gui_qt/paper_tape.py:254 msgid "Save Paper Tape" msgstr "Papierstrook opslaan" #. Paper tape, "save" file picker. -#: plover/gui_qt/paper_tape.py:258 +#: plover/gui_qt/paper_tape.py:257 msgid "Text files (*.txt)" msgstr "Tekstbestanden (*.txt)" @@ -1356,22 +1356,22 @@ msgid "N/A" msgstr "n.v.t." #. Metadata field. -#: plover/gui_qt/plugins_manager.py:127 +#: plover/gui_qt/plugins_manager.py:126 #, python-format msgid "

Author: %s

" msgstr "

Auteur: %s

" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:133 +#: plover/gui_qt/plugins_manager.py:132 #, python-format msgid "

Home page: %s

" msgstr "

Homepage: %s

" -#: plover/gui_qt/plugins_manager.py:180 +#: plover/gui_qt/plugins_manager.py:179 msgid "Install from Git repo" msgstr "Installeren vanuit Git-repo" -#: plover/gui_qt/plugins_manager.py:182 +#: plover/gui_qt/plugins_manager.py:181 msgid "" "WARNING: Installing plugins is a security risk.
A plugin from a Git" " repo can contain malicious code.
Only install it if you got it from a" @@ -1384,12 +1384,12 @@ msgstr "" "bron hebt verkregen.


Voer de repository-link voor de plug-in " "in
(zal lijken op https://github.com/gebruiker/repository.git):
" -#: plover/gui_qt/plugins_manager.py:204 +#: plover/gui_qt/plugins_manager.py:203 #, python-brace-format msgid "Install {packages}" msgstr "Installeer {packages}" -#: plover/gui_qt/plugins_manager.py:206 +#: plover/gui_qt/plugins_manager.py:205 msgid "" "Installing plugins is a security risk. A plugin can contain " "virus/malware. Only install it if you got it from a trusted source. Are " @@ -1399,12 +1399,12 @@ msgstr "" " kan virussen/malware bevatten. Installeer deze alleen als u deze van een" " vertrouwde bron hebt verkregen. Weet u zeker dat u wilt doorgaan?" -#: plover/gui_qt/plugins_manager.py:233 +#: plover/gui_qt/plugins_manager.py:232 #, python-brace-format msgid "Uninstall {packages}" msgstr "Deïnstalleer {packages}" -#: plover/gui_qt/plugins_manager.py:234 +#: plover/gui_qt/plugins_manager.py:233 msgid "Are you sure you want to proceed?" msgstr "Weet u zeker dat u wilt doorgaan?" @@ -1445,23 +1445,23 @@ msgid "..." msgstr "..." #. Widget: “SuggestionsDialog”, tooltip. -#: plover/gui_qt/suggestions_dialog.py:26 +#: plover/gui_qt/suggestions_dialog.py:25 msgid "Suggest possible strokes for the last written words." msgstr "Stel mogelijke aanslagen voor de laatste geschreven woorden voor." #. Widget: “SuggestionsDialog”, accessible name. -#: plover/gui_qt/suggestions_dialog.py:28 +#: plover/gui_qt/suggestions_dialog.py:27 #: plover/gui_qt/suggestions_dialog_ui.py:97 msgid "Suggestions" msgstr "Suggesties" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:62 +#: plover/gui_qt/suggestions_dialog.py:61 msgid "&Text" msgstr "&Tekst" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:64 +#: plover/gui_qt/suggestions_dialog.py:63 msgid "&Strokes" msgstr "&Aanslagen" @@ -1471,7 +1471,7 @@ msgid "Clear the history." msgstr "Maakt de geschiedenis leeg." #. Widget: “SuggestionsWidget”. -#: plover/gui_qt/suggestions_widget.py:27 +#: plover/gui_qt/suggestions_widget.py:26 msgid "no suggestions" msgstr "geen suggesties" @@ -1515,7 +1515,7 @@ msgid "disconnected" msgstr "verbinding verbroken" #. Machine name. -#: plover/machine/keyboard.py:16 +#: plover/machine/keyboard.py:14 msgid "Keyboard" msgstr "Toetsenbord" diff --git a/plover/messages/plover.pot b/plover/messages/plover.pot index b98954bdf..9da18c54a 100644 --- a/plover/messages/plover.pot +++ b/plover/messages/plover.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: plover 5.4.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-07-10 08:01+0200\n" +"POT-Creation-Date: 2026-07-26 08:22+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -58,12 +58,12 @@ msgstr "" #. Widget: “AddTranslationDialog”, tooltip. #. Widget: “AddTranslationWidget”, tooltip. -#: plover/gui_qt/add_translation_dialog.py:11 -#: plover/gui_qt/add_translation_widget.py:24 +#: plover/gui_qt/add_translation_dialog.py:10 +#: plover/gui_qt/add_translation_widget.py:22 msgid "Add a new translation to the dictionary." msgstr "" -#: plover/gui_qt/add_translation_dialog.py:13 +#: plover/gui_qt/add_translation_dialog.py:12 msgid "Add Translation" msgstr "" @@ -110,7 +110,7 @@ msgstr "" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:132 -#: plover/gui_qt/dictionary_editor.py:170 +#: plover/gui_qt/dictionary_editor.py:169 msgid "Strokes" msgstr "" @@ -122,7 +122,7 @@ msgstr "" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:138 -#: plover/gui_qt/dictionary_editor.py:173 +#: plover/gui_qt/dictionary_editor.py:172 msgid "Translation" msgstr "" @@ -134,7 +134,7 @@ msgstr "" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:144 -#: plover/gui_qt/dictionary_editor.py:176 +#: plover/gui_qt/dictionary_editor.py:175 msgid "Dictionary" msgstr "" @@ -357,51 +357,51 @@ msgstr "" #. Widget: “NopeOption” (empty config option message, #. e.g. the machine option when selecting the Treal machine). -#: plover/gui_qt/config_window.py:52 +#: plover/gui_qt/config_window.py:49 msgid "Nothing to see here!" msgstr "" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:174 +#: plover/gui_qt/config_window.py:171 msgid "Key" msgstr "" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:176 +#: plover/gui_qt/config_window.py:173 msgid "Action" msgstr "" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:222 +#: plover/gui_qt/config_window.py:219 msgid "Selected" msgstr "" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:224 +#: plover/gui_qt/config_window.py:221 msgid "Choice" msgstr "" -#: plover/gui_qt/config_window.py:355 +#: plover/gui_qt/config_window.py:352 msgid "Interface" msgstr "" -#: plover/gui_qt/config_window.py:358 +#: plover/gui_qt/config_window.py:355 msgid "Appearance:" msgstr "" -#: plover/gui_qt/config_window.py:363 plover/gui_qt/config_window.py:587 +#: plover/gui_qt/config_window.py:360 plover/gui_qt/config_window.py:584 msgid "System" msgstr "" -#: plover/gui_qt/config_window.py:364 +#: plover/gui_qt/config_window.py:361 msgid "Light" msgstr "" -#: plover/gui_qt/config_window.py:365 +#: plover/gui_qt/config_window.py:362 msgid "Dark" msgstr "" -#: plover/gui_qt/config_window.py:369 +#: plover/gui_qt/config_window.py:366 msgid "" "Set the application appearance:\n" "- System: follow the operating system mode\n" @@ -409,166 +409,166 @@ msgid "" "- Dark: force dark mode" msgstr "" -#: plover/gui_qt/config_window.py:376 +#: plover/gui_qt/config_window.py:373 msgid "Start minimized:" msgstr "" -#: plover/gui_qt/config_window.py:379 +#: plover/gui_qt/config_window.py:376 msgid "Minimize the main window to systray on startup." msgstr "" -#: plover/gui_qt/config_window.py:382 +#: plover/gui_qt/config_window.py:379 msgid "Show paper tape:" msgstr "" -#: plover/gui_qt/config_window.py:385 +#: plover/gui_qt/config_window.py:382 msgid "Open the paper tape on startup." msgstr "" -#: plover/gui_qt/config_window.py:388 +#: plover/gui_qt/config_window.py:385 msgid "Show suggestions:" msgstr "" -#: plover/gui_qt/config_window.py:391 +#: plover/gui_qt/config_window.py:388 msgid "Open the suggestions dialog on startup." msgstr "" -#: plover/gui_qt/config_window.py:394 +#: plover/gui_qt/config_window.py:391 msgid "Add translation dialog opacity:" msgstr "" -#: plover/gui_qt/config_window.py:398 +#: plover/gui_qt/config_window.py:395 msgid "" "Set the translation dialog opacity:\n" "- 0 makes the dialog invisible.\n" "- 100 is fully opaque." msgstr "" -#: plover/gui_qt/config_window.py:404 +#: plover/gui_qt/config_window.py:401 msgid "Dictionaries display order:" msgstr "" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "top-down" msgstr "" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "bottom-up" msgstr "" -#: plover/gui_qt/config_window.py:410 +#: plover/gui_qt/config_window.py:407 msgid "" "Set the display order for dictionaries:\n" "- top-down: Match the search order; highest priority first.\n" "- bottom-up: Reverse search order; lowest priority first.\n" msgstr "" -#: plover/gui_qt/config_window.py:419 +#: plover/gui_qt/config_window.py:416 msgid "Logging" msgstr "" -#: plover/gui_qt/config_window.py:422 +#: plover/gui_qt/config_window.py:419 msgid "Log file:" msgstr "" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Select a log file" msgstr "" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Log files (*.log)" msgstr "" -#: plover/gui_qt/config_window.py:427 +#: plover/gui_qt/config_window.py:424 msgid "File to use for logging strokes/translations." msgstr "" -#: plover/gui_qt/config_window.py:430 +#: plover/gui_qt/config_window.py:427 msgid "Log strokes:" msgstr "" -#: plover/gui_qt/config_window.py:433 +#: plover/gui_qt/config_window.py:430 msgid "Save strokes to the logfile." msgstr "" -#: plover/gui_qt/config_window.py:436 +#: plover/gui_qt/config_window.py:433 msgid "Log translations:" msgstr "" -#: plover/gui_qt/config_window.py:439 +#: plover/gui_qt/config_window.py:436 msgid "Save translations to the logfile." msgstr "" #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:445 plover/gui_qt/main_window_ui.py:260 +#: plover/gui_qt/config_window.py:442 plover/gui_qt/main_window_ui.py:260 msgid "Machine" msgstr "" -#: plover/gui_qt/config_window.py:448 +#: plover/gui_qt/config_window.py:445 msgid "Machine:" msgstr "" -#: plover/gui_qt/config_window.py:460 +#: plover/gui_qt/config_window.py:457 msgid "Options:" msgstr "" -#: plover/gui_qt/config_window.py:462 +#: plover/gui_qt/config_window.py:459 msgid "Keymap:" msgstr "" #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:467 plover/gui_qt/main_window_ui.py:292 +#: plover/gui_qt/config_window.py:464 plover/gui_qt/main_window_ui.py:292 msgid "Output" msgstr "" -#: plover/gui_qt/config_window.py:470 +#: plover/gui_qt/config_window.py:467 msgid "Enable at start:" msgstr "" -#: plover/gui_qt/config_window.py:473 +#: plover/gui_qt/config_window.py:470 msgid "Enable output on startup." msgstr "" -#: plover/gui_qt/config_window.py:476 +#: plover/gui_qt/config_window.py:473 msgid "Start attached:" msgstr "" -#: plover/gui_qt/config_window.py:480 +#: plover/gui_qt/config_window.py:477 msgid "" "Disable preceding space on first output.\n" "\n" "This option is only applicable when spaces are placed before." msgstr "" -#: plover/gui_qt/config_window.py:486 +#: plover/gui_qt/config_window.py:483 msgid "Start capitalized:" msgstr "" -#: plover/gui_qt/config_window.py:489 +#: plover/gui_qt/config_window.py:486 msgid "Capitalize the first word." msgstr "" -#: plover/gui_qt/config_window.py:492 +#: plover/gui_qt/config_window.py:489 msgid "Space placement:" msgstr "" -#: plover/gui_qt/config_window.py:497 +#: plover/gui_qt/config_window.py:494 msgid "Before Output" msgstr "" -#: plover/gui_qt/config_window.py:498 +#: plover/gui_qt/config_window.py:495 msgid "After Output" msgstr "" -#: plover/gui_qt/config_window.py:501 +#: plover/gui_qt/config_window.py:498 msgid "Set automatic space placement: before or after each word." msgstr "" -#: plover/gui_qt/config_window.py:504 +#: plover/gui_qt/config_window.py:501 msgid "Undo levels:" msgstr "" -#: plover/gui_qt/config_window.py:508 +#: plover/gui_qt/config_window.py:505 msgid "" "Set how many preceding strokes can be undone.\n" "\n" @@ -576,11 +576,11 @@ msgid "" "dictionaries entry with the maximum number of strokes." msgstr "" -#: plover/gui_qt/config_window.py:515 +#: plover/gui_qt/config_window.py:512 msgid "Key press delay (ms):" msgstr "" -#: plover/gui_qt/config_window.py:523 +#: plover/gui_qt/config_window.py:520 msgid "" "Set the delay between emulated key presses (in milliseconds).\n" "\n" @@ -591,11 +591,11 @@ msgid "" "performance of key stroke output." msgstr "" -#: plover/gui_qt/config_window.py:533 +#: plover/gui_qt/config_window.py:530 msgid "Linux keyboard layout:" msgstr "" -#: plover/gui_qt/config_window.py:547 +#: plover/gui_qt/config_window.py:544 msgid "" "Set the keyboard layout configured in your system.\n" "This only applies when using Linux/BSD and not using X11.\n" @@ -605,35 +605,35 @@ msgid "" "and can not detect layout switches." msgstr "" -#: plover/gui_qt/config_window.py:557 +#: plover/gui_qt/config_window.py:554 msgid "" "When Wayland auto detect is selected, Plover is only able to detect the " "first keyboard layout and can not detect layout switches." msgstr "" -#: plover/gui_qt/config_window.py:568 +#: plover/gui_qt/config_window.py:565 msgid "Plugins" msgstr "" -#: plover/gui_qt/config_window.py:571 +#: plover/gui_qt/config_window.py:568 msgid "Extensions:" msgstr "" #. Widget: “MainWindow”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/main_window_ui.py:294 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/main_window_ui.py:294 msgid "Enabled" msgstr "" #. Widget: “PluginsManager”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/plugins_manager_ui.py:137 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/plugins_manager_ui.py:137 msgid "Name" msgstr "" -#: plover/gui_qt/config_window.py:581 +#: plover/gui_qt/config_window.py:578 msgid "Configure enabled plugin extensions." msgstr "" -#: plover/gui_qt/config_window.py:590 +#: plover/gui_qt/config_window.py:587 msgid "System:" msgstr "" @@ -660,83 +660,83 @@ msgid "{format} dictionaries ({extensions})" msgstr "" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:391 +#: plover/gui_qt/dictionaries_widget.py:393 msgid "disabled" msgstr "" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:394 +#: plover/gui_qt/dictionaries_widget.py:396 msgid "favorite" msgstr "" -#: plover/gui_qt/dictionaries_widget.py:398 +#: plover/gui_qt/dictionaries_widget.py:400 #, python-brace-format msgid "errored: {exception}." msgstr "" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:402 +#: plover/gui_qt/dictionaries_widget.py:404 msgid "loading" msgstr "" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:405 +#: plover/gui_qt/dictionaries_widget.py:407 msgid "read-only" msgstr "" #. Widget: “DictionariesWidget”, tooltip. -#: plover/gui_qt/dictionaries_widget.py:411 +#: plover/gui_qt/dictionaries_widget.py:413 #, python-brace-format msgid "Full path: {path}." msgstr "" #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:414 +#: plover/gui_qt/dictionaries_widget.py:416 msgid "This dictionary is marked as the favorite." msgstr "" #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:417 +#: plover/gui_qt/dictionaries_widget.py:419 msgid "This dictionary is being loaded." msgstr "" -#: plover/gui_qt/dictionaries_widget.py:421 +#: plover/gui_qt/dictionaries_widget.py:423 #, python-brace-format msgid "Loading this dictionary failed: {exception}." msgstr "" #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:427 +#: plover/gui_qt/dictionaries_widget.py:429 msgid "This dictionary is read-only." msgstr "" #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:618 +#: plover/gui_qt/dictionaries_widget.py:620 #, python-brace-format msgid "Save a copy of {name} as..." msgstr "" #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:620 +#: plover/gui_qt/dictionaries_widget.py:622 #, python-brace-format msgid "{name} - Copy" msgstr "" #. Widget: “DictionariesWidget”, “save as merge” file picker. -#: plover/gui_qt/dictionaries_widget.py:642 +#: plover/gui_qt/dictionaries_widget.py:644 #, python-brace-format msgid "Merge {names} as..." msgstr "" #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:671 +#: plover/gui_qt/dictionaries_widget.py:673 #: plover/gui_qt/dictionaries_widget_ui.py:203 msgid "Load dictionaries" msgstr "" #. Widget: “DictionariesWidget”, “new” file picker. #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:683 +#: plover/gui_qt/dictionaries_widget.py:685 #: plover/gui_qt/dictionaries_widget_ui.py:205 msgid "Create dictionary" msgstr "" @@ -960,11 +960,11 @@ msgid "Mappings" msgstr "" #. Widget: “LookupDialog”, tooltip. -#: plover/gui_qt/lookup_dialog.py:12 +#: plover/gui_qt/lookup_dialog.py:11 msgid "Search the dictionary for translations." msgstr "" -#: plover/gui_qt/lookup_dialog.py:14 +#: plover/gui_qt/lookup_dialog.py:13 msgid "Lookup" msgstr "" @@ -988,27 +988,27 @@ msgstr "" msgid "Results" msgstr "" -#: plover/gui_qt/machine_options.py:38 +#: plover/gui_qt/machine_options.py:36 #, python-brace-format msgid "product: {value}" msgstr "" -#: plover/gui_qt/machine_options.py:39 +#: plover/gui_qt/machine_options.py:37 #, python-brace-format msgid "manufacturer: {value}" msgstr "" -#: plover/gui_qt/machine_options.py:40 +#: plover/gui_qt/machine_options.py:38 #, python-brace-format msgid "serial number: {value}" msgstr "" -#: plover/gui_qt/machine_options.py:48 +#: plover/gui_qt/machine_options.py:46 #, python-brace-format msgid "description: {value}" msgstr "" -#: plover/gui_qt/machine_options.py:201 +#: plover/gui_qt/machine_options.py:199 msgid "" "Arpeggiate allows using non-NKRO keyboards.\n" "\n" @@ -1016,7 +1016,7 @@ msgid "" "space bar is pressed to send the stroke." msgstr "" -#: plover/gui_qt/main_window.py:312 +#: plover/gui_qt/main_window.py:310 msgid "Application is still running." msgstr "" @@ -1169,34 +1169,34 @@ msgid "Plover: Toolbar" msgstr "" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:30 +#: plover/gui_qt/paper_tape.py:27 msgid "Paper" msgstr "" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:32 +#: plover/gui_qt/paper_tape.py:29 msgid "Raw" msgstr "" #. Widget: “PaperTape”, tooltip. -#: plover/gui_qt/paper_tape.py:122 +#: plover/gui_qt/paper_tape.py:119 msgid "Paper tape display of strokes." msgstr "" -#: plover/gui_qt/paper_tape.py:124 +#: plover/gui_qt/paper_tape.py:121 msgid "Paper Tape" msgstr "" -#: plover/gui_qt/paper_tape.py:237 +#: plover/gui_qt/paper_tape.py:234 msgid "Do you want to clear the paper tape?" msgstr "" -#: plover/gui_qt/paper_tape.py:255 +#: plover/gui_qt/paper_tape.py:254 msgid "Save Paper Tape" msgstr "" #. Paper tape, "save" file picker. -#: plover/gui_qt/paper_tape.py:258 +#: plover/gui_qt/paper_tape.py:257 msgid "Text files (*.txt)" msgstr "" @@ -1286,22 +1286,22 @@ msgid "N/A" msgstr "" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:127 +#: plover/gui_qt/plugins_manager.py:126 #, python-format msgid "

Author: %s

" msgstr "" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:133 +#: plover/gui_qt/plugins_manager.py:132 #, python-format msgid "

Home page: %s

" msgstr "" -#: plover/gui_qt/plugins_manager.py:180 +#: plover/gui_qt/plugins_manager.py:179 msgid "Install from Git repo" msgstr "" -#: plover/gui_qt/plugins_manager.py:182 +#: plover/gui_qt/plugins_manager.py:181 msgid "" "WARNING: Installing plugins is a security risk.
A plugin from a Git" " repo can contain malicious code.
Only install it if you got it from a" @@ -1309,24 +1309,24 @@ msgid "" "look similar to https://github.com/user/repository.git):
" msgstr "" -#: plover/gui_qt/plugins_manager.py:204 +#: plover/gui_qt/plugins_manager.py:203 #, python-brace-format msgid "Install {packages}" msgstr "" -#: plover/gui_qt/plugins_manager.py:206 +#: plover/gui_qt/plugins_manager.py:205 msgid "" "Installing plugins is a security risk. A plugin can contain " "virus/malware. Only install it if you got it from a trusted source. Are " "you sure you want to proceed?" msgstr "" -#: plover/gui_qt/plugins_manager.py:233 +#: plover/gui_qt/plugins_manager.py:232 #, python-brace-format msgid "Uninstall {packages}" msgstr "" -#: plover/gui_qt/plugins_manager.py:234 +#: plover/gui_qt/plugins_manager.py:233 msgid "Are you sure you want to proceed?" msgstr "" @@ -1367,23 +1367,23 @@ msgid "..." msgstr "" #. Widget: “SuggestionsDialog”, tooltip. -#: plover/gui_qt/suggestions_dialog.py:26 +#: plover/gui_qt/suggestions_dialog.py:25 msgid "Suggest possible strokes for the last written words." msgstr "" #. Widget: “SuggestionsDialog”, accessible name. -#: plover/gui_qt/suggestions_dialog.py:28 +#: plover/gui_qt/suggestions_dialog.py:27 #: plover/gui_qt/suggestions_dialog_ui.py:97 msgid "Suggestions" msgstr "" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:62 +#: plover/gui_qt/suggestions_dialog.py:61 msgid "&Text" msgstr "" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:64 +#: plover/gui_qt/suggestions_dialog.py:63 msgid "&Strokes" msgstr "" @@ -1393,7 +1393,7 @@ msgid "Clear the history." msgstr "" #. Widget: “SuggestionsWidget”. -#: plover/gui_qt/suggestions_widget.py:27 +#: plover/gui_qt/suggestions_widget.py:26 msgid "no suggestions" msgstr "" @@ -1437,7 +1437,7 @@ msgid "disconnected" msgstr "" #. Machine name. -#: plover/machine/keyboard.py:16 +#: plover/machine/keyboard.py:14 msgid "Keyboard" msgstr "" diff --git a/plover/messages/zh_tw/LC_MESSAGES/plover.po b/plover/messages/zh_tw/LC_MESSAGES/plover.po index 73e20bcd6..cf6987200 100644 --- a/plover/messages/zh_tw/LC_MESSAGES/plover.po +++ b/plover/messages/zh_tw/LC_MESSAGES/plover.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: plover 5.4.0\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-07-10 08:01+0200\n" +"POT-Creation-Date: 2026-07-26 08:22+0200\n" "PO-Revision-Date: 2026-03-08 12:00+0100\n" "Last-Translator: Gemini CLI\n" "Language: zh_TW\n" @@ -74,12 +74,12 @@ msgstr "Plover: 關於" #. Widget: “AddTranslationDialog”, tooltip. #. Widget: “AddTranslationWidget”, tooltip. -#: plover/gui_qt/add_translation_dialog.py:11 -#: plover/gui_qt/add_translation_widget.py:24 +#: plover/gui_qt/add_translation_dialog.py:10 +#: plover/gui_qt/add_translation_widget.py:22 msgid "Add a new translation to the dictionary." msgstr "在字典中添加新的翻譯。" -#: plover/gui_qt/add_translation_dialog.py:13 +#: plover/gui_qt/add_translation_dialog.py:12 msgid "Add Translation" msgstr "添加翻譯" @@ -126,7 +126,7 @@ msgstr "和弦:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:132 -#: plover/gui_qt/dictionary_editor.py:170 +#: plover/gui_qt/dictionary_editor.py:169 msgid "Strokes" msgstr "和弦" @@ -138,7 +138,7 @@ msgstr "翻譯:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:138 -#: plover/gui_qt/dictionary_editor.py:173 +#: plover/gui_qt/dictionary_editor.py:172 msgid "Translation" msgstr "翻譯" @@ -150,7 +150,7 @@ msgstr "字典:" #. Widget: “AddTranslationWidget”, accessible name. #. Widget: “DictionaryEditor”. #: plover/gui_qt/add_translation_widget_ui.py:144 -#: plover/gui_qt/dictionary_editor.py:176 +#: plover/gui_qt/dictionary_editor.py:175 msgid "Dictionary" msgstr "字典" @@ -375,51 +375,51 @@ msgstr "RTS/CTS" #. Widget: “NopeOption” (empty config option message, #. e.g. the machine option when selecting the Treal machine). -#: plover/gui_qt/config_window.py:52 +#: plover/gui_qt/config_window.py:49 msgid "Nothing to see here!" msgstr "這裡沒有東西!" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:174 +#: plover/gui_qt/config_window.py:171 msgid "Key" msgstr "按鍵" #. Widget: “KeymapOption”. -#: plover/gui_qt/config_window.py:176 +#: plover/gui_qt/config_window.py:173 msgid "Action" msgstr "字根" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:222 +#: plover/gui_qt/config_window.py:219 msgid "Selected" msgstr "已選取" #. Widget: “MultipleChoicesOption”. -#: plover/gui_qt/config_window.py:224 +#: plover/gui_qt/config_window.py:221 msgid "Choice" msgstr "選項" -#: plover/gui_qt/config_window.py:355 +#: plover/gui_qt/config_window.py:352 msgid "Interface" msgstr "界面" -#: plover/gui_qt/config_window.py:358 +#: plover/gui_qt/config_window.py:355 msgid "Appearance:" msgstr "外觀:" -#: plover/gui_qt/config_window.py:363 plover/gui_qt/config_window.py:587 +#: plover/gui_qt/config_window.py:360 plover/gui_qt/config_window.py:584 msgid "System" msgstr "系統" -#: plover/gui_qt/config_window.py:364 +#: plover/gui_qt/config_window.py:361 msgid "Light" msgstr "淺色" -#: plover/gui_qt/config_window.py:365 +#: plover/gui_qt/config_window.py:362 msgid "Dark" msgstr "深色" -#: plover/gui_qt/config_window.py:369 +#: plover/gui_qt/config_window.py:366 msgid "" "Set the application appearance:\n" "- System: follow the operating system mode\n" @@ -431,35 +431,35 @@ msgstr "" "- 淺色:強制使用淺色模式\n" "- 深色:強制使用深色模式" -#: plover/gui_qt/config_window.py:376 +#: plover/gui_qt/config_window.py:373 msgid "Start minimized:" msgstr "啟用時最小化:" -#: plover/gui_qt/config_window.py:379 +#: plover/gui_qt/config_window.py:376 msgid "Minimize the main window to systray on startup." msgstr "開啟程式時將主視窗最小化。" -#: plover/gui_qt/config_window.py:382 +#: plover/gui_qt/config_window.py:379 msgid "Show paper tape:" msgstr "顯示輸入紙帶:" -#: plover/gui_qt/config_window.py:385 +#: plover/gui_qt/config_window.py:382 msgid "Open the paper tape on startup." msgstr "開啟程式時同時開啟輸入紙帶。" -#: plover/gui_qt/config_window.py:388 +#: plover/gui_qt/config_window.py:385 msgid "Show suggestions:" msgstr "顯示和弦建議:" -#: plover/gui_qt/config_window.py:391 +#: plover/gui_qt/config_window.py:388 msgid "Open the suggestions dialog on startup." msgstr "開啟程式時同時開啟和弦建議視窗。" -#: plover/gui_qt/config_window.py:394 +#: plover/gui_qt/config_window.py:391 msgid "Add translation dialog opacity:" msgstr "「新增翻譯」視窗透明度:" -#: plover/gui_qt/config_window.py:398 +#: plover/gui_qt/config_window.py:395 msgid "" "Set the translation dialog opacity:\n" "- 0 makes the dialog invisible.\n" @@ -469,19 +469,19 @@ msgstr "" "- 0 為完全透明。\n" "- 100 為完全不透明。" -#: plover/gui_qt/config_window.py:404 +#: plover/gui_qt/config_window.py:401 msgid "Dictionaries display order:" msgstr "字典顯示順序:" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "top-down" msgstr "由上而下" -#: plover/gui_qt/config_window.py:407 +#: plover/gui_qt/config_window.py:404 msgid "bottom-up" msgstr "由下而上" -#: plover/gui_qt/config_window.py:410 +#: plover/gui_qt/config_window.py:407 msgid "" "Set the display order for dictionaries:\n" "- top-down: Match the search order; highest priority first.\n" @@ -491,77 +491,77 @@ msgstr "" "- 由上而下:符合搜尋順序;優先級最高者優先。\n" "- 由下而上:相反搜尋順序;優先級最低者優先。\n" -#: plover/gui_qt/config_window.py:419 +#: plover/gui_qt/config_window.py:416 msgid "Logging" msgstr "輸入紀錄" -#: plover/gui_qt/config_window.py:422 +#: plover/gui_qt/config_window.py:419 msgid "Log file:" msgstr "紀錄檔:" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Select a log file" msgstr "選擇紀錄檔" -#: plover/gui_qt/config_window.py:425 +#: plover/gui_qt/config_window.py:422 msgid "Log files (*.log)" msgstr "記錄檔(*.log)" -#: plover/gui_qt/config_window.py:427 +#: plover/gui_qt/config_window.py:424 msgid "File to use for logging strokes/translations." msgstr "用來記錄輸入過的和弦、翻譯的檔案。" -#: plover/gui_qt/config_window.py:430 +#: plover/gui_qt/config_window.py:427 msgid "Log strokes:" msgstr "紀錄和弦:" -#: plover/gui_qt/config_window.py:433 +#: plover/gui_qt/config_window.py:430 msgid "Save strokes to the logfile." msgstr "將和弦紀錄至紀錄檔。" -#: plover/gui_qt/config_window.py:436 +#: plover/gui_qt/config_window.py:433 msgid "Log translations:" msgstr "紀錄翻譯:" -#: plover/gui_qt/config_window.py:439 +#: plover/gui_qt/config_window.py:436 msgid "Save translations to the logfile." msgstr "將翻譯紀錄至紀錄檔。" #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:445 plover/gui_qt/main_window_ui.py:260 +#: plover/gui_qt/config_window.py:442 plover/gui_qt/main_window_ui.py:260 msgid "Machine" msgstr "輸入硬體" -#: plover/gui_qt/config_window.py:448 +#: plover/gui_qt/config_window.py:445 msgid "Machine:" msgstr "輸入硬體:" -#: plover/gui_qt/config_window.py:460 +#: plover/gui_qt/config_window.py:457 msgid "Options:" msgstr "選項:" -#: plover/gui_qt/config_window.py:462 +#: plover/gui_qt/config_window.py:459 msgid "Keymap:" msgstr "按鍵映射:" #. Widget: “MainWindow”, title. -#: plover/gui_qt/config_window.py:467 plover/gui_qt/main_window_ui.py:292 +#: plover/gui_qt/config_window.py:464 plover/gui_qt/main_window_ui.py:292 msgid "Output" msgstr "輸出" -#: plover/gui_qt/config_window.py:470 +#: plover/gui_qt/config_window.py:467 msgid "Enable at start:" msgstr "啟用時啟用輸出:" -#: plover/gui_qt/config_window.py:473 +#: plover/gui_qt/config_window.py:470 msgid "Enable output on startup." msgstr "啟用時啟用輸出。" -#: plover/gui_qt/config_window.py:476 +#: plover/gui_qt/config_window.py:473 msgid "Start attached:" msgstr "首字取消空白:" -#: plover/gui_qt/config_window.py:480 +#: plover/gui_qt/config_window.py:477 msgid "" "Disable preceding space on first output.\n" "\n" @@ -571,35 +571,35 @@ msgstr "" "\n" "這個選項只適用於空白放置於字串前方時。" -#: plover/gui_qt/config_window.py:486 +#: plover/gui_qt/config_window.py:483 msgid "Start capitalized:" msgstr "首字大寫:" -#: plover/gui_qt/config_window.py:489 +#: plover/gui_qt/config_window.py:486 msgid "Capitalize the first word." msgstr "將第一個字母大寫。" -#: plover/gui_qt/config_window.py:492 +#: plover/gui_qt/config_window.py:489 msgid "Space placement:" msgstr "空白的放置位置:" -#: plover/gui_qt/config_window.py:497 +#: plover/gui_qt/config_window.py:494 msgid "Before Output" msgstr "在字串前面" -#: plover/gui_qt/config_window.py:498 +#: plover/gui_qt/config_window.py:495 msgid "After Output" msgstr "在字串後面" -#: plover/gui_qt/config_window.py:501 +#: plover/gui_qt/config_window.py:498 msgid "Set automatic space placement: before or after each word." msgstr "設定空白的放置位置。" -#: plover/gui_qt/config_window.py:504 +#: plover/gui_qt/config_window.py:501 msgid "Undo levels:" msgstr "最大回復次數:" -#: plover/gui_qt/config_window.py:508 +#: plover/gui_qt/config_window.py:505 msgid "" "Set how many preceding strokes can be undone.\n" "\n" @@ -607,11 +607,11 @@ msgid "" "dictionaries entry with the maximum number of strokes." msgstr "設定回復的最大次數。" -#: plover/gui_qt/config_window.py:515 +#: plover/gui_qt/config_window.py:512 msgid "Key press delay (ms):" msgstr "按鍵延遲 (毫秒):" -#: plover/gui_qt/config_window.py:523 +#: plover/gui_qt/config_window.py:520 msgid "" "Set the delay between emulated key presses (in milliseconds).\n" "\n" @@ -627,11 +627,11 @@ msgstr "" "增加延遲可以讓程式有時間處理每次按鍵。\n" "延遲設定過高會對輸出效能產生負面影響。" -#: plover/gui_qt/config_window.py:533 +#: plover/gui_qt/config_window.py:530 msgid "Linux keyboard layout:" msgstr "Linux 鍵盤佈局:" -#: plover/gui_qt/config_window.py:547 +#: plover/gui_qt/config_window.py:544 msgid "" "Set the keyboard layout configured in your system.\n" "This only applies when using Linux/BSD and not using X11.\n" @@ -646,35 +646,35 @@ msgstr "" "當選取 Wayland 自動偵測時,Plover 僅能偵測第一個鍵盤佈局,\n" "且無法偵測佈局切換。" -#: plover/gui_qt/config_window.py:557 +#: plover/gui_qt/config_window.py:554 msgid "" "When Wayland auto detect is selected, Plover is only able to detect the " "first keyboard layout and can not detect layout switches." msgstr "當選取 Wayland 自動偵測時,Plover 僅能偵測第一個鍵盤佈局,且無法偵測佈局切換。" -#: plover/gui_qt/config_window.py:568 +#: plover/gui_qt/config_window.py:565 msgid "Plugins" msgstr "外掛程式" -#: plover/gui_qt/config_window.py:571 +#: plover/gui_qt/config_window.py:568 msgid "Extensions:" msgstr "擴充功能:" #. Widget: “MainWindow”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/main_window_ui.py:294 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/main_window_ui.py:294 msgid "Enabled" msgstr "已啟用" #. Widget: “PluginsManager”, text. -#: plover/gui_qt/config_window.py:579 plover/gui_qt/plugins_manager_ui.py:137 +#: plover/gui_qt/config_window.py:576 plover/gui_qt/plugins_manager_ui.py:137 msgid "Name" msgstr "名稱" -#: plover/gui_qt/config_window.py:581 +#: plover/gui_qt/config_window.py:578 msgid "Configure enabled plugin extensions." msgstr "設定已開啟的外掛程式。" -#: plover/gui_qt/config_window.py:590 +#: plover/gui_qt/config_window.py:587 msgid "System:" msgstr "語言系統:" @@ -701,83 +701,83 @@ msgid "{format} dictionaries ({extensions})" msgstr "{format} 字典 ({extensions})" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:391 +#: plover/gui_qt/dictionaries_widget.py:393 msgid "disabled" msgstr "已停用" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:394 +#: plover/gui_qt/dictionaries_widget.py:396 msgid "favorite" msgstr "最愛" -#: plover/gui_qt/dictionaries_widget.py:398 +#: plover/gui_qt/dictionaries_widget.py:400 #, python-brace-format msgid "errored: {exception}." msgstr "錯誤:{exception}。" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:402 +#: plover/gui_qt/dictionaries_widget.py:404 msgid "loading" msgstr "載入中…" #. Widget: “DictionariesWidget”, accessible text. -#: plover/gui_qt/dictionaries_widget.py:405 +#: plover/gui_qt/dictionaries_widget.py:407 msgid "read-only" msgstr "唯讀" #. Widget: “DictionariesWidget”, tooltip. -#: plover/gui_qt/dictionaries_widget.py:411 +#: plover/gui_qt/dictionaries_widget.py:413 #, python-brace-format msgid "Full path: {path}." msgstr "完整路徑:{path}。" #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:414 +#: plover/gui_qt/dictionaries_widget.py:416 msgid "This dictionary is marked as the favorite." msgstr "此字典已標記為最愛。" #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:417 +#: plover/gui_qt/dictionaries_widget.py:419 msgid "This dictionary is being loaded." msgstr "字典正在載入中…" -#: plover/gui_qt/dictionaries_widget.py:421 +#: plover/gui_qt/dictionaries_widget.py:423 #, python-brace-format msgid "Loading this dictionary failed: {exception}." msgstr "載入此字典失敗:{exception}。" #. Widget: “DictionariesWidget”, tool tip. -#: plover/gui_qt/dictionaries_widget.py:427 +#: plover/gui_qt/dictionaries_widget.py:429 msgid "This dictionary is read-only." msgstr "字典為唯讀狀態。" #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:618 +#: plover/gui_qt/dictionaries_widget.py:620 #, python-brace-format msgid "Save a copy of {name} as..." msgstr "將{name}另存至..." #. Widget: “DictionariesWidget”, “save as copy” file picker. -#: plover/gui_qt/dictionaries_widget.py:620 +#: plover/gui_qt/dictionaries_widget.py:622 #, python-brace-format msgid "{name} - Copy" msgstr "{name} - 副本" #. Widget: “DictionariesWidget”, “save as merge” file picker. -#: plover/gui_qt/dictionaries_widget.py:642 +#: plover/gui_qt/dictionaries_widget.py:644 #, python-brace-format msgid "Merge {names} as..." msgstr "合併 {names} 為..." #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:671 +#: plover/gui_qt/dictionaries_widget.py:673 #: plover/gui_qt/dictionaries_widget_ui.py:203 msgid "Load dictionaries" msgstr "載入字典" #. Widget: “DictionariesWidget”, “new” file picker. #. Widget: “DictionariesWidget”, text. -#: plover/gui_qt/dictionaries_widget.py:683 +#: plover/gui_qt/dictionaries_widget.py:685 #: plover/gui_qt/dictionaries_widget_ui.py:205 msgid "Create dictionary" msgstr "建立字典" @@ -1001,11 +1001,11 @@ msgid "Mappings" msgstr "對映" #. Widget: “LookupDialog”, tooltip. -#: plover/gui_qt/lookup_dialog.py:12 +#: plover/gui_qt/lookup_dialog.py:11 msgid "Search the dictionary for translations." msgstr "在字典內尋找翻譯。" -#: plover/gui_qt/lookup_dialog.py:14 +#: plover/gui_qt/lookup_dialog.py:13 msgid "Lookup" msgstr "查詢" @@ -1029,27 +1029,27 @@ msgstr "要查詢的翻譯樣式。" msgid "Results" msgstr "結果" -#: plover/gui_qt/machine_options.py:38 +#: plover/gui_qt/machine_options.py:36 #, python-brace-format msgid "product: {value}" msgstr "產品:{value}" -#: plover/gui_qt/machine_options.py:39 +#: plover/gui_qt/machine_options.py:37 #, python-brace-format msgid "manufacturer: {value}" msgstr "製造商:{value}" -#: plover/gui_qt/machine_options.py:40 +#: plover/gui_qt/machine_options.py:38 #, python-brace-format msgid "serial number: {value}" msgstr "序號:{value}" -#: plover/gui_qt/machine_options.py:48 +#: plover/gui_qt/machine_options.py:46 #, python-brace-format msgid "description: {value}" msgstr "描述:{value}" -#: plover/gui_qt/machine_options.py:201 +#: plover/gui_qt/machine_options.py:199 msgid "" "Arpeggiate allows using non-NKRO keyboards.\n" "\n" @@ -1061,7 +1061,7 @@ msgstr "" "每個鍵可以分開來輸出,\n" "最後按下空白鍵以送出和弦。" -#: plover/gui_qt/main_window.py:312 +#: plover/gui_qt/main_window.py:310 msgid "Application is still running." msgstr "應用程式仍在執行中。" @@ -1214,34 +1214,34 @@ msgid "Plover: Toolbar" msgstr "Plover: 工具列" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:30 +#: plover/gui_qt/paper_tape.py:27 msgid "Paper" msgstr "紙帶模式" #. Paper tape style. -#: plover/gui_qt/paper_tape.py:32 +#: plover/gui_qt/paper_tape.py:29 msgid "Raw" msgstr "原始模式" #. Widget: “PaperTape”, tooltip. -#: plover/gui_qt/paper_tape.py:122 +#: plover/gui_qt/paper_tape.py:119 msgid "Paper tape display of strokes." msgstr "紙帶顯示和弦。" -#: plover/gui_qt/paper_tape.py:124 +#: plover/gui_qt/paper_tape.py:121 msgid "Paper Tape" msgstr "紙帶" -#: plover/gui_qt/paper_tape.py:237 +#: plover/gui_qt/paper_tape.py:234 msgid "Do you want to clear the paper tape?" msgstr "確認要清除紙帶嗎?" -#: plover/gui_qt/paper_tape.py:255 +#: plover/gui_qt/paper_tape.py:254 msgid "Save Paper Tape" msgstr "將紙帶存檔" #. Paper tape, "save" file picker. -#: plover/gui_qt/paper_tape.py:258 +#: plover/gui_qt/paper_tape.py:257 msgid "Text files (*.txt)" msgstr "Text 文字檔 (*.txt)" @@ -1331,22 +1331,22 @@ msgid "N/A" msgstr "不適用" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:127 +#: plover/gui_qt/plugins_manager.py:126 #, python-format msgid "

Author: %s

" msgstr "

作者:%s

" #. Metadata field. -#: plover/gui_qt/plugins_manager.py:133 +#: plover/gui_qt/plugins_manager.py:132 #, python-format msgid "

Home page: %s

" msgstr "

首頁:%s

" -#: plover/gui_qt/plugins_manager.py:180 +#: plover/gui_qt/plugins_manager.py:179 msgid "Install from Git repo" msgstr "從 Git 儲存庫安裝" -#: plover/gui_qt/plugins_manager.py:182 +#: plover/gui_qt/plugins_manager.py:181 msgid "" "WARNING: Installing plugins is a security risk.
A plugin from a Git" " repo can contain malicious code.
Only install it if you got it from a" @@ -1357,24 +1357,24 @@ msgstr "" "儲存庫的外掛程式可能包含惡意代碼。
僅在您從信任的來源獲取時才進行安裝。


輸入外掛程式的儲存庫連結
(看起來類似於" " https://github.com/user/repository.git):
" -#: plover/gui_qt/plugins_manager.py:204 +#: plover/gui_qt/plugins_manager.py:203 #, python-brace-format msgid "Install {packages}" msgstr "安裝 {packages}" -#: plover/gui_qt/plugins_manager.py:206 +#: plover/gui_qt/plugins_manager.py:205 msgid "" "Installing plugins is a security risk. A plugin can contain " "virus/malware. Only install it if you got it from a trusted source. Are " "you sure you want to proceed?" msgstr "安裝外掛程式是一個安全風險。外掛程式可能包含病毒或惡意軟體。僅在您從信任的來源獲取時才進行安裝。您確定要繼續嗎?" -#: plover/gui_qt/plugins_manager.py:233 +#: plover/gui_qt/plugins_manager.py:232 #, python-brace-format msgid "Uninstall {packages}" msgstr "解除安裝 {packages}" -#: plover/gui_qt/plugins_manager.py:234 +#: plover/gui_qt/plugins_manager.py:233 msgid "Are you sure you want to proceed?" msgstr "您確定要繼續嗎?" @@ -1415,23 +1415,23 @@ msgid "..." msgstr "..." #. Widget: “SuggestionsDialog”, tooltip. -#: plover/gui_qt/suggestions_dialog.py:26 +#: plover/gui_qt/suggestions_dialog.py:25 msgid "Suggest possible strokes for the last written words." msgstr "最後輸入文字的所有可能和弦建議。" #. Widget: “SuggestionsDialog”, accessible name. -#: plover/gui_qt/suggestions_dialog.py:28 +#: plover/gui_qt/suggestions_dialog.py:27 #: plover/gui_qt/suggestions_dialog_ui.py:97 msgid "Suggestions" msgstr "和弦建議" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:62 +#: plover/gui_qt/suggestions_dialog.py:61 msgid "&Text" msgstr "&文字" #. Widget: “SuggestionsDialog”, “font” menu. -#: plover/gui_qt/suggestions_dialog.py:64 +#: plover/gui_qt/suggestions_dialog.py:63 msgid "&Strokes" msgstr "&和弦" @@ -1441,7 +1441,7 @@ msgid "Clear the history." msgstr "清除歷史紀錄。" #. Widget: “SuggestionsWidget”. -#: plover/gui_qt/suggestions_widget.py:27 +#: plover/gui_qt/suggestions_widget.py:26 msgid "no suggestions" msgstr "無和弦建議" @@ -1485,7 +1485,7 @@ msgid "disconnected" msgstr "尚未連接" #. Machine name. -#: plover/machine/keyboard.py:16 +#: plover/machine/keyboard.py:14 msgid "Keyboard" msgstr "鍵盤" diff --git a/plover/meta/attach.py b/plover/meta/attach.py index 756c01846..e34a537d2 100644 --- a/plover/meta/attach.py +++ b/plover/meta/attach.py @@ -1,9 +1,9 @@ from os.path import commonprefix from plover.formatting import ( - Case, META_ATTACH_FLAG, META_CARRY_CAPITALIZATION, + Case, has_word_boundary, rightmost_word, ) diff --git a/plover/meta/conditional.py b/plover/meta/conditional.py index 57fbadb2d..0df062ae4 100644 --- a/plover/meta/conditional.py +++ b/plover/meta/conditional.py @@ -2,7 +2,6 @@ from plover.formatting import _LookAheadAction - IF_NEXT_META_RX = re.compile(r"((?:[^\\/]|\\\\|\\/)*)/?") IF_NEXT_ESCAPE_RX = re.compile(r"\\([\\/])") diff --git a/plover/meta/mode.py b/plover/meta/mode.py index fdf474827..156c8ecb1 100644 --- a/plover/meta/mode.py +++ b/plover/meta/mode.py @@ -1,4 +1,4 @@ -from plover.formatting import Case, SPACE +from plover.formatting import SPACE, Case def meta_mode(ctx, cmdline): @@ -23,7 +23,7 @@ def meta_mode(ctx, cmdline): return action # No argument allowed for other mode directives. if args: - raise ValueError("%r is not a valid mode" % cmdline) + raise ValueError(f"{cmdline!r} is not a valid mode") if mode == "caps": action.case = Case.UPPER elif mode == "title": @@ -44,5 +44,5 @@ def meta_mode(ctx, cmdline): elif mode == "reset_case": action.case = None else: - raise ValueError("%r is not a valid mode" % cmdline) + raise ValueError(f"{cmdline!r} is not a valid mode") return action diff --git a/plover/oslayer/__init__.py b/plover/oslayer/__init__.py index 6c812405b..abb87ef8d 100644 --- a/plover/oslayer/__init__.py +++ b/plover/oslayer/__init__.py @@ -9,7 +9,6 @@ from .config import PLATFORM - PLATFORM_PACKAGE = { "bsd": "linux", "linux": "linux", @@ -21,7 +20,7 @@ def _add_platform_package_to_path(): platform_package = PLATFORM_PACKAGE.get(PLATFORM) if platform_package is None: - log.warning("No platform-specific oslayer package for: %s" % PLATFORM) + log.warning(f"No platform-specific oslayer package for: {PLATFORM}") return __path__.insert(0, os.path.join(__path__[0], platform_package)) diff --git a/plover/oslayer/config.py b/plover/oslayer/config.py index 9ef2d69c3..aac440e4c 100644 --- a/plover/oslayer/config.py +++ b/plover/oslayer/config.py @@ -8,7 +8,6 @@ import appdirs - if sys.platform.startswith("darwin"): PLATFORM = "mac" elif sys.platform.startswith("linux"): diff --git a/plover/oslayer/controller.py b/plover/oslayer/controller.py index bd7bea037..ebc3fa98d 100644 --- a/plover/oslayer/controller.py +++ b/plover/oslayer/controller.py @@ -1,8 +1,8 @@ -from multiprocessing import connection -from threading import Thread import errno import os import tempfile +from multiprocessing import connection +from threading import Thread from plover import log from plover.oslayer.config import PLATFORM diff --git a/plover/oslayer/linux/i18n.py b/plover/oslayer/linux/i18n.py index 006635304..33d6b64a0 100644 --- a/plover/oslayer/linux/i18n.py +++ b/plover/oslayer/linux/i18n.py @@ -1,7 +1,6 @@ import locale import os - # Note: highest priority first. LANG_ENV_VARS = ("LC_ALL", "LC_MESSAGES", "LANG") diff --git a/plover/oslayer/linux/keyboardcontrol_uinput.py b/plover/oslayer/linux/keyboardcontrol_uinput.py index 33a98e900..f4835c684 100644 --- a/plover/oslayer/linux/keyboardcontrol_uinput.py +++ b/plover/oslayer/linux/keyboardcontrol_uinput.py @@ -1,18 +1,23 @@ -import threading import os import selectors +import threading from evdev import ( - UInput, - ecodes as e, - util, InputDevice, - list_devices, InputEvent, KeyEvent, + UInput, + list_devices, + util, +) +from evdev import ( + ecodes as e, ) from psutil import process_iter +from plover import log +from plover.key_combo import parse_key_combo +from plover.machine.keyboard_capture import Capture from plover.oslayer.linux.keyboardlayout_wayland import ( DEFAULT_LAYOUT, GET_WAYLAND_KEYMAP_TIMEOUT_SECONDS, @@ -20,15 +25,12 @@ LAYOUTS, WAYLAND_AUTO_LAYOUT_NAME, KeyCodeInfo, + ev_keycode_to_xkb_keycode, generate_plover_keymap_from_xkb_keymap_and_modifiers, get_modifier_keycodes, - ev_keycode_to_xkb_keycode, get_wayland_keymap, ) from plover.output.keyboard import GenericKeyboardEmulation -from plover.machine.keyboard_capture import Capture -from plover.key_combo import parse_key_combo -from plover import log # EV keycodes of keys considered modifiers when not able to automatically be # determined from the keymap (this feature isn't implemented yet). @@ -97,11 +99,11 @@ def _update_layout(self, layout): log.debug("Retrieved Wayland keymap: %s", self._key_to_keycodeinfo) # Verify that no modifier requires modifiers to be pressed in the generated keymap - modifier_xkb_keycodes = set( + modifier_xkb_keycodes = { keycode for keycodes in modifier_index_to_xkb_keycode for keycode in keycodes - ) + } log.debug( "Modifier index to keycode: %s", modifier_index_to_xkb_keycode ) @@ -190,9 +192,7 @@ def _verify_can_send_unicode_key_combo(self) -> bool: return False if not self._get_key("shift")[0]: return False - if not self._get_key("u")[0]: - return False - return True + return self._get_key("u")[0] def send_string(self, string): for key in self.with_delay(list(string)): diff --git a/plover/oslayer/linux/keyboardcontrol_x11.py b/plover/oslayer/linux/keyboardcontrol_x11.py index 4d7361b46..99f115b7c 100644 --- a/plover/oslayer/linux/keyboardcontrol_x11.py +++ b/plover/oslayer/linux/keyboardcontrol_x11.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # # Copyright (c) 2010 Joshua Harlan Lifton. # See LICENSE.txt for details. @@ -25,7 +24,7 @@ import select import threading -from Xlib import X, XK +from Xlib import XK, X from Xlib.display import Display from Xlib.ext import xinput, xtest from Xlib.ext.ge import GenericEventCode @@ -35,7 +34,6 @@ from plover.machine.keyboard_capture import Capture from plover.output.keyboard import GenericKeyboardEmulation - # Enable support for media keys. XK.load_keysym_group("xf86") # Load non-us keyboard related keysyms. @@ -258,7 +256,7 @@ def start(self): self._event_loop = XEventLoop(self._on_event, name="KeyboardCapture") with self._event_loop as display: if not display.has_extension("XInputExtension"): - raise Exception( + raise RuntimeError( "X11's XInput extension is required, but could not be found." ) self._update_devices(display) @@ -1137,12 +1135,10 @@ def __init__(self, keycode, modifiers, keysym, custom_mapping=None): self.custom_mapping = custom_mapping def __str__(self): - return "%u:%x=%x[%s]%s" % ( - self.keycode, - self.modifiers, - self.keysym, - keysym_to_string(self.keysym), - "" if self.custom_mapping is None else "*", + return ( + f"{self.keycode}:{self.modifiers:x}={self.keysym:x}" + f"[{keysym_to_string(self.keysym)}]" + f"{'' if self.custom_mapping is None else '*'}" ) # We can use the first 2 entry of a X11 mapping: diff --git a/plover/oslayer/linux/keyboardlayout_wayland.py b/plover/oslayer/linux/keyboardlayout_wayland.py index 6b3ef4720..467f9c7b1 100644 --- a/plover/oslayer/linux/keyboardlayout_wayland.py +++ b/plover/oslayer/linux/keyboardlayout_wayland.py @@ -1,13 +1,14 @@ -from dataclasses import dataclass -from typing import Sequence -import string import contextlib import mmap import os +import string import threading +from collections.abc import Sequence +from dataclasses import dataclass +from evdev import ecodes as e +from evdev import util from xkbcommon import xkb -from evdev import ecodes as e, util from plover.key_combo import add_modifiers_aliases from plover.oslayer.linux.wayland_connection import ( @@ -96,7 +97,7 @@ def get_modifier_keycodes(keymap: xkb.Keymap) -> list[list[int]]: num_layouts = keymap.num_layouts_for_key(keycode) - for layout in range(0, num_layouts): + for layout in range(num_layouts): layout_is_active = keyboard_state.layout_index_is_active( layout, xkb.StateComponent.XKB_STATE_LAYOUT_EFFECTIVE ) @@ -398,7 +399,7 @@ def get_modifiers_for_key_sym( } # Make sure no keys missing. The last 3 are "\r\x0b\x0c" which don't need to be mapped. -assert all(c in LAYOUTS[DEFAULT_LAYOUT].keys() for c in string.printable[:-3]) +assert all(c in LAYOUTS[DEFAULT_LAYOUT] for c in string.printable[:-3]) if __name__ == "__main__": xkb_keymap = get_wayland_keymap(GET_WAYLAND_KEYMAP_TIMEOUT_SECONDS) diff --git a/plover/oslayer/linux/log_dbus.py b/plover/oslayer/linux/log_dbus.py index b580cb131..acac30688 100644 --- a/plover/oslayer/linux/log_dbus.py +++ b/plover/oslayer/linux/log_dbus.py @@ -1,12 +1,12 @@ -from contextlib import contextmanager import ctypes.util -import os import logging +import os +from contextlib import contextmanager -from plover import log, __name__ as __software_name__ +from plover import __name__ as __software_name__ +from plover import log from plover.oslayer.config import ASSETS_DIR - APPNAME = ctypes.c_char_p(__software_name__.capitalize().encode()) APPICON = ctypes.c_char_p(os.path.join(ASSETS_DIR, "plover.png").encode()) SERVICE = ctypes.c_char_p(b"org.freedesktop.Notifications") @@ -167,9 +167,7 @@ def append_basic(kind, value): error_init(error) bus = bus_get(DBUS_BUS_SESSION, ctypes.byref(error)) if error_is_set(error): - e = ConnectionError( - "%s: %s" % (error.name.decode(), error.message.decode()) - ) + e = ConnectionError(f"{error.name.decode()}: {error.message.decode()}") error_free(error) raise e assert bus is not None @@ -217,8 +215,7 @@ def notify(body, urgency, timeout): def handle(self, record): level = record.levelno message = self.format(record) - if message.endswith("\n"): - message = message[:-1] + message = message.removesuffix("\n") if level <= log.INFO: timeout = 10 urgency = NOTIFY_URGENCY_LOW diff --git a/plover/oslayer/linux/wayland_connection.py b/plover/oslayer/linux/wayland_connection.py index 08369d95c..91cbc26ec 100644 --- a/plover/oslayer/linux/wayland_connection.py +++ b/plover/oslayer/linux/wayland_connection.py @@ -152,7 +152,7 @@ def _recv_fds_exact(self, length: int, fd_count: int): if key.fileobj == self._shutdown_pipe_read: raise InterruptedError() # Based on Python3 socket.recvmsg docs (https://docs.python.org/3/library/socket.html#socket.socket.recvmsg) - n, ancdata, flags, addr = self._wayland_socket.recvmsg_into( + n, ancdata, _flags, _addr = self._wayland_socket.recvmsg_into( [buffer_view], socket.CMSG_LEN(fd_count * fds.itemsize) ) for cmsg_level, cmsg_type, cmsg_data in ancdata: @@ -245,7 +245,7 @@ def wayland_keymap_event_loop(connection: WaylandConnection) -> tuple[int, int]: break elif object_id == DISPLAY_ID and opcode == OPCODE_WL_DISPLAY_ERROR: # wl_display::error - raise RuntimeError(f"Wayland error: {repr(event_data_bytes)}") + raise RuntimeError(f"Wayland error: {event_data_bytes!r}") elif object_id == DISPLAY_ID and opcode == OPCODE_WL_DISPLAY_DELETE_ID: # wl_display::delete_id if length != WAYLAND_MESSAGE_HEADER_SIZE_BYTES + 4: @@ -288,6 +288,6 @@ def wayland_keymap_event_loop(connection: WaylandConnection) -> tuple[int, int]: return fd, keymap_size elif object_id == DISPLAY_ID and opcode == OPCODE_WL_DISPLAY_ERROR: # wl_display::error - raise RuntimeError(f"Wayland error: {repr(event_data_bytes)}") + raise RuntimeError(f"Wayland error: {event_data_bytes!r}") else: log.debug("Ignoring event for object %d, opcode %d", object_id, opcode) diff --git a/plover/oslayer/linux/wmctrl_x11.py b/plover/oslayer/linux/wmctrl_x11.py index e7479ba08..6d64dca8d 100644 --- a/plover/oslayer/linux/wmctrl_x11.py +++ b/plover/oslayer/linux/wmctrl_x11.py @@ -9,12 +9,12 @@ def __init__(self): self._root = self._display.screen().root self._atoms = { name: self._display.intern_atom(name) - for name in """ - _NET_ACTIVE_WINDOW - _NET_CURRENT_DESKTOP - _NET_WM_DESKTOP - _WIN_WORKSPACE - """.split() + for name in [ + "_NET_ACTIVE_WINDOW", + "_NET_CURRENT_DESKTOP", + "_NET_WM_DESKTOP", + "_WIN_WORKSPACE", + ] } def _get_wm_property(self, window, atom_name): diff --git a/plover/oslayer/osx/keyboardcontrol.py b/plover/oslayer/osx/keyboardcontrol.py index 4973454a9..263a844bd 100644 --- a/plover/oslayer/osx/keyboardcontrol.py +++ b/plover/oslayer/osx/keyboardcontrol.py @@ -1,18 +1,17 @@ -# coding: utf-8 - import threading -from time import sleep from queue import Queue +from time import sleep +from typing import ClassVar from Quartz import ( CFMachPortCreateRunLoopSource, CFMachPortInvalidate, + CFRelease, CFRunLoopAddSource, - CFRunLoopSourceInvalidate, CFRunLoopGetCurrent, CFRunLoopRun, + CFRunLoopSourceInvalidate, CFRunLoopStop, - CFRelease, CGEventCreateKeyboardEvent, CGEventGetFlags, CGEventGetIntegerValueField, @@ -23,6 +22,8 @@ CGEventSourceCreate, CGEventTapCreate, CGEventTapEnable, + NSEvent, + NSSystemDefined, kCFRunLoopCommonModes, kCGEventFlagMaskAlternate, kCGEventFlagMaskCommand, @@ -33,24 +34,21 @@ kCGEventFlagMaskShift, kCGEventKeyDown, kCGEventKeyUp, + kCGEventSourceStateHIDSystemState, kCGEventTapDisabledByTimeout, kCGEventTapOptionDefault, kCGHeadInsertEventTap, kCGKeyboardEventKeycode, kCGSessionEventTap, - kCGEventSourceStateHIDSystemState, - NSEvent, - NSSystemDefined, ) from plover import log -from plover.key_combo import add_modifiers_aliases, parse_key_combo, KEYNAME_TO_CHAR +from plover.key_combo import KEYNAME_TO_CHAR, add_modifiers_aliases, parse_key_combo from plover.machine.keyboard_capture import Capture from plover.output.keyboard import GenericKeyboardEmulation from .keyboardlayout import KeyboardLayout - BACK_SPACE = 51 NX_KEY_OFFSET = 65536 @@ -292,7 +290,7 @@ def start(self): if self._tap is None: # TODO: See if there is a nice way to show # the user what's needed (or do it for them). - raise Exception("Enable access for assistive devices.") + raise RuntimeError("Enable access for assistive devices.") self._source = CFMachPortCreateRunLoopSource(None, self._tap, 0) loop_is_set = threading.Event() self._thread = threading.Thread( @@ -318,7 +316,7 @@ def cancel(self): class KeyboardCapture(Capture): - _KEYBOARD_EVENTS = {kCGEventKeyDown, kCGEventKeyUp} + _KEYBOARD_EVENTS: ClassVar[set] = {kCGEventKeyDown, kCGEventKeyUp} # Don't ignore Fn and Numeric flags so we can handle # the arrow and extended (home, end, etc...) keys. @@ -480,13 +478,13 @@ def name_to_code(name): pass # Dead keys elif name.startswith("dead_"): - code, mod = self._layout.deadkey_symbol_to_key_sequence( + code, _mod = self._layout.deadkey_symbol_to_key_sequence( DEADKEY_SYMBOLS.get(name) )[0] # Normal keys else: char = KEYNAME_TO_CHAR.get(name, name) - code, mods = self._layout.char_to_key_sequence(char)[0] + code, _mods = self._layout.char_to_key_sequence(char)[0] return code # Parse and validate combo. diff --git a/plover/oslayer/osx/keyboardlayout.py b/plover/oslayer/osx/keyboardlayout.py index 9a6b7cbb1..b193e4af7 100644 --- a/plover/oslayer/osx/keyboardlayout.py +++ b/plover/oslayer/osx/keyboardlayout.py @@ -1,26 +1,23 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- # Author: @abarnert, @willwade, and @morinted # Code taken and modified from # # -from threading import Thread import ctypes import ctypes.util import re import struct import unicodedata +from threading import Thread -from PyObjCTools import AppHelper import AppKit import Foundation +from PyObjCTools import AppHelper from plover import log from plover.key_combo import CHAR_TO_KEYNAME from plover.misc import popcount_8 - carbon_path = ctypes.util.find_library("Carbon") carbon = ctypes.cdll.LoadLibrary(carbon_path) @@ -97,10 +94,8 @@ def is_printable(string): category = unicodedata.category(character) if category[0] in "C": # Exception: the "Apple" character that most Mac layouts have - return False if string != "" else True - elif category == "Zs" and character != " ": - return False - elif category in "Zl, Zp": + return string == "\uf8ff" + elif category == "Zs" and character != " " or category in "Zl, Zp": return False return True @@ -186,25 +181,25 @@ def _deadkeys_by_symbols(self): deadkeys_by_symbol = {} for symbol, equivalent_symbols in symbols.items(): for equivalent_symbol in equivalent_symbols: - sequence = self.char_to_key_sequence("dk%s" % equivalent_symbol) + sequence = self.char_to_key_sequence(f"dk{equivalent_symbol}") if sequence[0][0] is not None: deadkeys_by_symbol[symbol] = sequence return deadkeys_by_symbol def format_modifier_header(self): modifiers = ( - "| {}\t".format(KeyboardLayout._modifier_string(mod)).expandtabs(8) + f"| {KeyboardLayout._modifier_string(mod)}\t".expandtabs(8) for mod in sorted(self._modifier_masks.values()) ) header = "Keycode\t{}".format("".join(modifiers)) - return "%s\n%s" % (header, re.sub(r"[^|]", "-", header)) + return "{}\n{}".format(header, re.sub(r"[^|]", "-", header)) def format_keycode_keys(self, keycode): """Returns all the variations of the keycode with modifiers""" keys = ( - "| {}\t".format( - get_printable_string(self._key_sequence_to_char[keycode, mod]) - ).expandtabs(8) + f"| {get_printable_string(self._key_sequence_to_char[keycode, mod])}\t".expandtabs( + 8 + ) for mod in sorted(self._modifier_masks.values()) ) @@ -271,7 +266,7 @@ def _get_layout(): @staticmethod def _parse_layout(buf, ktype): - hf, dv, featureinfo, ktcount = struct.unpack_from("HHII", buf) + _hf, _dv, _featureinfo, ktcount = struct.unpack_from("HHII", buf) offset = struct.calcsize("HHII") ktsize = struct.calcsize("IIIIIII") kts = [ @@ -284,10 +279,10 @@ def _parse_layout(buf, ktype): break else: kentry = 0 - ktf, ktl, modoff, charoff, sroff, stoff, seqoff = kts[kentry] + _ktf, _ktl, modoff, charoff, sroff, stoff, seqoff = kts[kentry] # Modifiers - mf, deftable, mcount = struct.unpack_from("HHI", buf, modoff) + _mf, _deftable, mcount = struct.unpack_from("HHI", buf, modoff) modtableoff = modoff + struct.calcsize("HHI") modtables = struct.unpack_from("B" * mcount, buf, modtableoff) modifier_masks = {} @@ -297,7 +292,7 @@ def _parse_layout(buf, ktype): # Sequences sequences = [] if seqoff: - sf, scount = struct.unpack_from("HH", buf, seqoff) + _sf, scount = struct.unpack_from("HH", buf, seqoff) seqtableoff = seqoff + struct.calcsize("HH") lastoff = -1 for soff in struct.unpack_from("H" * scount, buf, seqtableoff): @@ -319,7 +314,7 @@ def lookupseq(key): # Dead keys deadkeys = [] if sroff: - srf, srcount = struct.unpack_from("HH", buf, sroff) + _srf, srcount = struct.unpack_from("HH", buf, sroff) srtableoff = sroff + struct.calcsize("HH") for recoff in struct.unpack_from("I" * srcount, buf, srtableoff): cdata, nextstate, ecount, eformat = struct.unpack_from( @@ -330,7 +325,7 @@ def lookupseq(key): deadkeys.append((cdata, nextstate, ecount, eformat, edata)) if stoff: - stf, stcount = struct.unpack_from("HH", buf, stoff) + _stf, stcount = struct.unpack_from("HH", buf, stoff) sttableoff = stoff + struct.calcsize("HH") dkterms = struct.unpack_from("H" * stcount, buf, sttableoff) else: @@ -400,10 +395,11 @@ def save_shortest_key_sequence(character, new_sequence): elif len(new_sequence) < len(current_sequence): char_to_key_sequence[character] = new_sequence[0] # Favor fewer modifiers on last item - elif last_current_better < 0: - char_to_key_sequence[character] = new_sequence - # Favor lower modifiers on first item if last item is the same - elif last_current_better == 0 and first_current_better < 0: + elif ( + last_current_better < 0 + or last_current_better == 0 + and first_current_better < 0 + ): char_to_key_sequence[character] = new_sequence def lookup_and_add(key, j, mod): @@ -411,7 +407,7 @@ def lookup_and_add(key, j, mod): save_shortest_key_sequence(ch, (j, mod)) key_sequence_to_char[j, mod] = ch - cf, csize, ccount = struct.unpack_from("HHI", buf, charoff) + _cf, csize, ccount = struct.unpack_from("HHI", buf, charoff) chartableoff = charoff + struct.calcsize("HHI") for i, table_offset in enumerate( @@ -422,7 +418,7 @@ def lookup_and_add(key, j, mod): if key == 65535: key_sequence_to_char[j, mod] = "mod" elif key >= 0xFFFE: - key_sequence_to_char[j, mod] = "<{}>".format(key) + key_sequence_to_char[j, mod] = f"<{key}>" elif key & 0x0C000 == 0x4000: dead = key & ~0xC000 if dead < len(deadkeys): @@ -433,21 +429,19 @@ def lookup_and_add(key, j, mod): current_deadkey = deadkey_state_to_key_sequence.setdefault( nextstate, new_deadkey ) - if new_deadkey != current_deadkey: - if ( - favored_modifiers( - current_deadkey[1], new_deadkey[1] - ) - < 0 - ): - deadkey_state_to_key_sequence[nextstate] = ( - new_deadkey - ) + if ( + new_deadkey != current_deadkey + and favored_modifiers( + current_deadkey[1], new_deadkey[1] + ) + < 0 + ): + deadkey_state_to_key_sequence[nextstate] = new_deadkey if nextstate - 1 < len(dkterms): base_key = lookupseq(dkterms[nextstate - 1]) - dead_key_name = "dk{}".format(base_key) + dead_key_name = f"dk{base_key}" else: - dead_key_name = "dk#{}".format(nextstate) + dead_key_name = f"dk#{nextstate}" key_sequence_to_char[j, mod] = dead_key_name save_shortest_key_sequence(dead_key_name, (j, mod)) elif eformat == 1 or (eformat == 0 and not nextstate): @@ -496,10 +490,7 @@ def lookup_and_add(key, j, mod): sequence.append( ( code, - "{}{}".format( - layout._modifier_string(mod), - layout.key_code_to_char(code, 0), - ), + f"{layout._modifier_string(mod)}{layout.key_code_to_char(code, 0)}", ) ) else: diff --git a/plover/oslayer/osx/log.py b/plover/oslayer/osx/log.py index 44ae9ef0b..469711fc7 100644 --- a/plover/oslayer/osx/log.py +++ b/plover/oslayer/osx/log.py @@ -1,5 +1,7 @@ -import objc import logging + +import objc + from plover import log NSUserNotification = objc.lookUpClass("NSUserNotification") diff --git a/plover/oslayer/osx/wmctrl.py b/plover/oslayer/osx/wmctrl.py index 7d13cb1e1..61ae27a57 100644 --- a/plover/oslayer/osx/wmctrl.py +++ b/plover/oslayer/osx/wmctrl.py @@ -1,7 +1,7 @@ from Cocoa import ( - NSWorkspace, - NSRunningApplication, NSApplicationActivateIgnoringOtherApps, + NSRunningApplication, + NSWorkspace, ) diff --git a/plover/oslayer/windows/i18n.py b/plover/oslayer/windows/i18n.py index 53faaa360..1cde65e12 100644 --- a/plover/oslayer/windows/i18n.py +++ b/plover/oslayer/windows/i18n.py @@ -1,5 +1,4 @@ import locale - from ctypes import windll diff --git a/plover/oslayer/windows/keyboardcontrol.py b/plover/oslayer/windows/keyboardcontrol.py index e960dc10f..bb6e64666 100644 --- a/plover/oslayer/windows/keyboardcontrol.py +++ b/plover/oslayer/windows/keyboardcontrol.py @@ -13,7 +13,6 @@ """ -from ctypes import windll, wintypes import atexit import ctypes import multiprocessing @@ -21,6 +20,7 @@ import signal import threading import winreg +from ctypes import windll, wintypes from plover import log from plover.key_combo import parse_key_combo diff --git a/plover/oslayer/windows/keyboardlayout.py b/plover/oslayer/windows/keyboardlayout.py index 52a75c927..c0e747ec7 100644 --- a/plover/oslayer/windows/keyboardlayout.py +++ b/plover/oslayer/windows/keyboardlayout.py @@ -1,17 +1,14 @@ -# -*- coding: utf-8 -*- - -from collections import defaultdict, namedtuple -from ctypes import windll, wintypes import codecs import ctypes import sys +from collections import defaultdict, namedtuple +from ctypes import windll, wintypes from plover.key_combo import CHAR_TO_KEYNAME, add_modifiers_aliases from plover.misc import popcount_8 from .wmctrl import GetForegroundWindow - GetKeyboardLayout = windll.user32.GetKeyboardLayout GetKeyboardLayout.argtypes = [ wintypes.DWORD, # idThread @@ -60,7 +57,16 @@ def enum(name, items): ( (mod, n) for n, mod in enumerate( - "BASE SHIFT CTRL SHIFT_CTRL MENU SHIFT_MENU MENU_CTRL SHIFT_MENU_CTRL".split() + [ + "BASE", + "SHIFT", + "CTRL", + "SHIFT_CTRL", + "MENU", + "SHIFT_MENU", + "MENU_CTRL", + "SHIFT_MENU_CTRL", + ] ) ), ) @@ -247,7 +253,7 @@ def shift_state_str(ss): vk_dict["HANGUL"] = vk_dict["KANA"] vk_dict["KANJI"] = vk_dict["HANJA"] for digit in range(10): - vk_dict["DIGIT%u" % digit] = 0x30 + digit + vk_dict[f"DIGIT{digit}"] = 0x30 + digit for anum in range(26): vk_dict[chr(ord("A") + anum)] = 0x41 + anum VK = enum("VK", vk_dict.items()) @@ -356,7 +362,7 @@ def shift_state_str(ss): def vk_to_str(vk): s = VK_TO_NAME.get(vk) - return "%x" % vk if s is None else s + return f"{vk:x}" if s is None else s # }}} @@ -434,8 +440,7 @@ def sort_vk_ss_list(vk_ss_list): char, dead_key = to_unichr(vk, sc, ss) if debug and char: print( - "%s%s -> %s [%r] %s" - % ( + "{}{} -> {} [{!r}] {}".format( shift_state_str(ss), vk_to_str(vk), char, @@ -501,12 +506,11 @@ def current_layout_id(): if __name__ == "__main__": sys.stdout = codecs.getwriter("utf8")(sys.stdout) layout = KeyboardLayout(debug=True) - print("character to virtual key + shift state [%u]" % len(layout.char_to_vk_ss)) + print(f"character to virtual key + shift state [{len(layout.char_to_vk_ss)}]") for char, combo in sorted(layout.char_to_vk_ss.items()): vk, ss = combo print( - "%s [%r:%s] -> %s%s" - % ( + "{} [{!r}:{}] -> {}{}".format( char, char, CHAR_TO_KEYNAME.get(char, "?"), @@ -515,15 +519,16 @@ def current_layout_id(): ) ) print() - print("keyname to virtual key [%u]" % len(layout.keyname_to_vk)) + print(f"keyname to virtual key [{len(layout.keyname_to_vk)}]") for kn, vk in sorted(layout.keyname_to_vk.items()): - print("%s -> %s" % (kn, vk_to_str(vk))) + print(f"{kn} -> {vk_to_str(vk)}") print() - print("modifiers combo [%u]" % len(layout.ss_to_vks)) + print(f"modifiers combo [{len(layout.ss_to_vks)}]") for ss, vk_list in sorted(layout.ss_to_vks.items()): print( - "%s -> %s" - % (shift_state_str(ss), "+".join(vk_to_str(vk) for vk in vk_list)) + "{} -> {}".format( + shift_state_str(ss), "+".join(vk_to_str(vk) for vk in vk_list) + ) ) # vim: foldmethod=marker diff --git a/plover/oslayer/windows/log.py b/plover/oslayer/windows/log.py index 8c906a50e..63b34ce4a 100644 --- a/plover/oslayer/windows/log.py +++ b/plover/oslayer/windows/log.py @@ -1,8 +1,10 @@ -from plyer import notification import logging import os -from plover import log, __name__ as __software_name__ +from plyer import notification + +from plover import __name__ as __software_name__ +from plover import log from plover.oslayer.config import ASSETS_DIR APPNAME = __software_name__.capitalize() diff --git a/plover/oslayer/windows/wmctrl.py b/plover/oslayer/windows/wmctrl.py index cc41eb963..3c587cca1 100644 --- a/plover/oslayer/windows/wmctrl.py +++ b/plover/oslayer/windows/wmctrl.py @@ -1,6 +1,5 @@ from ctypes import windll, wintypes - GetForegroundWindow = windll.user32.GetForegroundWindow GetForegroundWindow.argtypes = [] GetForegroundWindow.restype = wintypes.HWND diff --git a/plover/plugins_manager/__main__.py b/plover/plugins_manager/__main__.py index 324286df5..bb436eb79 100644 --- a/plover/plugins_manager/__main__.py +++ b/plover/plugins_manager/__main__.py @@ -1,8 +1,8 @@ +import itertools import os -import subprocess import site +import subprocess import sys -import itertools from plover.plugins_manager import global_registry, local_registry from plover.plugins_manager.utils import running_under_virtualenv @@ -48,7 +48,7 @@ def pip(args, stdin=None, stdout=None, stderr=None, **kwargs): ) ) else: - raise ValueError("invalid command: %s" % command) + raise ValueError(f"invalid command: {command}") cmd.extend(args) return subprocess.Popen( cmd, env=env, stdin=stdin, stdout=stdout, stderr=stderr, **kwargs @@ -70,13 +70,13 @@ def list_plugins(freeze=False): info = latest or current if freeze: if current: - print("%s==%s" % (current.name, current.version)) + print(f"{current.name}=={current.version}") continue - print("%s (%s) - %s" % (info.name, info.version, info.summary)) + print(f"{info.name} ({info.version}) - {info.summary}") if current: - print(" INSTALLED: %s" % current.version) + print(f" INSTALLED: {current.version}") if latest: - print(" LATEST: %s" % latest.version) + print(f" LATEST: {latest.version}") def main(args=None): diff --git a/plover/plugins_manager/global_registry.py b/plover/plugins_manager/global_registry.py index 67a45caec..f81826334 100644 --- a/plover/plugins_manager/global_registry.py +++ b/plover/plugins_manager/global_registry.py @@ -12,5 +12,5 @@ def list_plugins(): release_info = release["info"] plugin_metadata = PluginMetadata.from_dict(release_info) plugins[canonicalize_name(plugin_metadata.name)].append(plugin_metadata) - plugins = {name: list(sorted(versions)) for name, versions in plugins.items()} + plugins = {name: sorted(versions) for name, versions in plugins.items()} return plugins diff --git a/plover/plugins_manager/local_registry.py b/plover/plugins_manager/local_registry.py index 85b4b4c63..94b522869 100644 --- a/plover/plugins_manager/local_registry.py +++ b/plover/plugins_manager/local_registry.py @@ -1,10 +1,10 @@ from collections import defaultdict +from importlib.metadata import distributions from pkginfo.distribution import Distribution as Metadata -from importlib.metadata import distributions -from plover.plugins_manager.plugin_metadata import PluginMetadata from plover import log +from plover.plugins_manager.plugin_metadata import PluginMetadata def list_plugins(): @@ -39,4 +39,4 @@ def list_plugins(): plugins[dist.metadata["Name"].lower()].append(plugin_metadata) # Sort and return plugins - return {name: list(sorted(versions)) for name, versions in plugins.items()} + return {name: sorted(versions) for name, versions in plugins.items()} diff --git a/plover/plugins_manager/package_index.py b/plover/plugins_manager/package_index.py index 53e9cd21d..73c4bd31c 100644 --- a/plover/plugins_manager/package_index.py +++ b/plover/plugins_manager/package_index.py @@ -1,10 +1,9 @@ -from concurrent.futures import as_completed import json import os +from concurrent.futures import as_completed from plover.plugins_manager.requests import CachedFuturesSession - PYPI_URL = "https://pypi.org/pypi" REGISTRY_URL = "https://raw.githubusercontent.com/openstenoproject/plover_plugins_registry/master/registry.json" @@ -26,9 +25,9 @@ def fetch_release(name, version=None): return all_releases[(name, version)] = None if version is None: - url = "%s/%s/json" % (pypi_url, name) + url = f"{pypi_url}/{name}/json" else: - url = "%s/%s/%s/json" % (pypi_url, name, version) + url = f"{pypi_url}/{name}/{version}/json" in_progress.add(session.get(url)) with session: diff --git a/plover/plugins_manager/plugin_metadata.py b/plover/plugins_manager/plugin_metadata.py index 2bfa54fdd..08140d555 100644 --- a/plover/plugins_manager/plugin_metadata.py +++ b/plover/plugins_manager/plugin_metadata.py @@ -24,7 +24,7 @@ class PluginMetadata( ): @property def requirement(self): - return "%s==%s" % (self.name, self.version) + return f"{self.name}=={self.version}" @property def parsed_version(self): diff --git a/plover/plugins_manager/registry.py b/plover/plugins_manager/registry.py index 44dcdc771..1db926cbb 100644 --- a/plover/plugins_manager/registry.py +++ b/plover/plugins_manager/registry.py @@ -1,7 +1,5 @@ -from plover import log, __version__ - +from plover import __version__, log from plover.plugins_manager import global_registry, local_registry - from plover.plugins_manager.requests import CachedFuturesSession @@ -90,7 +88,7 @@ def parse_unsupported_plover_version(self, unsupported_plover_version) -> int: f'Failed to parse unsupported plover version "{unsupported_plover_version}" from plugin metadata' ) from e else: - raise ValueError( + raise TypeError( f'Unknown format for unsupported plover version "{unsupported_plover_version}" from plugin metadata' ) diff --git a/plover/plugins_manager/requests.py b/plover/plugins_manager/requests.py index 34d678f35..7fadc35d9 100644 --- a/plover/plugins_manager/requests.py +++ b/plover/plugins_manager/requests.py @@ -1,5 +1,5 @@ -from requests_futures import sessions import requests_cache +from requests_futures import sessions class CachedSession(requests_cache.CachedSession): diff --git a/plover/plugins_manager/utils.py b/plover/plugins_manager/utils.py index d737aac68..faa568555 100644 --- a/plover/plugins_manager/utils.py +++ b/plover/plugins_manager/utils.py @@ -1,10 +1,9 @@ import sys -from pygments.formatters import HtmlFormatter import readme_renderer.markdown import readme_renderer.rst import readme_renderer.txt - +from pygments.formatters import HtmlFormatter _RENDERERS = { None: readme_renderer.rst, @@ -36,7 +35,5 @@ def running_under_virtualenv(): if sys.prefix != getattr(sys, "base_prefix", sys.prefix): # venv return True - if hasattr(sys, "real_prefix"): - # virtualenv - return True - return False + # virtualenv + return hasattr(sys, "real_prefix") diff --git a/plover/registry.py b/plover/registry.py index 1f29aba49..85fda5952 100644 --- a/plover/registry.py +++ b/plover/registry.py @@ -1,9 +1,8 @@ from collections import namedtuple +from importlib.metadata import PackageNotFoundError, entry_points -from importlib.metadata import entry_points, PackageNotFoundError - -from plover.oslayer.config import PLUGINS_PLATFORM from plover import log +from plover.oslayer.config import PLUGINS_PLATFORM class Plugin: diff --git a/plover/resource.py b/plover/resource.py index 933a4dd69..ba2d0d8d6 100644 --- a/plover/resource.py +++ b/plover/resource.py @@ -1,9 +1,8 @@ +import os +import shutil from contextlib import contextmanager from importlib.util import find_spec from tempfile import NamedTemporaryFile -import os -import shutil - ASSET_SCHEME = "asset:" @@ -47,7 +46,10 @@ def resource_update(resource_name): filename = resource_filename(resource_name) directory = os.path.dirname(filename) extension = os.path.splitext(filename)[1] - tempfile = NamedTemporaryFile(delete=False, dir=directory, suffix=extension or None) + # Only used to generate a unique filename: closed right away, removed on error. + tempfile = NamedTemporaryFile( # noqa: SIM115 + delete=False, dir=directory, suffix=extension or None + ) try: tempfile.close() yield tempfile.name diff --git a/plover/scripts/dist_main.py b/plover/scripts/dist_main.py index a06e59228..6b0facea6 100644 --- a/plover/scripts/dist_main.py +++ b/plover/scripts/dist_main.py @@ -1,6 +1,6 @@ import os -import sys import subprocess +import sys from plover.oslayer.config import CONFIG_DIR, PLATFORM, PLUGINS_PLATFORM diff --git a/plover/scripts/main.py b/plover/scripts/main.py index f72a5a2a2..be88f76cb 100644 --- a/plover/scripts/main.py +++ b/plover/scripts/main.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2013 Hesky Fisher # See LICENSE.txt for details. @@ -7,19 +6,17 @@ import argparse import atexit import os -import sys import subprocess +import sys import traceback - from importlib.metadata import entry_points +from plover import __name__ as __software_name__ +from plover import __version__, log from plover.config import Config -from plover.oslayer.controller import Controller from plover.oslayer.config import CONFIG_DIR, CONFIG_FILE, PLATFORM +from plover.oslayer.controller import Controller from plover.registry import registry -from plover import log -from plover import __name__ as __software_name__ -from plover import __version__ def init_config_dir(): @@ -43,7 +40,7 @@ def main(): parser.add_argument( "--version", action="version", - version="%s %s" % (__software_name__.capitalize(), __version__), + version=f"{__software_name__.capitalize()} {__version__}", ) parser.add_argument( "-s", diff --git a/plover/steno_dictionary.py b/plover/steno_dictionary.py index b69165272..a1daa23e1 100644 --- a/plover/steno_dictionary.py +++ b/plover/steno_dictionary.py @@ -46,7 +46,7 @@ def __init__(self): self.path = None def __str__(self): - return "%s(%r)" % (self.__class__.__name__, self.path) + return f"{self.__class__.__name__}({self.path!r})" def __repr__(self): return str(self) @@ -55,7 +55,7 @@ def __repr__(self): def create(cls, resource): assert not resource.startswith(ASSET_SCHEME) if cls.readonly: - raise ValueError("%s does not support creation" % cls.__name__) + raise ValueError(f"{cls.__name__} does not support creation") d = cls() d.path = resource return d @@ -129,8 +129,7 @@ def update(self, *args, **kwargs): reverse[value].append(key) casereverse[value.lower()].append(value) key_len = len(key) - if key_len > longest_key: - longest_key = key_len + longest_key = max(longest_key, key_len) self._longest_key = longest_key else: for iterable in iterable_list: @@ -171,7 +170,7 @@ def casereverse_lookup(self, value): class StenoDictionaryCollection: - def __init__(self, dicts=[]): + def __init__(self, dicts=()): self.dicts = [] self.filters = [] self.set_dicts(dicts) @@ -181,7 +180,7 @@ def longest_key(self): return max((d.longest_key for d in self.dicts if d.enabled), default=0) def set_dicts(self, dicts): - self.dicts = dicts[:] + self.dicts = list(dicts) def _lookup_keep_deleted(self, key, dicts=None, filters=()): """ @@ -201,9 +200,8 @@ def _lookup_keep_deleted(self, key, dicts=None, filters=()): if key_len > d.longest_key: continue value = d.get(key) - if value is not None: - if not any(f(key, value) for f in filters): - return value + if value is not None and not any(f(key, value) for f in filters): + return value def _lookup(self, key, dicts=None, filters=()): """ @@ -234,9 +232,8 @@ def _lookup_from_all(self, key, dicts=None, filters=()): if key_len > d.longest_key: continue value = d.get(key) - if value: - if not any(f(key, value) for f in filters): - values.append((value, d)) + if value and not any(f(key, value) for f in filters): + values.append((value, d)) return values def __str__(self): diff --git a/plover/suggestions.py b/plover/suggestions.py index 08c8646a8..ed4bba60b 100644 --- a/plover/suggestions.py +++ b/plover/suggestions.py @@ -2,7 +2,6 @@ from plover.steno import sort_steno_strokes - Suggestion = collections.namedtuple("Suggestion", "text steno_list") diff --git a/plover/system/__init__.py b/plover/system/__init__.py index cc64fa264..4682370dd 100644 --- a/plover/system/__init__.py +++ b/plover/system/__init__.py @@ -1,10 +1,10 @@ -from collections.abc import Sequence import os import re +from collections.abc import Sequence from plover.oslayer.config import CONFIG_DIR -from plover.resource import resource_filename from plover.registry import registry +from plover.resource import resource_filename from plover.steno import Stroke diff --git a/plover/translation.py b/plover/translation.py index ee3b3a9c0..3e538b539 100644 --- a/plover/translation.py +++ b/plover/translation.py @@ -16,14 +16,13 @@ """ -from collections import namedtuple import re +from collections import namedtuple +from plover import system +from plover.registry import registry from plover.steno import Stroke from plover.steno_dictionary import StenoDictionaryCollection -from plover.registry import registry -from plover import system - _ESCAPE_RX = re.compile("(\\\\[nrt]|[\n\r\t])") _ESCAPE_REPLACEMENTS = { @@ -137,8 +136,8 @@ def __str__(self): translation = "None" else: translation = escape_translation(self.english) - translation = '"%s"' % translation.replace('"', r"\"") - return "Translation(%s : %s)" % (self.rtfcre, translation) + translation = '"{}"'.format(translation.replace('"', r"\"")) + return f"Translation({self.rtfcre} : {translation})" def __repr__(self): return str(self) diff --git a/plover_build_utils/check_requirements.py b/plover_build_utils/check_requirements.py old mode 100644 new mode 100755 index 19574257c..edd46bc13 --- a/plover_build_utils/check_requirements.py +++ b/plover_build_utils/check_requirements.py @@ -1,6 +1,7 @@ #!/usr/bin/env python3 -from importlib.metadata import distributions, requires, PackageNotFoundError +from importlib.metadata import PackageNotFoundError, distributions, requires + from packaging.requirements import Requirement diff --git a/plover_build_utils/download.py b/plover_build_utils/download.py old mode 100644 new mode 100755 index 204e0ba32..3943277bd --- a/plover_build_utils/download.py +++ b/plover_build_utils/download.py @@ -1,11 +1,10 @@ #!/usr/bin/env python3 -from urllib.request import urlopen -from urllib.parse import urlsplit import hashlib import os import sys - +from urllib.parse import urlsplit +from urllib.request import urlopen DOWNLOADS_DIR = os.path.join(".cache", "downloads") @@ -39,11 +38,11 @@ def download(url, sha1=None, filename=None, downloads_dir=DOWNLOADS_DIR): if h.hexdigest() == sha1: break print( - "sha1 does not match: %s instead of %s" % (h.hexdigest(), sha1), + f"sha1 does not match: {h.hexdigest()} instead of {sha1}", file=sys.stderr, ) os.unlink(dst) - assert os.path.exists(dst), "could not successfully retrieve %s" % url + assert os.path.exists(dst), f"could not successfully retrieve {url}" return dst diff --git a/plover_build_utils/get_pip.py b/plover_build_utils/get_pip.py old mode 100644 new mode 100755 index 1f5cb4d30..5d8606005 --- a/plover_build_utils/get_pip.py +++ b/plover_build_utils/get_pip.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 import os -import sys import subprocess +import sys def get_pip(args=None): diff --git a/plover_build_utils/install_wheels.py b/plover_build_utils/install_wheels.py old mode 100644 new mode 100755 index 53b1640e9..37a54a1d8 --- a/plover_build_utils/install_wheels.py +++ b/plover_build_utils/install_wheels.py @@ -4,7 +4,6 @@ import subprocess import sys - # Default directory for caching wheels. WHEELS_CACHE = os.path.join(".cache", "wheels") @@ -139,7 +138,7 @@ def install_wheels( install_only = True wheel_only = False else: - raise ValueError("unsupported option: %s" % opt) + raise ValueError(f"unsupported option: {opt}") a = [opt] + args[:nb_args] del args[:nb_args] if wheel_only: @@ -151,12 +150,12 @@ def install_wheels( install_args.extend(a) wheel_args[0:0] = ["wheel", "-f", wheels_cache, "-w", wheels_cache] install_args[0:0] = ["install", "--no-index", "--no-cache-dir", "-f", wheels_cache] - pip_kwargs = dict(pip_install=pip_install, no_progress=no_progress) + pip_kwargs = {"pip_install": pip_install, "no_progress": no_progress} code = _pip(wheel_args, **pip_kwargs) if code == 0 and not no_install: code = _pip(install_args, **pip_kwargs) if code != 0: - raise Exception("wheels installation failed: pip execution returned %u" % code) + raise RuntimeError(f"wheels installation failed: pip execution returned {code}") if __name__ == "__main__": diff --git a/plover_build_utils/qt_ui_hooks.py b/plover_build_utils/qt_ui_hooks.py index 1759dcb2b..429614cde 100644 --- a/plover_build_utils/qt_ui_hooks.py +++ b/plover_build_utils/qt_ui_hooks.py @@ -1,5 +1,5 @@ import re -from typing import Match +from re import Match def convert_ui_translations(contents: str) -> str: @@ -26,7 +26,7 @@ def repl(m: Match[str]) -> str: field = " ".join( word.lower() for word in re.split(r"([A-Z][a-z_0-9]+)", field) if word ) - comment += ", {field}".format(field=field) + comment += f", {field}" comment += "." gd["pre2"] = gd["pre2"] or "" return "{comment}\n{ws}{pre1}{pre2}_({msg}".format(comment=comment, **gd) diff --git a/plover_build_utils/setup.py b/plover_build_utils/setup.py index 3db443578..c1bd75781 100644 --- a/plover_build_utils/setup.py +++ b/plover_build_utils/setup.py @@ -3,11 +3,12 @@ import os import subprocess import sys +from importlib.metadata import PackageNotFoundError, distribution +from typing import ClassVar +import setuptools from setuptools.command.build_py import build_py from setuptools.command.develop import develop -import setuptools -from importlib.metadata import distribution, PackageNotFoundError class Command(setuptools.Command): @@ -43,7 +44,7 @@ def bdist_wheel(self): for cmd, py_version, dist_path in whl_cmd.distribution.dist_files: if cmd == "bdist_wheel": return dist_path - raise Exception("could not find wheel path") + raise RuntimeError("could not find wheel path") # i18n support. {{{ @@ -51,10 +52,10 @@ def bdist_wheel(self): def babel_options(package, resource_dir=None): if resource_dir is None: - localedir = "%s/messages" % package + localedir = f"{package}/messages" else: - localedir = "%s/%s" % (package, resource_dir) - template = "%s/%s.pot" % (localedir, package) + localedir = f"{package}/{resource_dir}" + template = f"{localedir}/{package}.pot" return { "compile_catalog": { "domain": package, @@ -85,13 +86,11 @@ def babel_options(package, resource_dir=None): class BuildUi(Command): description = "build UI files" - user_options = [ + user_options: ClassVar[list] = [ ("force", "f", "force re-generation of all UI files"), ] - hooks = """ - plover_build_utils.qt_ui_hooks:remove_ui_autoconnection - """.split() + hooks: ClassVar[list] = ["plover_build_utils.qt_ui_hooks:remove_ui_autoconnection"] def initialize_options(self): self.force = False @@ -143,10 +142,7 @@ def _build_resources(self, src): def run(self): self.run_command("egg_info") std_hook_prefix = __package__ + ".qt_ui_hooks:" - hooks_info = [ - h[len(std_hook_prefix) :] if h.startswith(std_hook_prefix) else h - for h in self.hooks - ] + hooks_info = [h.removeprefix(std_hook_prefix) for h in self.hooks] if self.verbose: print("generating UI using hooks:", ", ".join(hooks_info)) ei_cmd = self.get_finalized_command("egg_info") @@ -165,7 +161,7 @@ def run(self): class BuildPy(build_py): - build_dependencies = [] + build_dependencies: ClassVar[list] = [] def run(self): for command in self.build_dependencies: @@ -179,7 +175,7 @@ def run(self): class Develop(develop): - build_dependencies = [] + build_dependencies: ClassVar[list] = [] def run(self): for command in self.build_dependencies: diff --git a/plover_build_utils/source_less.py b/plover_build_utils/source_less.py old mode 100644 new mode 100755 diff --git a/plover_build_utils/testing/__init__.py b/plover_build_utils/testing/__init__.py index 61b06c742..6d85db73d 100644 --- a/plover_build_utils/testing/__init__.py +++ b/plover_build_utils/testing/__init__.py @@ -6,10 +6,10 @@ from .steno_dictionary import dictionary_test __all__ = [ + "CaptureOutput", "blackbox_test", + "dictionary_test", "make_dict", - "CaptureOutput", "parametrize", "steno_to_stroke", - "dictionary_test", ] diff --git a/plover_build_utils/testing/blackbox.py b/plover_build_utils/testing/blackbox.py index fa3d13208..1e8103491 100644 --- a/plover_build_utils/testing/blackbox.py +++ b/plover_build_utils/testing/blackbox.py @@ -8,9 +8,9 @@ from plover import system from plover.formatting import ( - Formatter, - SPACE_PLACEMENT_BEFORE, SPACE_PLACEMENT_AFTER, + SPACE_PLACEMENT_BEFORE, + Formatter, ) from plover.steno import normalize_steno from plover.steno_dictionary import StenoDictionary @@ -19,7 +19,6 @@ from .output import CaptureOutput from .steno import steno_to_stroke - BLACKBOX_OUTPUT_RX = re.compile("r?['\"]") @@ -86,7 +85,7 @@ def blackbox_replay(blackbox, name, test): assert_msg += " " + exception_class + "\n!= " + expected_exception assert exception_class == expected_exception, assert_msg else: - raise ValueError("invalid output:\n%s" % output) + raise ValueError(f"invalid output:\n{output}") def _blackbox_replay_action(blackbox, action_spec): @@ -104,7 +103,7 @@ def _blackbox_replay_action(blackbox, action_spec): assert len(args) == 1 system.setup(args[0]) else: - raise ValueError("invalid action:\n%r" % action_spec) + raise ValueError(f"invalid action:\n{action_spec!r}") def blackbox_test(cls_or_fn): diff --git a/plover_build_utils/testing/dict.py b/plover_build_utils/testing/dict.py index da28dce9f..9f0484e8b 100644 --- a/plover_build_utils/testing/dict.py +++ b/plover_build_utils/testing/dict.py @@ -1,7 +1,7 @@ -from contextlib import contextmanager -from pathlib import Path import os import tempfile +from contextlib import contextmanager +from pathlib import Path @contextmanager diff --git a/plover_build_utils/testing/parametrize.py b/plover_build_utils/testing/parametrize.py index 094ce8c38..608b613c7 100644 --- a/plover_build_utils/testing/parametrize.py +++ b/plover_build_utils/testing/parametrize.py @@ -21,18 +21,18 @@ def parametrize(tests, arity=None): argvalues = [] for n, t in enumerate(tests): line = inspect.getsourcelines(t)[1] - ids.append("%u:%u" % (n + 1, line)) + ids.append(f"{n + 1}:{line}") argvalues.append(t()) if arity is None: arity = len(argvalues[0]) assert arity > 0 def decorator(fn): - argnames = list( + argnames = [ parameter.name for parameter in inspect.signature(fn).parameters.values() if parameter.default is inspect.Parameter.empty - )[-arity:] + ][-arity:] if arity == 1: argnames = argnames[0] return pytest.mark.parametrize(argnames, argvalues, ids=ids)(fn) diff --git a/plover_build_utils/testing/steno_dictionary.py b/plover_build_utils/testing/steno_dictionary.py index 1934e7a41..78e003ad3 100644 --- a/plover_build_utils/testing/steno_dictionary.py +++ b/plover_build_utils/testing/steno_dictionary.py @@ -1,9 +1,9 @@ -from collections import defaultdict -from contextlib import contextmanager import ast import functools import inspect import os +from collections import defaultdict +from contextlib import contextmanager import pytest @@ -187,9 +187,8 @@ def test_readonly_no_create_allowed(self, tmp_path): """ Don't allow creating a read-only dictionary. """ - with self.sample_dict(tmp_path) as dict_path: - with pytest.raises(ValueError): - self.DICT_CLASS.create(str(dict_path)) + with self.sample_dict(tmp_path) as dict_path, pytest.raises(ValueError): + self.DICT_CLASS.create(str(dict_path)) _TEST_DICTIONARY_UPDATE_DICT = { diff --git a/plover_build_utils/tree.py b/plover_build_utils/tree.py old mode 100644 new mode 100755 index 9be3462d9..2eedf7f0c --- a/plover_build_utils/tree.py +++ b/plover_build_utils/tree.py @@ -1,12 +1,11 @@ #!/usr/bin/env python3 -from pathlib import Path import functools import operator import os.path import stat import sys - +from pathlib import Path BLOCK_SIZES = ( (1024 * 1024 * 1024 * 1024, "T"), @@ -19,7 +18,7 @@ def format_size(size): for bs, unit in BLOCK_SIZES: if size >= bs: - return "%.1f%s" % (size / bs, unit) + return f"{size / bs:.1f}{unit}" return str(size) @@ -48,7 +47,7 @@ def tree(path, dirs_only=False, max_depth=0, _depth=0): p += os.path.sep if is_symlink: p += " -> " + os.readlink(str(path)) - print("%10s %s" % (format_size(size), p)) + print(f"{format_size(size):>10} {p}") return size diff --git a/plover_build_utils/trim.py b/plover_build_utils/trim.py old mode 100644 new mode 100755 index b9a3551b0..35d52e734 --- a/plover_build_utils/trim.py +++ b/plover_build_utils/trim.py @@ -1,9 +1,9 @@ #!/usr/bin/env python3 import glob +import os import shutil import sys -import os def trim(directory, patterns_file, verbose=True, dry_run=False): diff --git a/plover_build_utils/zipdir.py b/plover_build_utils/zipdir.py old mode 100644 new mode 100755 index 0d302487a..276eadc5c --- a/plover_build_utils/zipdir.py +++ b/plover_build_utils/zipdir.py @@ -6,7 +6,7 @@ def zipdir(directory, compression=zipfile.ZIP_DEFLATED): - zipname = "%s.zip" % directory + zipname = f"{directory}.zip" prefix = os.path.dirname(directory) with zipfile.ZipFile(zipname, "w", compression) as zf: for dirpath, dirnames, filenames in os.walk(directory): diff --git a/pyproject.toml b/pyproject.toml index ccbf3557c..33a914d3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,12 +1,20 @@ [build-system] requires = [ "babel", + "packaging", "PySide6>=6.9.0", "setuptools>=79.0.0", "wheel", ] build-backend = "setuptools.build_meta" +[tool.ruff.lint] +ignore = [ + # Broad `except Exception` is Plover's deliberate crash-resilience idiom: + # engine hooks, plugin and dictionary loading must never take down the engine. + "BLE001", +] + [tool.towncrier] name = "" version = "" diff --git a/reqs/constraints.txt b/reqs/constraints.txt index a73ef9eb4..8b812bbb7 100644 --- a/reqs/constraints.txt +++ b/reqs/constraints.txt @@ -60,7 +60,7 @@ requests-futures==1.0.2 requests-toolbelt==1.0.0 rfc3986==2.0.0 rtf-tokenize==1.0.1 -ruff==0.14.8 # also update .pre-commit-config.yaml +ruff==0.16.0 # also update .pre-commit-config.yaml SecretStorage==3.3.3 setuptools==79.0.0 six==1.17.0 diff --git a/reqs/setup.txt b/reqs/setup.txt index 3423c3ab9..4410119da 100644 --- a/reqs/setup.txt +++ b/reqs/setup.txt @@ -1,4 +1,5 @@ babel +packaging PySide6 setuptools wheel diff --git a/setup.py b/setup.py index 3defeadf9..f52fd5627 100755 --- a/setup.py +++ b/setup.py @@ -8,8 +8,8 @@ import subprocess import sys -from setuptools import setup from packaging.version import Version +from setuptools import setup sys.path.insert(0, os.path.dirname(__file__)) @@ -23,10 +23,11 @@ __license__ = "" with open(os.path.join(__software_name__, "__init__.py")) as fp: - exec(fp.read()) + exec(fp.read()) # noqa: S102 -from plover_build_utils.setup import BuildPy, BuildUi, Command, Develop, babel_options +from typing import ClassVar +from plover_build_utils.setup import BuildPy, BuildUi, Command, Develop, babel_options Develop.build_dependencies.append("build_py") BuildPy.build_dependencies.append("build_ui") @@ -37,10 +38,7 @@ } options = {} -PACKAGE = "%s-%s" % ( - __software_name__, - __version__, -) +PACKAGE = f"{__software_name__}-{__version__}" # Helpers. {{{ @@ -53,7 +51,7 @@ def get_version(): # extend version with git revision if no tag is available - used for builds during development git_version = ( - subprocess.check_output("git describe --tags --match=v[0-9]*".split()) + subprocess.check_output(["git", "describe", "--tags", "--match=v[0-9]*"]) .strip() .decode() ) @@ -72,7 +70,7 @@ def get_version(): class BinaryDistWin(Command): description = "create distribution(s) for MS Windows" - user_options = [ + user_options: ClassVar[list] = [ ("trim", "t", "trim the resulting distribution to reduce size"), ("zipdir", "z", "create a zip of the resulting directory"), ( @@ -82,8 +80,8 @@ class BinaryDistWin(Command): ), ("bash=", None, "bash executable to use for running the build script"), ] - boolean_options = ["installer", "trim", "zipdir"] - extra_args = [] + boolean_options: ClassVar[list] = ["installer", "trim", "zipdir"] + extra_args: ClassVar[list] = [] def initialize_options(self): self.bash = None @@ -117,9 +115,9 @@ def run(self): class Launch(Command): - description = "run %s from source" % __software_name__.capitalize() + description = f"run {__software_name__.capitalize()} from source" command_consumes_arguments = True - user_options = [] + user_options: ClassVar[list] = [] def initialize_options(self): self.args = None @@ -150,7 +148,7 @@ def run(self): class PatchVersion(Command): description = "patch package version from VCS" command_consumes_arguments = True - user_options = [] + user_options: ClassVar[list] = [] def initialize_options(self): self.args = [] @@ -214,8 +212,8 @@ def run(self): class BinaryDistApp(Command): description = "create an application bundle for Mac" - user_options = [] - extra_args = [] + user_options: ClassVar[list] = [] + extra_args: ClassVar[list] = [] def initialize_options(self): pass @@ -231,14 +229,14 @@ def run(self): class BinaryDistDmg(Command): - user_options = [ + user_options: ClassVar[list] = [ ( "skip-app-build", None, "skip building the app; assume dist/Plover.app already exists", ), ] - boolean_options = ["skip-app-build"] + boolean_options: ClassVar[list] = ["skip-app-build"] def initialize_options(self): self.skip_app_build = False @@ -269,8 +267,8 @@ def run(self): class NotarizeApp(Command): - user_options = [] - extra_args = [] + user_options: ClassVar[list] = [] + extra_args: ClassVar[list] = [] def initialize_options(self): pass @@ -286,8 +284,8 @@ def run(self): class NotarizeDmg(Command): - user_options = [] - extra_args = [] + user_options: ClassVar[list] = [] + extra_args: ClassVar[list] = [] def initialize_options(self): pass @@ -330,7 +328,7 @@ def run(self): class BinaryDistAppImage(Command): description = "create AppImage distribution for Linux" - user_options = [ + user_options: ClassVar[list] = [ ("docker", None, "use docker to run the build script"), ( "no-update-tools", @@ -338,7 +336,7 @@ class BinaryDistAppImage(Command): "don't try to update AppImage tools, only fetch missing ones", ), ] - boolean_options = ["docker", "no-update-tools"] + boolean_options: ClassVar[list] = ["docker", "no-update-tools"] def initialize_options(self): self.docker = False diff --git a/test/gui_qt/test_dictionaries_widget.py b/test/gui_qt/test_dictionaries_widget.py index 96c1c4af8..2d359d0e2 100644 --- a/test/gui_qt/test_dictionaries_widget.py +++ b/test/gui_qt/test_dictionaries_widget.py @@ -1,23 +1,20 @@ +import operator from collections import namedtuple from pathlib import Path from textwrap import dedent from types import SimpleNamespace -import operator - -from PySide6.QtCore import QModelIndex, QPersistentModelIndex, Qt +from unittest import mock import pytest +from PySide6.QtCore import QModelIndex, QPersistentModelIndex, Qt from plover.config import DictionaryConfig from plover.engine import ErroredDictionary from plover.gui_qt.dictionaries_widget import DictionariesModel, DictionariesWidget -from plover.steno_dictionary import StenoDictionary, StenoDictionaryCollection from plover.misc import expand_path - +from plover.steno_dictionary import StenoDictionary, StenoDictionaryCollection from plover_build_utils.testing import parametrize -from unittest import mock - INVALID_EXCEPTION = Exception("loading error") ICON_TO_CHAR = { @@ -139,8 +136,7 @@ def check( icon = index.data(Qt.ItemDataRole.DecorationRole) path = index.data(Qt.ItemDataRole.DisplayRole) actual_state.append( - "%s %s %s" - % ( + "{} {} {}".format( ENABLED_TO_CHAR.get(is_checked, "?"), ICON_TO_CHAR.get(icon, "?"), path, @@ -188,7 +184,7 @@ def reset_mocks(self): def model_test(monkeypatch, request): state = request.function.__doc__ # Patch configuration directory. - current_dir = Path(".").resolve() + current_dir = Path.cwd() monkeypatch.setattr("plover.misc.CONFIG_DIR", str(current_dir)) monkeypatch.setattr( "plover.gui_qt.dictionaries_widget.CONFIG_DIR", str(current_dir) @@ -201,12 +197,7 @@ def model_test(monkeypatch, request): # Dictionaries. dictionaries = StenoDictionaryCollection() # Fake engine. - engine = mock.MagicMock( - spec=""" - __enter__ __exit__ - config signal_connect - """.split() - ) + engine = mock.MagicMock(spec=["__enter__", "__exit__", "config", "signal_connect"]) engine.__enter__.return_value = engine type(engine).config = config signals = mock.MagicMock() @@ -216,12 +207,12 @@ def model_test(monkeypatch, request): } # Setup model. model = DictionariesModel(engine, {name: name for name in ICON_TO_CHAR}, max_undo=5) - for slot in """ - dataChanged - layoutAboutToBeChanged - layoutChanged - has_undo_changed - """.split(): + for slot in [ + "dataChanged", + "layoutAboutToBeChanged", + "layoutChanged", + "has_undo_changed", + ]: getattr(model, slot).connect(getattr(signals, slot)) connections = dict(call.args for call in engine.signal_connect.mock_calls) assert connections.keys() == { @@ -287,7 +278,7 @@ def test_model_accessible_text_3(model_test): """ ☑ ! invalid.bad """ - expected = "invalid.bad, errored: %s." % INVALID_EXCEPTION + expected = f"invalid.bad, errored: {INVALID_EXCEPTION}." assert ( model_test.model.index(0).data(Qt.ItemDataRole.AccessibleTextRole) == expected ) @@ -297,7 +288,7 @@ def test_model_accessible_text_4(model_test): """ ☐ ! invalid.bad """ - expected = "invalid.bad, disabled, errored: %s." % INVALID_EXCEPTION + expected = f"invalid.bad, disabled, errored: {INVALID_EXCEPTION}." assert ( model_test.model.index(0).data(Qt.ItemDataRole.AccessibleTextRole) == expected ) @@ -912,12 +903,7 @@ def list_plugins(plugin_type): registry.list_plugins.side_effect = list_plugins monkeypatch.setattr("plover.gui_qt.dictionaries_widget.registry", registry) # Fake file dialog. - file_dialog = mock.MagicMock( - spec=""" - getOpenFileNames - getSaveFileName - """.split() - ) + file_dialog = mock.MagicMock(spec=["getOpenFileNames", "getSaveFileName"]) monkeypatch.setattr("plover.gui_qt.dictionaries_widget.QFileDialog", file_dialog) # Fake `create_dictionary`. @@ -1000,19 +986,19 @@ def test_widget_selection(widget_test, selection, enabled_actions): ☑ ! invalid.bad """ widget_test.select(selection) - for action_name in """ - AddDictionaries - AddTranslation - EditDictionaries - MoveDictionariesDown - MoveDictionariesUp - RemoveDictionaries - SaveDictionaries - Undo - """.split(): + for action_name in [ + "AddDictionaries", + "AddTranslation", + "EditDictionaries", + "MoveDictionariesDown", + "MoveDictionariesUp", + "RemoveDictionaries", + "SaveDictionaries", + "Undo", + ]: action = getattr(widget_test.widget, "action_" + action_name) enabled = action.isEnabled() - msg = "%s is %s" % (action_name, "enabled" if enabled else "disabled") + msg = "{} is {}".format(action_name, "enabled" if enabled else "disabled") assert enabled == (action_name in enabled_actions), msg @@ -1048,8 +1034,8 @@ def test_widget_save_copy_1(widget_test): assert widget_test.file_dialog.mock_calls == [ mock.call.getSaveFileName( parent=widget_test.widget, - caption="Save a copy of %s as..." % name, - dir=expand_path("%s - Copy.json" % Path(name).stem), + caption=f"Save a copy of {name} as...", + dir=expand_path(f"{Path(name).stem} - Copy.json"), filter=FILE_PICKER_SAVE_FILTER, ) for name in ["favorite.json", "normal.json", "read-only.ro"] @@ -1085,7 +1071,7 @@ def test_widget_save_merge_1(widget_test): assert widget_test.file_dialog.mock_calls == [ mock.call.getSaveFileName( parent=widget_test.widget, - caption="Merge %s as..." % merge_name, + caption=f"Merge {merge_name} as...", dir=expand_path(merge_name + ".json"), filter=FILE_PICKER_SAVE_FILTER, ) @@ -1120,7 +1106,7 @@ def test_widget_save_merge_2(widget_test): assert widget_test.file_dialog.mock_calls == [ mock.call.getSaveFileName( parent=widget_test.widget, - caption="Merge %s as..." % merge_name, + caption=f"Merge {merge_name} as...", dir=expand_path(merge_name + ".json"), filter=FILE_PICKER_SAVE_FILTER, ) diff --git a/test/gui_qt/test_i18n_files.py b/test/gui_qt/test_i18n_files.py index 3b0b942f9..88634daba 100644 --- a/test/gui_qt/test_i18n_files.py +++ b/test/gui_qt/test_i18n_files.py @@ -1,9 +1,9 @@ +import difflib import os +import shutil import subprocess import sys import tempfile -import difflib -import shutil from pathlib import Path import pytest diff --git a/test/gui_qt/test_steno_validator.py b/test/gui_qt/test_steno_validator.py index 0f15a0e56..6ba2834ae 100644 --- a/test/gui_qt/test_steno_validator.py +++ b/test/gui_qt/test_steno_validator.py @@ -1,6 +1,5 @@ -from PySide6.QtGui import QValidator - import pytest +from PySide6.QtGui import QValidator from plover.gui_qt.steno_validator import StenoValidator diff --git a/test/test_blackbox.py b/test/test_blackbox.py index 8dd6deff4..14c28dd14 100644 --- a/test/test_blackbox.py +++ b/test/test_blackbox.py @@ -1,11 +1,10 @@ -# -*- coding: utf-8 -*- +from typing import ClassVar import pytest from plover import system from plover.registry import Registry from plover.system import english_stenotype - from plover_build_utils.testing import blackbox_test @@ -26,7 +25,7 @@ class Melani: IMPLICIT_HYPHEN_KEYS = KEYS SUFFIX_KEYS = () NUMBER_KEY = "#" - NUMBERS = { + NUMBERS: ClassVar[dict] = { "S-": "1-", "P-": "2-", "T-": "3-", @@ -39,10 +38,10 @@ class Melani: "-i": "-9", } UNDO_STROKE_STENO = "*" - ORTHOGRAPHY_RULES = [] - ORTHOGRAPHY_RULES_ALIASES = {} + ORTHOGRAPHY_RULES: ClassVar[list] = [] + ORTHOGRAPHY_RULES_ALIASES: ClassVar[dict] = {} ORTHOGRAPHY_WORDLIST = None - KEYMAPS = {} + KEYMAPS: ClassVar[dict] = {} DICTIONARIES_ROOT = None DEFAULT_DICTIONARIES = () @@ -81,12 +80,12 @@ class KoreanCAS: ) SUFFIX_KEYS = () NUMBER_KEY = None - NUMBERS = {} + NUMBERS: ClassVar[dict] = {} UNDO_STROKE_STENO = "-ㅂㄴ" - ORTHOGRAPHY_RULES = [] - ORTHOGRAPHY_RULES_ALIASES = {} + ORTHOGRAPHY_RULES: ClassVar[list] = [] + ORTHOGRAPHY_RULES_ALIASES: ClassVar[dict] = {} ORTHOGRAPHY_WORDLIST = None - KEYMAPS = {} + KEYMAPS: ClassVar[dict] = {} DICTIONARIES_ROOT = None DEFAULT_DICTIONARIES = () diff --git a/test/test_command.py b/test/test_command.py index f4f79af8a..26616df39 100644 --- a/test/test_command.py +++ b/test/test_command.py @@ -4,14 +4,12 @@ import pytest -from plover.formatting import SPACE_PLACEMENT_AFTER - from plover.command.set_config import set_config from plover.config import Config, DictionaryConfig - +from plover.formatting import SPACE_PLACEMENT_AFTER from plover_build_utils.testing import parametrize -from .test_config import DEFAULTS, DEFAULT_KEYMAP +from .test_config import DEFAULT_KEYMAP, DEFAULTS class FakeEngine: @@ -32,9 +30,7 @@ def config(self, options): SET_CONFIG_TESTS = ( lambda: ( - '"space_placement":"{SPACE_PLACEMENT_AFTER}"'.format( - SPACE_PLACEMENT_AFTER=SPACE_PLACEMENT_AFTER - ), + f'"space_placement":"{SPACE_PLACEMENT_AFTER}"', SPACE_PLACEMENT_AFTER, ), lambda: ('"start_attached":True', True), diff --git a/test/test_config.py b/test/test_config.py index 1859ef59f..0a8339380 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -3,29 +3,29 @@ """Unit tests for config.py.""" -from ast import literal_eval -from contextlib import ExitStack -from pathlib import Path -from site import USER_BASE -from string import Template import inspect import json import os import subprocess import sys import textwrap +from ast import literal_eval +from contextlib import ExitStack +from pathlib import Path +from site import USER_BASE +from string import Template +from typing import ClassVar import appdirs import pytest -from plover.formatting import SPACE_PLACEMENT_BEFORE, SPACE_PLACEMENT_AFTER - from plover import config from plover.config import DictionaryConfig -from plover.oslayer.config import PLATFORM +from plover.formatting import SPACE_PLACEMENT_AFTER, SPACE_PLACEMENT_BEFORE from plover.machine.keyboard import Keyboard from plover.machine.keymap import Keymap from plover.misc import expand_path +from plover.oslayer.config import PLATFORM from plover.registry import Registry from plover.system import english_stenotype @@ -76,10 +76,10 @@ class FakeSystem: NUMBER_KEY = english_stenotype.NUMBER_KEY NUMBERS = english_stenotype.NUMBERS UNDO_STROKE_STENO = english_stenotype.UNDO_STROKE_STENO - ORTHOGRAPHY_RULES = [] - ORTHOGRAPHY_RULES_ALIASES = {} + ORTHOGRAPHY_RULES: ClassVar[list] = [] + ORTHOGRAPHY_RULES_ALIASES: ClassVar[dict] = {} ORTHOGRAPHY_WORDLIST = None - KEYMAPS = { + KEYMAPS: ClassVar[dict] = { "Faky faky": english_stenotype.KEYMAPS["Keyboard"], } DEFAULT_DICTIONARIES = ("utilisateur.json", "principal.json") @@ -167,13 +167,13 @@ def test_config_dict(): ), ( "simple_options", - """ + f""" [Output Configuration] space_placement = {SPACE_PLACEMENT_AFTER} start_attached = true start_capitalized = yes undo_levels = 42 - """.format(SPACE_PLACEMENT_AFTER=SPACE_PLACEMENT_AFTER), + """, dict_replace( DEFAULTS, { @@ -190,13 +190,13 @@ def test_config_dict(): "undo_levels": 200, }, None, - """ + f""" [Output Configuration] space_placement = {SPACE_PLACEMENT_BEFORE} start_attached = False start_capitalized = False undo_levels = 200 - """.format(SPACE_PLACEMENT_BEFORE=SPACE_PLACEMENT_BEFORE), + """, ), ( "machine_options", @@ -247,7 +247,7 @@ def test_config_dict(): DictionaryConfig("principal.json"), ], }, - """ + f""" [Machine Configuration] auto_start = True machine_type = Faky faky @@ -267,9 +267,8 @@ def test_config_dict(): name = Faux système [System: Faux système] - keymap[faky faky] = %s - """ - % DEFAULT_KEYMAP, + keymap[faky faky] = {DEFAULT_KEYMAP} + """, ), ( "machine_bool_option", @@ -356,9 +355,8 @@ def test_config_dict(): "dictionaries", """ [System: English Stenotype] - dictionaries = %s - """ - % json.dumps([os.path.join(ABS_PATH, "user.json"), "english/main.json"]), + dictionaries = {} + """.format(json.dumps([os.path.join(ABS_PATH, "user.json"), "english/main.json"])), dict_replace( DEFAULTS, { @@ -382,14 +380,15 @@ def test_config_dict(): }, """ [System: English Stenotype] - dictionaries = %s - """ - % json.dumps( - [ - {"enabled": True, "path": os.path.join(ABS_PATH, "user.json")}, - {"enabled": True, "path": os.path.join("english", "main.json")}, - ], - sort_keys=True, + dictionaries = {} + """.format( + json.dumps( + [ + {"enabled": True, "path": os.path.join(ABS_PATH, "user.json")}, + {"enabled": True, "path": os.path.join("english", "main.json")}, + ], + sort_keys=True, + ) ), ), ( @@ -763,12 +762,11 @@ def path_expand(path): # Check plover.oslayer.config.CONFIG_DIR is correctly set. config_dir = pyeval( dedent_strip( - """ - __import__('sys').path.insert(0, %r) + f""" + __import__('sys').path.insert(0, {str(Path(config.__file__).parent.parent)!r}) from plover.oslayer.config import CONFIG_DIR print(repr(CONFIG_DIR)) """ - % str(Path(config.__file__).parent.parent) ) ) expected_config_dir = path_expand(expected_config_dir) diff --git a/test/test_default_dict.py b/test/test_default_dict.py index af82727e7..81c790fbe 100644 --- a/test/test_default_dict.py +++ b/test/test_default_dict.py @@ -8,7 +8,6 @@ from plover_build_utils.testing import steno_to_stroke - DICT_NAMES = ["main.json", "commands.json", "user.json"] DICT_PATH = "plover/assets/" @@ -25,9 +24,9 @@ def test_no_duplicates_categorized_files(): for key, value_list in d.items(): if len(value_list) > 1: has_duplicate = True - msg_list.append("key: %s\n" % key) + msg_list.append(f"key: {key}\n") for value in value_list: - msg_list.append("%r in %s\n" % value) + msg_list.append("{!r} in {}\n".format(*value)) msg = "\n" + "".join(msg_list) assert not has_duplicate, msg diff --git a/test/test_engine.py b/test/test_engine.py index c4b749773..45e45d413 100644 --- a/test/test_engine.py +++ b/test/test_engine.py @@ -1,6 +1,7 @@ -from functools import partial import os import tempfile +from functools import partial +from unittest import mock import pytest @@ -19,11 +20,8 @@ from plover.output import Output from plover.registry import Registry from plover.steno_dictionary import StenoDictionaryCollection - from plover_build_utils.testing import make_dict -from unittest import mock - class FakeMachine(StenotypeBase): instance = None @@ -96,7 +94,8 @@ def engine(monkeypatch): monkeypatch.setattr("plover.engine.registry", registry) ctrl = mock.MagicMock(spec=Controller) kbd = FakeKeyboardEmulation() - cfg_file = tempfile.NamedTemporaryFile( + # Closed right away: only used to get a unique config file path. + cfg_file = tempfile.NamedTemporaryFile( # noqa: SIM115 prefix="plover", suffix="config", delete=False ) try: @@ -183,7 +182,7 @@ def check_loaded_events(actual_events, expected_events): assert len(filtered_events) == len(expected_events) for n, event in enumerate(filtered_events): event_type, event_args, event_kwargs = event - msg = "event %u: %r" % (n, event) + msg = f"event {n}: {event!r}" assert event_type == "dictionaries_loaded", msg assert event_kwargs == {}, msg assert len(event_args) == 1, msg diff --git a/test/test_formatting.py b/test/test_formatting.py index 59893da18..6cb0ccda5 100644 --- a/test/test_formatting.py +++ b/test/test_formatting.py @@ -9,10 +9,9 @@ from plover import formatting from plover.formatting import ( - Case, SPACE_PLACEMENT_AFTER, + Case, ) - from plover_build_utils.testing import CaptureOutput, parametrize @@ -22,13 +21,13 @@ def action(**kwargs): for k, v in list(kwargs.items()): if "_and_" in k: del kwargs[k] - for k in k.split("_and_"): - kwargs[k] = v + for sub_k in k.split("_and_"): + kwargs[sub_k] = v return formatting._Action(**kwargs) class MockTranslation: - def __init__(self, rtfcre=tuple(), english=None, formatting=None): + def __init__(self, rtfcre=(), english=None, formatting=None): self.rtfcre = rtfcre self.english = english self.formatting = formatting diff --git a/test/test_json_dict.py b/test/test_json_dict.py index 8d6e7d1e2..aed6ca028 100644 --- a/test/test_json_dict.py +++ b/test/test_json_dict.py @@ -1,11 +1,9 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2013 Hesky Fisher # See LICENSE.txt for details. """Unit tests for json.py.""" from plover.dictionary.json_dict import JsonDictionary - from plover_build_utils.testing import dictionary_test diff --git a/test/test_key_combo.py b/test/test_key_combo.py index 92823f6a4..e9d2f3192 100644 --- a/test/test_key_combo.py +++ b/test/test_key_combo.py @@ -140,7 +140,7 @@ def repr_expected(result): def repr_key_events(events): assert isinstance(events, list) - return ["%s%s" % ("+" if pressed else "-", key) for key, pressed in events] + return ["{}{}".format("+" if pressed else "-", key) for key, pressed in events] for action, *args in instructions: if action == "parse": diff --git a/test/test_keyboard.py b/test/test_keyboard.py index 97bccd37b..5d3ef98bd 100644 --- a/test/test_keyboard.py +++ b/test/test_keyboard.py @@ -1,14 +1,14 @@ +from unittest import mock + import pytest +from plover.oslayer.keyboardcontrol import KeyboardCapture from plover import system from plover.machine.keyboard import Keyboard from plover.machine.keymap import Keymap -from plover.oslayer.keyboardcontrol import KeyboardCapture from plover.oslayer.config import PLATFORM from plover.oslayer.linux.display_server import DISPLAY_SERVER -from unittest import mock - def send_input(capture, key_events): for evt in key_events.strip().split(): diff --git a/test/test_keymap.py b/test/test_keymap.py index 400d27613..753447d06 100644 --- a/test/test_keymap.py +++ b/test/test_keymap.py @@ -4,7 +4,7 @@ def new_keymap(): - return Keymap(("k%u" % n for n in range(8)), ("a%u" % n for n in range(4))) + return Keymap((f"k{n}" for n in range(8)), (f"a{n}" for n in range(4))) BINDINGS_LIST = ( diff --git a/test/test_loading_manager.py b/test/test_loading_manager.py index d31548994..cdbc2ab6e 100644 --- a/test/test_loading_manager.py +++ b/test/test_loading_manager.py @@ -3,14 +3,14 @@ """Tests for loading_manager.py.""" -from collections import defaultdict import os import tempfile +from collections import defaultdict import pytest +from plover.dictionary import loading_manager from plover.engine import ErroredDictionary -import plover.dictionary.loading_manager as loading_manager class FakeDictionaryContents: @@ -28,10 +28,11 @@ class FakeDictionaryInfo: def __init__(self, name, contents): self.name = name self.contents = contents - self.tf = tempfile.NamedTemporaryFile() + # Kept open for the lifetime of the fake dictionary. + self.tf = tempfile.NamedTemporaryFile() # noqa: SIM115 def __repr__(self): - return "FakeDictionaryInfo(%r, %r)" % (self.name, self.contents) + return f"FakeDictionaryInfo({self.name!r}, {self.contents!r})" class MockLoader: diff --git a/test/test_log.py b/test/test_log.py index 21d0f3cee..438c9a647 100644 --- a/test/test_log.py +++ b/test/test_log.py @@ -2,17 +2,18 @@ # See LICENSE.txt for details. import os -from logging import Handler from collections import defaultdict +from logging import Handler +from typing import ClassVar import pytest -from plover.steno import Stroke from plover import log +from plover.steno import Stroke class FakeHandler(Handler): - outputs = defaultdict(list) + outputs: ClassVar[defaultdict] = defaultdict(list) def __init__(self, filename, format=log.STROKE_LOG_FORMAT): super().__init__() diff --git a/test/test_machine.py b/test/test_machine.py index bff21c748..0fc08dc9d 100644 --- a/test/test_machine.py +++ b/test/test_machine.py @@ -1,7 +1,9 @@ from unittest.mock import Mock -from plover.machine.base import ThreadedStenotypeBase + import pytest +from plover.machine.base import ThreadedStenotypeBase + class MyMachine(ThreadedStenotypeBase): def run(self): diff --git a/test/test_misc.py b/test/test_misc.py index dc89dbe6c..6b60bd271 100644 --- a/test/test_misc.py +++ b/test/test_misc.py @@ -1,4 +1,3 @@ -# -*- coding: utf-8 -*- # Copyright (c) 2016 Open Steno Project # See LICENSE.txt for details. @@ -9,10 +8,9 @@ import pytest -import plover.misc as misc import plover.oslayer.config as conf +from plover import misc from plover.resource import ASSET_SCHEME - from plover_build_utils.testing import parametrize @@ -61,7 +59,7 @@ def test_dictionary_path(short_path, full_path): # Expand. (short_path, "expand", full_path), ): - function = "%s_path" % function + function = f"{function}_path" result = getattr(misc, function)(input) assert result == expected, function diff --git a/test/test_orthography.py b/test/test_orthography.py index f52937436..334d0fd71 100644 --- a/test/test_orthography.py +++ b/test/test_orthography.py @@ -2,10 +2,8 @@ # See LICENSE.txt for details. from plover.orthography import add_suffix - from plover_build_utils.testing import parametrize - ADD_SUFFIX_TESTS = ( lambda: ("artistic", "ly", "artistically"), lambda: ("cosmetic", "ly", "cosmetically"), diff --git a/test/test_passport.py b/test/test_passport.py index 0f2f57dc1..0280353af 100644 --- a/test/test_passport.py +++ b/test/test_passport.py @@ -4,9 +4,9 @@ """Unit tests for passport.py.""" import threading +from typing import ClassVar from plover.machine.passport import Passport - from plover_build_utils.testing import parametrize @@ -68,7 +68,7 @@ def test_passport(monkeypatch, inputs, expected): class mock(MockSerial): event = threading.Event() - data = [b"<123/" + s + b"/something>" for s in inputs] + data: ClassVar[list] = [b"<123/" + s + b"/something>" for s in inputs] monkeypatch.setattr("plover.machine.base.serial.Serial", mock) actual = [] diff --git a/test/test_resource.py b/test/test_resource.py index f0ec0e2b4..57c7c4fa3 100644 --- a/test/test_resource.py +++ b/test/test_resource.py @@ -1,5 +1,5 @@ -from pathlib import Path import inspect +from pathlib import Path import pytest @@ -69,18 +69,19 @@ def test_resource_update(tmp_path): # Can't update assets. resource = "asset:plover:assets/pouet.json" resource_path = Path(resource_filename(resource)) - with pytest.raises(ValueError): - with resource_update(resource): - resource_path.write_bytes(b"contents") + with pytest.raises(ValueError), resource_update(resource): + resource_path.write_bytes(b"contents") assert not resource_path.exists() # Don't update resource on exception (but still cleanup). resource = (tmp_path / "resource").resolve() exception_str = "Houston, we have a problem" - with pytest.raises(Exception, match=exception_str): - with resource_update(str(resource)) as tmpf: - tmpf = Path(tmpf) - tmpf.write_bytes(b"contents") - raise Exception(exception_str) + with ( + pytest.raises(Exception, match=exception_str), + resource_update(str(resource)) as tmpf, + ): + tmpf = Path(tmpf) + tmpf.write_bytes(b"contents") + raise RuntimeError(exception_str) assert not resource.exists() assert not tmpf.exists() # Normal use. diff --git a/test/test_rtfcre_dict.py b/test/test_rtfcre_dict.py index ebaccc031..51249b836 100644 --- a/test/test_rtfcre_dict.py +++ b/test/test_rtfcre_dict.py @@ -8,7 +8,6 @@ from plover import __version__ as plover_version from plover.dictionary.rtfcre_dict import RtfDictionary, TranslationFormatter from plover.dictionary.rtfcre_parse import BadRtfError - from plover_build_utils.testing import dictionary_test, parametrize @@ -89,15 +88,15 @@ def rtf_load_test(*spec, xfail=False): assert 1 <= len(spec) <= 2 if len(spec) == 2: # Conversion test. - rtf_entries = r"{\*\cxs S}%s" % spec[0] - dict_entries = '"S": %r' % spec[1] + rtf_entries = rf"{{\*\cxs S}}{spec[0]}" + dict_entries = f'"S": {spec[1]!r}' else: spec = textwrap.dedent(spec[0]).lstrip() if not spec: rtf_entries, dict_entries = "", "" else: rtf_entries, dict_entries = tuple(spec.rsplit("\n\n", 1)) - kwargs = dict(marks=pytest.mark.xfail) if xfail else {} + kwargs = {"marks": pytest.mark.xfail} if xfail else {} return pytest.param(rtf_entries, dict_entries, **kwargs) @@ -544,7 +543,7 @@ def make_dict(contents): rtf = "\r\n".join( [r"{\rtf1\ansi\cxdict{\*\cxrev100}{\*\cxsystem Fake Software}"] + [r"{\stylesheet"] - + [r"{\s%d %s;}" % (k, v) for k, v in rtf_styles.items()] + + [rf"{{\s{k} {v};}}" for k, v in rtf_styles.items()] + ["}", contents, "}", ""] ) return rtf.encode("cp1252") diff --git a/test/test_steno.py b/test/test_steno.py index 1f113e9dc..e30c291a9 100644 --- a/test/test_steno.py +++ b/test/test_steno.py @@ -7,11 +7,9 @@ import pytest -from plover.steno import normalize_steno, Stroke - +from plover.steno import Stroke, normalize_steno from plover_build_utils.testing import parametrize - NORMALIZE_TESTS = ( lambda: ("S", ("S",)), lambda: ("S-", ("S",)), @@ -78,7 +76,7 @@ def test_normalize_steno(mode, steno, expected): return expected = expected[1] result = normalize_steno(steno, **kwargs) - msg = "normalize_steno(%r, %s)=%r != %r" % (steno, mode, result, expected) + msg = f"normalize_steno({steno!r}, {mode})={result!r} != {expected!r}" assert result == expected, msg diff --git a/test/test_steno_dictionary.py b/test/test_steno_dictionary.py index 0981c0406..ab6d687bc 100644 --- a/test/test_steno_dictionary.py +++ b/test/test_steno_dictionary.py @@ -6,7 +6,6 @@ import pytest from plover.steno_dictionary import StenoDictionary, StenoDictionaryCollection - from plover_build_utils.testing import dictionary_test diff --git a/test/test_stentura.py b/test/test_stentura.py index 5c25e5e53..b8f8f6ebb 100644 --- a/test/test_stentura.py +++ b/test/test_stentura.py @@ -25,7 +25,7 @@ def make_response(seq, action, error=0, p1=0, p2=0, data=None, length=None): return response -def make_read_response(seq, data=[]): +def make_read_response(seq, data=b""): return make_response(seq, stentura._READC, p1=len(data), data=data) @@ -91,7 +91,7 @@ def __init__(self, responses, requests=None): def write(self, data): self.writes += 1 if self._requests and self._requests[self.writes - 1] != bytes(data): - raise Exception("Wrong packet.") + raise RuntimeError("Wrong packet.") self._current_response_offset = 0 return len(data) @@ -268,7 +268,7 @@ def test_read_data_simple(): class MockPort: def read(self, count): if count != 5: - raise Exception("Incorrect number read.") + raise RuntimeError("Incorrect number read.") return b"12345" port = MockPort() @@ -358,7 +358,7 @@ def read(self, count): if self._set2: self.event.set() else: - raise Exception("Already read data.") + raise RuntimeError("Already read data.") if self._give_timeout and len(self._data) == count: # If read() returns less bytes what was requested, # it indicates a timeout. @@ -511,10 +511,10 @@ def __init__(self, count, data, stop=False): self.stop = stop def __repr__(self): - return "<{}, {}, {}>".format(self.count, self.data, self.stop) + return f"<{self.count}, {self.data}, {self.stop}>" class MockPort: - def __init__(self, events=[]): + def __init__(self, events=()): self._file = b"" self._out = b"" self._is_open = False @@ -530,7 +530,7 @@ def write(self, request): self._is_open = True elif p["action"] == stentura._READC: if not self._is_open: - raise Exception("no open") + raise RuntimeError("no open") length, block, byte = p["p3"], p["p4"], p["p5"] seq = p["seq"] action = stentura._READC @@ -579,7 +579,7 @@ def flushOutput(self): for test in tests: read_data = [] - def callback(data): + def callback(data, read_data=read_data): read_data.append(data) port = test[0] @@ -587,7 +587,7 @@ def callback(data): ready_called = [False] - def ready(): + def ready(ready_called=ready_called): ready_called[0] = True try: diff --git a/test/test_translation.py b/test/test_translation.py index 8d2dc575e..6fc6a8ff3 100644 --- a/test/test_translation.py +++ b/test/test_translation.py @@ -3,22 +3,25 @@ """Unit tests for translation.py.""" -from collections import namedtuple import ast import copy import operator - -from plover.oslayer.config import PLATFORM -from plover.steno import Stroke, normalize_steno +from collections import namedtuple import pytest +from plover.oslayer.config import PLATFORM +from plover.steno import Stroke, normalize_steno from plover.steno_dictionary import StenoDictionary, StenoDictionaryCollection -from plover.translation import Translation, Translator, _State -from plover.translation import escape_translation, unescape_translation - -from plover_build_utils.testing import parametrize, steno_to_stroke as stroke - +from plover.translation import ( + Translation, + Translator, + _State, + escape_translation, + unescape_translation, +) +from plover_build_utils.testing import parametrize +from plover_build_utils.testing import steno_to_stroke as stroke if PLATFORM == "mac": BACK_STRING = "{#Alt_L(BackSpace)}{^}" @@ -460,11 +463,11 @@ def translate(self, steno): def _check_translations(self, expected): # Hide from traceback on assertions (reduce output size for failed tests). __tracebackhide__ = operator.methodcaller("errisinstance", AssertionError) - msg = """ + msg = f""" translations: - results: %s - expected: %s - """ % (self.s.translations, expected) + results: {self.s.translations} + expected: {expected} + """ assert self.s.translations == expected, msg def _check_output(self, undo, do, prev): @@ -850,11 +853,11 @@ def _check_lookup_history(self, expected): __tracebackhide__ = operator.methodcaller("errisinstance", AssertionError) result = ["/".join(key) for key in self.dc.lookup_history] expected = expected.split() - msg = """ + msg = f""" lookup history: - results: %s - expected: %s - """ % (result, expected) + results: {result} + expected: {expected} + """ assert result == expected, msg def test_zero_lookups(self):