ruyi 0.44.0b20251219__py3-none-any.whl → 0.45.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. ruyi/__main__.py +16 -4
  2. ruyi/cli/cmd.py +6 -5
  3. ruyi/cli/config_cli.py +14 -11
  4. ruyi/cli/main.py +14 -4
  5. ruyi/cli/oobe.py +7 -3
  6. ruyi/cli/self_cli.py +48 -34
  7. ruyi/cli/user_input.py +42 -12
  8. ruyi/cli/version_cli.py +11 -5
  9. ruyi/config/__init__.py +26 -2
  10. ruyi/config/errors.py +19 -7
  11. ruyi/device/provision.py +116 -55
  12. ruyi/device/provision_cli.py +6 -3
  13. ruyi/i18n/__init__.py +129 -0
  14. ruyi/log/__init__.py +6 -5
  15. ruyi/mux/runtime.py +19 -6
  16. ruyi/mux/venv/maker.py +93 -35
  17. ruyi/mux/venv/venv_cli.py +13 -10
  18. ruyi/pluginhost/plugin_cli.py +4 -3
  19. ruyi/resource_bundle/__init__.py +22 -8
  20. ruyi/resource_bundle/__main__.py +6 -5
  21. ruyi/resource_bundle/data.py +13 -9
  22. ruyi/ruyipkg/admin_checksum.py +4 -1
  23. ruyi/ruyipkg/admin_cli.py +9 -6
  24. ruyi/ruyipkg/augmented_pkg.py +15 -14
  25. ruyi/ruyipkg/checksum.py +8 -2
  26. ruyi/ruyipkg/distfile.py +33 -9
  27. ruyi/ruyipkg/entity.py +12 -2
  28. ruyi/ruyipkg/entity_cli.py +20 -12
  29. ruyi/ruyipkg/entity_provider.py +11 -2
  30. ruyi/ruyipkg/fetcher.py +38 -9
  31. ruyi/ruyipkg/install.py +143 -42
  32. ruyi/ruyipkg/install_cli.py +18 -15
  33. ruyi/ruyipkg/list.py +27 -20
  34. ruyi/ruyipkg/list_cli.py +12 -7
  35. ruyi/ruyipkg/news.py +23 -11
  36. ruyi/ruyipkg/news_cli.py +10 -7
  37. ruyi/ruyipkg/profile_cli.py +8 -2
  38. ruyi/ruyipkg/repo.py +22 -8
  39. ruyi/ruyipkg/unpack.py +42 -8
  40. ruyi/ruyipkg/unpack_method.py +5 -1
  41. ruyi/ruyipkg/update_cli.py +8 -3
  42. ruyi/telemetry/provider.py +74 -29
  43. ruyi/telemetry/telemetry_cli.py +9 -8
  44. ruyi/utils/git.py +18 -11
  45. ruyi/utils/prereqs.py +10 -5
  46. ruyi/utils/ssl_patch.py +2 -1
  47. ruyi/version.py +9 -3
  48. {ruyi-0.44.0b20251219.dist-info → ruyi-0.45.0.dist-info}/METADATA +2 -1
  49. ruyi-0.45.0.dist-info/RECORD +103 -0
  50. {ruyi-0.44.0b20251219.dist-info → ruyi-0.45.0.dist-info}/WHEEL +1 -1
  51. ruyi-0.44.0b20251219.dist-info/RECORD +0 -102
  52. {ruyi-0.44.0b20251219.dist-info → ruyi-0.45.0.dist-info}/entry_points.txt +0 -0
  53. {ruyi-0.44.0b20251219.dist-info → ruyi-0.45.0.dist-info}/licenses/LICENSE-Apache.txt +0 -0
ruyi/__main__.py CHANGED
@@ -1,9 +1,11 @@
1
1
  #!/usr/bin/env python3
2
2
 
3
3
  import os
4
+ import pathlib
4
5
  import sys
5
6
 
6
7
  import ruyi
8
+ from ruyi.i18n import _, ADAPTER
7
9
  from ruyi.utils.ci import is_running_in_ci
8
10
  from ruyi.utils.global_mode import (
9
11
  EnvGlobalModeProvider,
@@ -41,6 +43,8 @@ def _is_allowed_to_run_as_root() -> bool:
41
43
 
42
44
  def entrypoint() -> None:
43
45
  gm = EnvGlobalModeProvider(os.environ, sys.argv)
46
+ ADAPTER.init_from_env(os.environ)
47
+ ADAPTER.hook()
44
48
 
45
49
  # NOTE: import of `ruyi.log` takes ~90ms on my machine, so initialization
46
50
  # of logging is deferred as late as possible
@@ -50,11 +54,16 @@ def entrypoint() -> None:
50
54
 
51
55
  logger = RuyiConsoleLogger(gm)
52
56
 
53
- logger.F("refusing to run as super user outside CI without explicit consent")
57
+ logger.F(_("refusing to run as super user outside CI without explicit consent"))
54
58
 
55
59
  choices = ", ".join(f"'{x}'" for x in TRUTHY_ENV_VAR_VALUES)
56
60
  logger.I(
57
- f"re-run with environment variable [yellow]{ENV_FORCE_ALLOW_ROOT}[/] set to one of [yellow]{choices}[/] to signify consent"
61
+ _(
62
+ "re-run with environment variable [yellow]{env_var}[/] set to one of [yellow]{choices}[/] to signify consent"
63
+ ).format(
64
+ env_var=ENV_FORCE_ALLOW_ROOT,
65
+ choices=choices,
66
+ )
58
67
  )
59
68
  sys.exit(1)
60
69
 
@@ -63,7 +72,7 @@ def entrypoint() -> None:
63
72
 
64
73
  logger = RuyiConsoleLogger(gm)
65
74
 
66
- logger.F("no argv?")
75
+ logger.F(_("no argv?"))
67
76
  sys.exit(1)
68
77
 
69
78
  if gm.is_packaged and ruyi.__compiled__.standalone:
@@ -85,8 +94,11 @@ def entrypoint() -> None:
85
94
  #
86
95
  # we assume the one-file build if Nuitka is detected; sys.argv[0] does NOT
87
96
  # work if it's just `ruyi` so we have to check our parent process in that case
88
- self_exe = get_nuitka_self_exe() if gm.is_packaged else __file__
89
97
  sys.argv[0] = get_argv0()
98
+ if gm.is_packaged:
99
+ self_exe = get_nuitka_self_exe()
100
+ else:
101
+ self_exe = str(pathlib.Path(sys.argv[0]).resolve())
90
102
  gm.record_self_exe(sys.argv[0], __file__, self_exe)
91
103
 
92
104
  from ruyi.config import GlobalConfig
ruyi/cli/cmd.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import argparse
2
2
  from typing import Callable, IO, Protocol, TYPE_CHECKING
3
3
 
4
+ from ..i18n import _
4
5
  from . import RUYI_ENTRYPOINT_NAME
5
6
 
6
7
  if TYPE_CHECKING:
@@ -114,7 +115,7 @@ class BaseCommand:
114
115
  return
115
116
 
116
117
  sp = p.add_subparsers(
117
- title="subcommands",
118
+ title=_("subcommands"),
118
119
  required=cls.is_subcommand_required,
119
120
  )
120
121
  for subcmd_cls in cls.parsers:
@@ -158,7 +159,7 @@ class RootCommand(
158
159
  has_subcommands=True,
159
160
  has_main=True,
160
161
  prog=RUYI_ENTRYPOINT_NAME,
161
- description="RuyiSDK Package Manager",
162
+ description=_("RuyiSDK Package Manager"),
162
163
  ):
163
164
  @classmethod
164
165
  def configure_args(cls, gc: "GlobalConfig", p: "ArgumentParser") -> None:
@@ -170,12 +171,12 @@ class RootCommand(
170
171
  action="store_const",
171
172
  dest="func",
172
173
  const=cli_version,
173
- help="Print version information",
174
+ help=_("Print version information"),
174
175
  )
175
176
  p.add_argument(
176
177
  "--porcelain",
177
178
  action="store_true",
178
- help="Give the output in a machine-friendly format if applicable",
179
+ help=_("Give the output in a machine-friendly format if applicable"),
179
180
  )
180
181
 
181
182
  # https://github.com/python/cpython/issues/67037 prevents the registration
@@ -219,7 +220,7 @@ class AdminCommand(
219
220
  has_subcommands=True,
220
221
  # https://github.com/python/cpython/issues/67037
221
222
  # help=argparse.SUPPRESS,
222
- help="(NOT FOR REGULAR USERS) Subcommands for managing Ruyi repos",
223
+ help=_("(NOT FOR REGULAR USERS) Subcommands for managing Ruyi repos"),
223
224
  ):
224
225
  @classmethod
225
226
  def configure_args(cls, gc: "GlobalConfig", p: "ArgumentParser") -> None:
ruyi/cli/config_cli.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import argparse
2
2
  from typing import TYPE_CHECKING
3
3
 
4
+ from ..i18n import _
4
5
  from .cmd import RootCommand
5
6
 
6
7
  if TYPE_CHECKING:
@@ -13,7 +14,7 @@ class ConfigCommand(
13
14
  RootCommand,
14
15
  cmd="config",
15
16
  has_subcommands=True,
16
- help="Manage Ruyi's config options",
17
+ help=_("Manage Ruyi's config options"),
17
18
  ):
18
19
  @classmethod
19
20
  def configure_args(
@@ -27,7 +28,7 @@ class ConfigCommand(
27
28
  class ConfigGetCommand(
28
29
  ConfigCommand,
29
30
  cmd="get",
30
- help="Query the value of a Ruyi config option",
31
+ help=_("Query the value of a Ruyi config option"),
31
32
  ):
32
33
  @classmethod
33
34
  def configure_args(
@@ -38,7 +39,7 @@ class ConfigGetCommand(
38
39
  p.add_argument(
39
40
  "key",
40
41
  type=str,
41
- help="The Ruyi config option to query",
42
+ help=_("The Ruyi config option to query"),
42
43
  )
43
44
 
44
45
  @classmethod
@@ -66,7 +67,7 @@ class ConfigGetCommand(
66
67
  class ConfigSetCommand(
67
68
  ConfigCommand,
68
69
  cmd="set",
69
- help="Set the value of a Ruyi config option",
70
+ help=_("Set the value of a Ruyi config option"),
70
71
  ):
71
72
  @classmethod
72
73
  def configure_args(
@@ -77,12 +78,12 @@ class ConfigSetCommand(
77
78
  p.add_argument(
78
79
  "key",
79
80
  type=str,
80
- help="The Ruyi config option to set",
81
+ help=_("The Ruyi config option to set"),
81
82
  )
82
83
  p.add_argument(
83
84
  "value",
84
85
  type=str,
85
- help="The value to set the option to",
86
+ help=_("The value to set the option to"),
86
87
  )
87
88
 
88
89
  @classmethod
@@ -100,7 +101,9 @@ class ConfigSetCommand(
100
101
  ed.set_value(key, pyval)
101
102
  except ProtectedGlobalConfigError:
102
103
  cfg.logger.F(
103
- f"the config [yellow]{key}[/] is protected and not meant to be overridden by users",
104
+ _(
105
+ "the config [yellow]{key}[/] is protected and not meant to be overridden by users"
106
+ ).format(key=key)
104
107
  )
105
108
  return 2
106
109
 
@@ -112,7 +115,7 @@ class ConfigSetCommand(
112
115
  class ConfigUnsetCommand(
113
116
  ConfigCommand,
114
117
  cmd="unset",
115
- help="Unset a Ruyi config option",
118
+ help=_("Unset a Ruyi config option"),
116
119
  ):
117
120
  @classmethod
118
121
  def configure_args(
@@ -123,7 +126,7 @@ class ConfigUnsetCommand(
123
126
  p.add_argument(
124
127
  "key",
125
128
  type=str,
126
- help="The Ruyi config option to unset",
129
+ help=_("The Ruyi config option to unset"),
127
130
  )
128
131
 
129
132
  @classmethod
@@ -142,7 +145,7 @@ class ConfigUnsetCommand(
142
145
  class ConfigRemoveSectionCommand(
143
146
  ConfigCommand,
144
147
  cmd="remove-section",
145
- help="Remove a section from the Ruyi config",
148
+ help=_("Remove a section from the Ruyi config"),
146
149
  ):
147
150
  @classmethod
148
151
  def configure_args(
@@ -153,7 +156,7 @@ class ConfigRemoveSectionCommand(
153
156
  p.add_argument(
154
157
  "section",
155
158
  type=str,
156
- help="The section to remove",
159
+ help=_("The section to remove"),
157
160
  )
158
161
 
159
162
  @classmethod
ruyi/cli/main.py CHANGED
@@ -4,6 +4,7 @@ import sys
4
4
  from typing import Final, TYPE_CHECKING
5
5
 
6
6
  from ..config import GlobalConfig
7
+ from ..i18n import _
7
8
  from ..telemetry.scope import TelemetryScope
8
9
  from ..utils.global_mode import GlobalModeProvider
9
10
  from ..version import RUYI_SEMVER
@@ -50,10 +51,19 @@ def main(gm: GlobalModeProvider, gc: GlobalConfig, argv: list[str]) -> int:
50
51
  if not is_called_as_ruyi(gm.argv0):
51
52
  if should_prompt_for_renaming(gm.argv0):
52
53
  logger.F(
53
- f"the {RUYI_ENTRYPOINT_NAME} executable must be named [green]'{RUYI_ENTRYPOINT_NAME}'[/] to work"
54
+ _(
55
+ "the {ruyi_exe} executable must be named [green]'{expected_name}'[/] to work"
56
+ ).format(
57
+ ruyi_exe=RUYI_ENTRYPOINT_NAME,
58
+ expected_name=RUYI_ENTRYPOINT_NAME,
59
+ )
54
60
  )
55
- logger.I(f"it is now [yellow]'{gm.argv0}'[/]")
56
- logger.I("please rename the command file and retry")
61
+ logger.I(
62
+ _("it is now [yellow]'{current_name}'[/]").format(
63
+ current_name=gm.argv0,
64
+ )
65
+ )
66
+ logger.I(_("please rename the command file and retry"))
57
67
  return 1
58
68
 
59
69
  from ..mux.runtime import mux_main
@@ -115,7 +125,7 @@ def main(gm: GlobalModeProvider, gc: GlobalConfig, argv: list[str]) -> int:
115
125
  try:
116
126
  telemetry_key: str = args.tele_key
117
127
  except AttributeError:
118
- logger.F("internal error: CLI entrypoint was added without a telemetry key")
128
+ logger.F(_("internal error: CLI entrypoint was added without a telemetry key"))
119
129
  return 1
120
130
 
121
131
  # Special-case the `--output-completion-script` argument; treat it as if
ruyi/cli/oobe.py CHANGED
@@ -2,13 +2,16 @@
2
2
 
3
3
  import os
4
4
  import sys
5
- from typing import Callable, TYPE_CHECKING
5
+ from typing import Callable, Final, TYPE_CHECKING
6
+
7
+ from ..i18n import _, d_
6
8
 
7
9
  if TYPE_CHECKING:
8
10
  from ..config import GlobalConfig
9
11
 
10
12
 
11
- SHELL_AUTO_COMPLETION_TIP = """
13
+ SHELL_AUTO_COMPLETION_TIP: Final = d_(
14
+ """
12
15
  [bold green]tip[/]: you can enable shell auto-completion for [yellow]ruyi[/] by adding the
13
16
  following line to your [green]{shrc}[/], if you have not done so already:
14
17
 
@@ -18,6 +21,7 @@ You can do so by running the following command later:
18
21
 
19
22
  [green]echo 'eval "$(ruyi --output-completion-script={shell})"' >> {shrc}[/]
20
23
  """
24
+ )
21
25
 
22
26
 
23
27
  class OOBE:
@@ -74,7 +78,7 @@ class OOBE:
74
78
  return
75
79
 
76
80
  self._gc.logger.stdout(
77
- SHELL_AUTO_COMPLETION_TIP.format(
81
+ _(SHELL_AUTO_COMPLETION_TIP).format(
78
82
  shell=shell,
79
83
  shrc=f"~/.{shell}rc",
80
84
  )
ruyi/cli/self_cli.py CHANGED
@@ -4,13 +4,16 @@ import pathlib
4
4
  import shutil
5
5
  from typing import Final, TYPE_CHECKING
6
6
 
7
+ from ..i18n import _, d_
7
8
  from .cmd import RootCommand
8
9
 
9
10
  if TYPE_CHECKING:
10
11
  from .completion import ArgumentParser
11
12
  from .. import config
12
13
 
13
- UNINSTALL_NOTICE: Final = """
14
+
15
+ UNINSTALL_NOTICE: Final = d_(
16
+ """
14
17
  [bold]Thanks for hacking with [yellow]Ruyi[/]![/]
15
18
 
16
19
  This will uninstall [yellow]Ruyi[/] from your system, and optionally remove
@@ -21,6 +24,7 @@ Note that your [yellow]Ruyi[/] virtual environments [bold]will become unusable[/
21
24
  [yellow]Ruyi[/] is uninstalled. You should take care of migrating or cleaning
22
25
  them yourselves afterwards.
23
26
  """
27
+ )
24
28
 
25
29
 
26
30
  # Self-management commands
@@ -28,7 +32,7 @@ class SelfCommand(
28
32
  RootCommand,
29
33
  cmd="self",
30
34
  has_subcommands=True,
31
- help="Manage this Ruyi installation",
35
+ help=_("Manage this Ruyi installation"),
32
36
  ):
33
37
  @classmethod
34
38
  def configure_args(
@@ -42,7 +46,7 @@ class SelfCommand(
42
46
  class SelfCleanCommand(
43
47
  SelfCommand,
44
48
  cmd="clean",
45
- help="Remove various Ruyi-managed data to reclaim storage",
49
+ help=_("Remove various Ruyi-managed data to reclaim storage"),
46
50
  ):
47
51
  @classmethod
48
52
  def configure_args(
@@ -54,42 +58,42 @@ class SelfCleanCommand(
54
58
  "--quiet",
55
59
  "-q",
56
60
  action="store_true",
57
- help="Do not print out the actions being performed",
61
+ help=_("Do not print out the actions being performed"),
58
62
  )
59
63
  p.add_argument(
60
64
  "--all",
61
65
  action="store_true",
62
- help="Remove all covered data",
66
+ help=_("Remove all covered data"),
63
67
  )
64
68
  p.add_argument(
65
69
  "--distfiles",
66
70
  action="store_true",
67
- help="Remove all downloaded distfiles if any",
71
+ help=_("Remove all downloaded distfiles if any"),
68
72
  )
69
73
  p.add_argument(
70
74
  "--installed-pkgs",
71
75
  action="store_true",
72
- help="Remove all installed packages if any",
76
+ help=_("Remove all installed packages if any"),
73
77
  )
74
78
  p.add_argument(
75
79
  "--news-read-status",
76
80
  action="store_true",
77
- help="Mark all news items as unread",
81
+ help=_("Mark all news items as unread"),
78
82
  )
79
83
  p.add_argument(
80
84
  "--progcache",
81
85
  action="store_true",
82
- help="Clear the Ruyi program cache",
86
+ help=_("Clear the Ruyi program cache"),
83
87
  )
84
88
  p.add_argument(
85
89
  "--repo",
86
90
  action="store_true",
87
- help="Remove the Ruyi repo if located in Ruyi-managed cache directory",
91
+ help=_("Remove the Ruyi repo if located in Ruyi-managed cache directory"),
88
92
  )
89
93
  p.add_argument(
90
94
  "--telemetry",
91
95
  action="store_true",
92
- help="Remove all telemetry data recorded if any",
96
+ help=_("Remove all telemetry data recorded if any"),
93
97
  )
94
98
 
95
99
  @classmethod
@@ -122,9 +126,11 @@ class SelfCleanCommand(
122
126
  telemetry,
123
127
  ]
124
128
  ):
125
- logger.F("no data specified for cleaning")
129
+ logger.F(_("no data specified for cleaning"))
126
130
  logger.I(
127
- "please check [yellow]ruyi self clean --help[/] for a list of cleanable data"
131
+ _(
132
+ "please check [yellow]ruyi self clean --help[/] for a list of cleanable data"
133
+ )
128
134
  )
129
135
  return 1
130
136
 
@@ -149,7 +155,7 @@ class SelfCleanCommand(
149
155
  class SelfUninstallCommand(
150
156
  SelfCommand,
151
157
  cmd="uninstall",
152
- help="Uninstall Ruyi",
158
+ help=_("Uninstall Ruyi"),
153
159
  ):
154
160
  @classmethod
155
161
  def configure_args(
@@ -160,13 +166,15 @@ class SelfUninstallCommand(
160
166
  p.add_argument(
161
167
  "--purge",
162
168
  action="store_true",
163
- help="Remove all installed packages and Ruyi-managed remote repo data",
169
+ help=_("Remove all installed packages and Ruyi-managed remote repo data"),
164
170
  )
165
171
  p.add_argument(
166
172
  "-y",
167
173
  action="store_true",
168
174
  dest="consent",
169
- help="Give consent for uninstallation on CLI; do not ask for confirmation",
175
+ help=_(
176
+ "Give consent for uninstallation on CLI; do not ask for confirmation"
177
+ ),
170
178
  )
171
179
 
172
180
  @classmethod
@@ -180,24 +188,28 @@ class SelfUninstallCommand(
180
188
 
181
189
  if cfg.is_installation_externally_managed:
182
190
  logger.F(
183
- "this [yellow]ruyi[/] is externally managed, for example, by the system package manager, and cannot be uninstalled this way"
191
+ _(
192
+ "this [yellow]ruyi[/] is externally managed, for example, by the system package manager, and cannot be uninstalled this way"
193
+ )
184
194
  )
185
- logger.I("please uninstall via the external manager instead")
195
+ logger.I(_("please uninstall via the external manager instead"))
186
196
  return 1
187
197
 
188
198
  if not cfg.is_packaged:
189
199
  logger.F(
190
- "this [yellow]ruyi[/] is not in standalone form, and cannot be uninstalled this way"
200
+ _(
201
+ "this [yellow]ruyi[/] is not in standalone form, and cannot be uninstalled this way"
202
+ )
191
203
  )
192
204
  return 1
193
205
 
194
206
  if not consent:
195
- logger.stdout(UNINSTALL_NOTICE)
196
- if not user_input.ask_for_yesno_confirmation(logger, "Continue?"):
197
- logger.I("aborting uninstallation")
207
+ logger.stdout(_(UNINSTALL_NOTICE))
208
+ if not user_input.ask_for_yesno_confirmation(logger, _("Continue?")):
209
+ logger.I(_("aborting uninstallation"))
198
210
  return 0
199
211
  else:
200
- logger.I("uninstallation consent given over CLI, proceeding")
212
+ logger.I(_("uninstallation consent given over CLI, proceeding"))
201
213
 
202
214
  _do_reset(
203
215
  cfg,
@@ -208,7 +220,7 @@ class SelfUninstallCommand(
208
220
  self_binary=True,
209
221
  )
210
222
 
211
- logger.I("[yellow]ruyi[/] is uninstalled")
223
+ logger.I(_("[yellow]ruyi[/] is uninstalled"))
212
224
 
213
225
  return 0
214
226
 
@@ -235,7 +247,7 @@ def _do_reset(
235
247
  logger.I(s)
236
248
 
237
249
  if installed_pkgs:
238
- status("removing installed packages")
250
+ status(_("removing installed packages"))
239
251
  shutil.rmtree(cfg.data_root, True)
240
252
  cfg.ruyipkg_global_state.purge_installation_info()
241
253
 
@@ -244,28 +256,28 @@ def _do_reset(
244
256
  cfg.telemetry.discard_events(True)
245
257
 
246
258
  if all_state:
247
- status("removing state data")
259
+ status(_("removing state data"))
248
260
  shutil.rmtree(cfg.state_root, True)
249
261
  else:
250
262
  if news_read_status:
251
- status("removing read status of news items")
263
+ status(_("removing read status of news items"))
252
264
  cfg.news_read_status.remove()
253
265
 
254
266
  if telemetry:
255
- status("removing all telemetry data")
267
+ status(_("removing all telemetry data"))
256
268
  shutil.rmtree(cfg.telemetry_root, True)
257
269
 
258
270
  if all_cache:
259
- status("removing cached data")
271
+ status(_("removing cached data"))
260
272
  shutil.rmtree(cfg.cache_root, True)
261
273
  else:
262
274
  if distfiles:
263
- status("removing downloaded distfiles")
275
+ status(_("removing downloaded distfiles"))
264
276
  # TODO: deduplicate the path derivation
265
277
  shutil.rmtree(os.path.join(cfg.cache_root, "distfiles"), True)
266
278
 
267
279
  if progcache:
268
- status("clearing the Ruyi program cache")
280
+ status(_("clearing the Ruyi program cache"))
269
281
  # TODO: deduplicate the path derivation
270
282
  shutil.rmtree(os.path.join(cfg.cache_root, "progcache"), True)
271
283
 
@@ -283,14 +295,16 @@ def _do_reset(
283
295
 
284
296
  if not repo_is_below_cache_root:
285
297
  logger.W(
286
- "not removing the Ruyi repo: it is outside of the Ruyi cache directory"
298
+ _(
299
+ "not removing the Ruyi repo: it is outside of the Ruyi cache directory"
300
+ )
287
301
  )
288
302
  else:
289
- status("removing the Ruyi repo")
303
+ status(_("removing the Ruyi repo"))
290
304
  shutil.rmtree(repo_dir, True)
291
305
 
292
306
  if self_binary:
293
- status("removing the ruyi binary")
307
+ status(_("removing the ruyi binary"))
294
308
  try:
295
309
  os.unlink(cfg.self_exe)
296
310
  except FileNotFoundError:
ruyi/cli/user_input.py CHANGED
@@ -1,5 +1,6 @@
1
1
  import os.path
2
2
 
3
+ from ..i18n import _
3
4
  from ..log import RuyiLogger
4
5
 
5
6
 
@@ -10,7 +11,7 @@ def pause_before_continuing(
10
11
 
11
12
  EOFError should be handled by the caller."""
12
13
 
13
- logger.stdout("Press [green]<ENTER>[/] to continue: ", end="")
14
+ logger.stdout(_("Press [green]<ENTER>[/] to continue: "), end="")
14
15
  input()
15
16
 
16
17
 
@@ -26,9 +27,11 @@ def ask_for_yesno_confirmation(
26
27
  logger.stdout(f"{prompt} {choices_help} ", end="")
27
28
  user_input = input()
28
29
  except EOFError:
29
- yesno = "YES" if default else "NO"
30
+ yesno = _("YES") if default else _("NO")
30
31
  logger.W(
31
- f"EOF while reading user input, assuming the default choice {yesno}"
32
+ _(
33
+ "EOF while reading user input, assuming the default choice {yesno}"
34
+ ).format(yesno=yesno)
32
35
  )
33
36
  return default
34
37
 
@@ -39,8 +42,12 @@ def ask_for_yesno_confirmation(
39
42
  if user_input in {"N", "n", "no"}:
40
43
  return False
41
44
  else:
42
- logger.stdout(f"Unrecognized input [yellow]'{user_input}'[/].")
43
- logger.stdout("Accepted choices: Y/y/yes for YES, N/n/no for NO.")
45
+ logger.stdout(
46
+ _("Unrecognized input [yellow]'{user_input}'[/].").format(
47
+ user_input=user_input
48
+ )
49
+ )
50
+ logger.stdout(_("Accepted choices: Y/y/yes for YES, N/n/no for NO."))
44
51
 
45
52
 
46
53
  def ask_for_kv_choice(
@@ -81,12 +88,19 @@ def ask_for_choice(
81
88
  if default_idx is not None:
82
89
  if not (0 <= default_idx < nr_choices):
83
90
  raise ValueError(f"Default choice index {default_idx} out of range")
84
- choices_help = f"(1-{nr_choices}, default {default_idx + 1})"
91
+ choices_help = _("(1-{nr_choices}, default {default})").format(
92
+ nr_choices=nr_choices,
93
+ default=default_idx + 1,
94
+ )
85
95
  else:
86
- choices_help = f"(1-{nr_choices})"
96
+ choices_help = _("(1-{nr_choices})").format(nr_choices=nr_choices)
87
97
  while True:
88
98
  try:
89
- user_input = input(f"Choice? {choices_help} ")
99
+ user_input = input(
100
+ _("Choice? {choices_help} ").format(
101
+ choices_help=choices_help,
102
+ )
103
+ )
90
104
  except EOFError:
91
105
  raise ValueError("EOF while reading user choice")
92
106
 
@@ -96,18 +110,34 @@ def ask_for_choice(
96
110
  try:
97
111
  choice_int = int(user_input)
98
112
  except ValueError:
99
- logger.stdout(f"Unrecognized input [yellow]'{user_input}'[/].")
100
113
  logger.stdout(
101
- f"Accepted choices: an integer number from 1 to {nr_choices} inclusive."
114
+ _("Unrecognized input [yellow]'{user_input}'[/].").format(
115
+ user_input=user_input,
116
+ )
117
+ )
118
+ logger.stdout(
119
+ _(
120
+ "Accepted choices: an integer number from 1 to {nr_choices} inclusive."
121
+ ).format(
122
+ nr_choices=nr_choices,
123
+ )
102
124
  )
103
125
  continue
104
126
 
105
127
  if 1 <= choice_int <= nr_choices:
106
128
  return choice_int - 1
107
129
 
108
- logger.stdout(f"Out-of-range input [yellow]'{user_input}'[/].")
109
130
  logger.stdout(
110
- f"Accepted choices: an integer number from 1 to {nr_choices} inclusive."
131
+ _("Out-of-range input [yellow]'{user_input}'[/].").format(
132
+ user_input=user_input,
133
+ )
134
+ )
135
+ logger.stdout(
136
+ _(
137
+ "Accepted choices: an integer number from 1 to {nr_choices} inclusive."
138
+ ).format(
139
+ nr_choices=nr_choices,
140
+ )
111
141
  )
112
142
 
113
143
 
ruyi/cli/version_cli.py CHANGED
@@ -1,6 +1,7 @@
1
1
  import argparse
2
2
  from typing import TYPE_CHECKING
3
3
 
4
+ from ..i18n import _
4
5
  from .cmd import RootCommand
5
6
 
6
7
  if TYPE_CHECKING:
@@ -11,7 +12,7 @@ if TYPE_CHECKING:
11
12
  class VersionCommand(
12
13
  RootCommand,
13
14
  cmd="version",
14
- help="Print version information",
15
+ help=_("Print version information"),
15
16
  ):
16
17
  @classmethod
17
18
  def configure_args(cls, gc: "GlobalConfig", p: "ArgumentParser") -> None:
@@ -27,19 +28,24 @@ def cli_version(cfg: "GlobalConfig", args: argparse.Namespace) -> int:
27
28
  from ..ruyipkg.host import get_native_host
28
29
  from ..version import COPYRIGHT_NOTICE, MPL_REDIST_NOTICE, RUYI_SEMVER
29
30
 
30
- print(f"Ruyi {RUYI_SEMVER}\n\nRunning on {get_native_host()}.")
31
+ print(
32
+ _("Ruyi {version}\n\nRunning on {host}.").format(
33
+ version=RUYI_SEMVER,
34
+ host=get_native_host(),
35
+ )
36
+ )
31
37
 
32
38
  if cfg.is_installation_externally_managed:
33
- print("This Ruyi installation is externally managed.")
39
+ print(_("This Ruyi installation is externally managed."))
34
40
 
35
41
  print()
36
42
 
37
- cfg.logger.stdout(COPYRIGHT_NOTICE)
43
+ cfg.logger.stdout(_(COPYRIGHT_NOTICE))
38
44
 
39
45
  # Output the MPL notice only when we actually bundle and depend on the
40
46
  # MPL component(s), which right now is only certifi. Keep the condition
41
47
  # synced with __main__.py.
42
48
  if hasattr(ruyi, "__compiled__") and ruyi.__compiled__.standalone:
43
- cfg.logger.stdout(MPL_REDIST_NOTICE)
49
+ cfg.logger.stdout(_(MPL_REDIST_NOTICE))
44
50
 
45
51
  return 0