diff --git a/src/click/_termui_impl.py b/src/click/_termui_impl.py index ee8225c4c..e755f8a38 100644 --- a/src/click/_termui_impl.py +++ b/src/click/_termui_impl.py @@ -173,7 +173,14 @@ def format_eta(self) -> str: hours = t % 24 t //= 24 if t > 0: - return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + return "{d}{day_label} {h:02}:{m:02}:{s:02}".format( + d=t, + # TRANSLATORS: The 'd' stands for 'day'. + day_label=_("d"), + h=hours, + m=minutes, + s=seconds, + ) else: return f"{hours:02}:{minutes:02}:{seconds:02}" return "" diff --git a/src/click/_winconsole.py b/src/click/_winconsole.py index e56c7c6ae..d25178d66 100644 --- a/src/click/_winconsole.py +++ b/src/click/_winconsole.py @@ -28,6 +28,7 @@ from ctypes.wintypes import HANDLE from ctypes.wintypes import LPCWSTR from ctypes.wintypes import LPWSTR +from gettext import gettext as _ from ._compat import _NonClosingTextIOWrapper @@ -152,7 +153,7 @@ def readinto(self, b: Buffer) -> int: # wait for KeyboardInterrupt time.sleep(0.1) if not rv: - raise OSError(f"Windows error: {GetLastError()}") + raise OSError(_("Windows error: {error}").format(error=GetLastError())) if buffer[0] == EOF: return 0 @@ -169,7 +170,7 @@ def _get_error_message(errno: int) -> str: return "ERROR_SUCCESS" elif errno == ERROR_NOT_ENOUGH_MEMORY: return "ERROR_NOT_ENOUGH_MEMORY" - return f"Windows error {errno}" + return _("Windows error: {error}").format(error=errno) def write(self, b: Buffer) -> int: bytes_to_be_written = len(b) diff --git a/src/click/core.py b/src/click/core.py index 6adc65ccd..a21b801b5 100644 --- a/src/click/core.py +++ b/src/click/core.py @@ -2902,7 +2902,7 @@ def _parse_decls( for decl in decls: if decl.isidentifier(): if name is not None: - raise TypeError(f"Name '{name}' defined twice") + raise TypeError(_("Name '{name}' defined twice").format(name=name)) name = decl else: split_char = ";" if decl[:1] == "/" else "/" @@ -2917,8 +2917,10 @@ def _parse_decls( secondary_opts.append(second.lstrip()) if first == second: raise ValueError( - f"Boolean option {decl!r} cannot use the" - " same flag for true/false." + _( + "Boolean option {decl!r} cannot use the" + " same flag for true/false." + ).format(decl=decl) ) else: possible_names.append(_split_opt(decl)) @@ -2934,14 +2936,18 @@ def _parse_decls( if not expose_value: return None, opts, secondary_opts raise TypeError( - f"Could not determine name for option with declarations {decls!r}" + _( + "Could not determine name for option with declarations {decls!r}" + ).format(decls=decls) ) if not opts and not secondary_opts: raise TypeError( - f"No options defined but a name was passed ({name})." - " Did you mean to declare an argument instead? Did" - f" you mean to pass '--{name}'?" + _( + "No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + " you mean to pass '--{name}'?" + ).format(name=name) ) return name, opts, secondary_opts @@ -3379,8 +3385,10 @@ def _parse_decls( name = name.replace("-", "_").lower() else: raise TypeError( - "Arguments take exactly one parameter declaration, got" - f" {len(decls)}: {decls}." + _( + "Arguments take exactly one parameter declaration, got" + " {length}: {decls}." + ).format(length=len(decls), decls=decls) ) return name, [arg], [] diff --git a/src/click/formatting.py b/src/click/formatting.py index 0b64f831b..de2ca4711 100644 --- a/src/click/formatting.py +++ b/src/click/formatting.py @@ -153,7 +153,7 @@ def write_usage(self, prog: str, args: str = "", prefix: str | None = None) -> N ``"Usage: "``. """ if prefix is None: - prefix = f"{_('Usage:')} " + prefix = "{usage} ".format(usage=_("Usage:")) usage_prefix = f"{prefix:>{self.current_indent}}{prog} " text_width = self.width - self.current_indent diff --git a/src/click/parser.py b/src/click/parser.py index 1ea1f7166..d9a764950 100644 --- a/src/click/parser.py +++ b/src/click/parser.py @@ -141,7 +141,11 @@ def __init__( for opt in opts: prefix, value = _split_opt(opt) if not prefix: - raise ValueError(f"Invalid start character for option ({opt})") + raise ValueError( + _("Invalid start character for option ({option})").format( + option=opt + ) + ) self.prefixes.add(prefix[0]) if len(prefix) == 1 and len(value) == 1: self._short_opts.append(opt) diff --git a/src/click/termui.py b/src/click/termui.py index 2e98a0771..2cd1d31ba 100644 --- a/src/click/termui.py +++ b/src/click/termui.py @@ -614,13 +614,13 @@ def style( try: bits.append(f"\033[{_interpret_color(fg)}m") except KeyError: - raise TypeError(f"Unknown color {fg!r}") from None + raise TypeError(_("Unknown color {colour!r}").format(colour=fg)) from None if bg: try: bits.append(f"\033[{_interpret_color(bg, 10)}m") except KeyError: - raise TypeError(f"Unknown color {bg!r}") from None + raise TypeError(_("Unknown color {colour!r}").format(colour=bg)) from None if bold is not None: bits.append(f"\033[{1 if bold else 22}m") diff --git a/src/click/types.py b/src/click/types.py index e71c1c21e..bac598234 100644 --- a/src/click/types.py +++ b/src/click/types.py @@ -372,7 +372,7 @@ def get_invalid_choice_message(self, value: t.Any, ctx: Context | None) -> str: ).format(value=value, choice=choices_str, choices=choices_str) def __repr__(self) -> str: - return f"Choice({list(self.choices)})" + return _("Choice({choices})").format(choices=list(self.choices)) def shell_complete( self, ctx: Context, param: Parameter, incomplete: str @@ -853,7 +853,11 @@ def convert( return f except OSError as e: - self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) + self.fail( + f"'{format_filename(value)}': {e.strerror}", + param, + ctx, + ) def shell_complete( self, ctx: Context, param: Parameter, incomplete: str diff --git a/src/click/utils.py b/src/click/utils.py index beae26f76..a8076a663 100644 --- a/src/click/utils.py +++ b/src/click/utils.py @@ -6,6 +6,7 @@ import sys import typing as t from functools import update_wrapper +from gettext import gettext as _ from types import ModuleType from types import TracebackType @@ -330,7 +331,7 @@ def get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryI """ opener = binary_streams.get(name) if opener is None: - raise TypeError(f"Unknown standard stream '{name}'") + raise TypeError(_("Unknown standard stream '{name}'").format(name=name)) return opener() @@ -351,7 +352,7 @@ def get_text_stream( """ opener = text_streams.get(name) if opener is None: - raise TypeError(f"Unknown standard stream '{name}'") + raise TypeError(_("Unknown standard stream '{name}'").format(name=name)) return opener(encoding, errors)