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/ruyipkg/fetcher.py CHANGED
@@ -7,6 +7,7 @@ from typing import Any, Final
7
7
  import requests
8
8
  from rich import progress
9
9
 
10
+ from ..i18n import _
10
11
  from ..log import RuyiLogger
11
12
 
12
13
  ENV_OVERRIDE_FETCHER: Final = "RUYI_OVERRIDE_FETCHER"
@@ -40,19 +41,31 @@ class BaseFetcher:
40
41
  ) -> bool:
41
42
  for t in range(retries):
42
43
  if t > 0:
43
- self._logger.I(f"retrying download ({t + 1} of {retries} times)")
44
+ self._logger.I(
45
+ _("retrying download ({current} of {total} times)").format(
46
+ current=t + 1,
47
+ total=retries,
48
+ )
49
+ )
44
50
  if self.fetch_one(url, dest, resume):
45
51
  return True
46
52
  return False
47
53
 
48
54
  def fetch(self, *, resume: bool = False, retries: int = 3) -> None:
49
55
  for url in self.urls:
50
- self._logger.I(f"downloading {url} to {self.dest}")
56
+ self._logger.I(
57
+ _("downloading {url} to {dest}").format(
58
+ url=url,
59
+ dest=self.dest,
60
+ )
61
+ )
51
62
  if self.fetch_one_with_retry(url, self.dest, resume, retries):
52
63
  return
53
64
  # all URLs have been tried and all have failed
54
65
  raise RuntimeError(
55
- f"failed to fetch '{self.dest}': all source URLs have failed"
66
+ _("failed to fetch '{dest}': all source URLs have failed").format(
67
+ dest=self.dest,
68
+ )
56
69
  )
57
70
 
58
71
  @classmethod
@@ -78,7 +91,7 @@ def get_usable_fetcher_cls(logger: RuyiLogger) -> type[BaseFetcher]:
78
91
 
79
92
  if _fetcher_cache_populated:
80
93
  if _cached_usable_fetcher_class is None:
81
- raise RuntimeError("no fetcher is available on the system")
94
+ raise RuntimeError(_("no fetcher is available on the system"))
82
95
  return _cached_usable_fetcher_class
83
96
 
84
97
  _fetcher_cache_populated = True
@@ -88,10 +101,16 @@ def get_usable_fetcher_cls(logger: RuyiLogger) -> type[BaseFetcher]:
88
101
 
89
102
  cls = KNOWN_FETCHERS.get(override_name)
90
103
  if cls is None:
91
- raise RuntimeError(f"unknown fetcher '{override_name}'")
104
+ raise RuntimeError(
105
+ _("unknown fetcher '{name}'").format(
106
+ name=override_name,
107
+ )
108
+ )
92
109
  if not cls.is_available(logger):
93
110
  raise RuntimeError(
94
- f"the requested fetcher '{override_name}' is unavailable on the system"
111
+ _("the requested fetcher '{name}' is unavailable on the system").format(
112
+ name=override_name,
113
+ )
95
114
  )
96
115
  _cached_usable_fetcher_class = cls
97
116
  return cls
@@ -103,7 +122,7 @@ def get_usable_fetcher_cls(logger: RuyiLogger) -> type[BaseFetcher]:
103
122
  _cached_usable_fetcher_class = cls
104
123
  return cls
105
124
 
106
- raise RuntimeError("no fetcher is available on the system")
125
+ raise RuntimeError(_("no fetcher is available on the system"))
107
126
 
108
127
 
109
128
  class CurlFetcher(BaseFetcher):
@@ -152,7 +171,12 @@ class CurlFetcher(BaseFetcher):
152
171
  retcode = subprocess.call(argv)
153
172
  if retcode != 0:
154
173
  self._logger.W(
155
- f"failed to fetch distfile: command '{' '.join(argv)}' returned {retcode}"
174
+ _(
175
+ "failed to fetch distfile: command '{cmd}' returned {retcode}"
176
+ ).format(
177
+ cmd=" ".join(argv),
178
+ retcode=retcode,
179
+ )
156
180
  )
157
181
  return False
158
182
 
@@ -190,7 +214,12 @@ class WgetFetcher(BaseFetcher):
190
214
  retcode = subprocess.call(argv)
191
215
  if retcode != 0:
192
216
  self._logger.W(
193
- f"failed to fetch distfile: command '{' '.join(argv)}' returned {retcode}"
217
+ _(
218
+ "failed to fetch distfile: command '{cmd}' returned {retcode}"
219
+ ).format(
220
+ cmd=" ".join(argv),
221
+ retcode=retcode,
222
+ )
194
223
  )
195
224
  return False
196
225
 
ruyi/ruyipkg/install.py CHANGED
@@ -8,6 +8,7 @@ from ruyi.ruyipkg.state import BoundInstallationStateStore
8
8
 
9
9
  from ..cli.user_input import ask_for_yesno_confirmation
10
10
  from ..config import GlobalConfig
11
+ from ..i18n import _
11
12
  from ..telemetry.scope import TelemetryScope
12
13
  from .atom import Atom
13
14
  from .distfile import Distfile
@@ -43,12 +44,16 @@ def do_extract_atoms(
43
44
  a = Atom.parse(a_str)
44
45
  pm = a.match_in_repo(mr, cfg.include_prereleases)
45
46
  if pm is None:
46
- logger.F(f"atom {a_str} matches no package in the repository")
47
+ logger.F(
48
+ _("atom {atom} matches no package in the repository").format(
49
+ atom=a_str,
50
+ )
51
+ )
47
52
  return 1
48
53
 
49
54
  sv = pm.service_level
50
55
  if sv.has_known_issues:
51
- logger.W("package has known issue(s)")
56
+ logger.W(_("package has known issue(s)"))
52
57
  for s in sv.render_known_issues(pm.repo.messages, cfg.lang_code):
53
58
  logger.I(s)
54
59
 
@@ -97,12 +102,20 @@ def _do_extract_pkg(
97
102
  bm = pm.binary_metadata
98
103
  sm = pm.source_metadata
99
104
  if bm is None and sm is None:
100
- logger.F(f"don't know how to extract package [green]{pkg_name}[/]")
105
+ logger.F(
106
+ _("don't know how to extract package [green]{pkg}[/]").format(
107
+ pkg=pkg_name,
108
+ )
109
+ )
101
110
  return 2
102
111
 
103
112
  if bm is not None and sm is not None:
104
113
  logger.F(
105
- f"cannot handle package [green]{pkg_name}[/]: package is both binary and source"
114
+ _(
115
+ "cannot handle package [green]{pkg}[/]: package is both binary and source"
116
+ ).format(
117
+ pkg=pkg_name,
118
+ )
106
119
  )
107
120
  return 2
108
121
 
@@ -114,7 +127,10 @@ def _do_extract_pkg(
114
127
 
115
128
  if not distfiles_for_host:
116
129
  logger.F(
117
- f"package [green]{pkg_name}[/] declares no distfile for host {canonicalized_host}"
130
+ _("package [green]{pkg}[/] declares no distfile for host {host}").format(
131
+ pkg=pkg_name,
132
+ host=canonicalized_host,
133
+ )
118
134
  )
119
135
  return 2
120
136
 
@@ -130,13 +146,21 @@ def _do_extract_pkg(
130
146
  logger.D("skipping extraction because [yellow]--fetch-only[/] is given")
131
147
  continue
132
148
 
133
- logger.I(f"extracting [green]{df_name}[/] for package [green]{pkg_name}[/]")
149
+ logger.I(
150
+ _("extracting [green]{distfile}[/] for package [green]{pkg}[/]").format(
151
+ distfile=df_name,
152
+ pkg=pkg_name,
153
+ )
154
+ )
134
155
  # unpack into destination
135
156
  df.unpack(dest_dir, logger)
136
157
 
137
158
  if not fetch_only:
138
159
  logger.I(
139
- f"package [green]{pkg_name}[/] has been extracted to {dest_dir}",
160
+ _("package [green]{pkg}[/] has been extracted to {dest_dir}").format(
161
+ pkg=pkg_name,
162
+ dest_dir=dest_dir,
163
+ )
140
164
  )
141
165
 
142
166
  return 0
@@ -158,13 +182,15 @@ def do_install_atoms(
158
182
  a = Atom.parse(a_str)
159
183
  pm = a.match_in_repo(mr, config.include_prereleases)
160
184
  if pm is None:
161
- logger.F(f"atom {a_str} matches no package in the repository")
185
+ logger.F(
186
+ _("atom {atom} matches no package in the repository").format(atom=a_str)
187
+ )
162
188
  return 1
163
189
  pkg_name = pm.name_for_installation
164
190
 
165
191
  sv = pm.service_level
166
192
  if sv.has_known_issues:
167
- logger.W("package has known issue(s)")
193
+ logger.W(_("package has known issue(s)"))
168
194
  for s in sv.render_known_issues(pm.repo.messages, config.lang_code):
169
195
  logger.I(s)
170
196
 
@@ -213,7 +239,11 @@ def do_install_atoms(
213
239
  return ret
214
240
  continue
215
241
 
216
- logger.F(f"don't know how to handle non-binary package [green]{pkg_name}[/]")
242
+ logger.F(
243
+ _("don't know how to handle non-binary package [green]{pkg}[/]").format(
244
+ pkg=pkg_name,
245
+ )
246
+ )
217
247
  return 2
218
248
 
219
249
  return 0
@@ -249,11 +279,17 @@ def _do_install_binary_pkg(
249
279
 
250
280
  if is_installed:
251
281
  if not reinstall:
252
- logger.I(f"skipping already installed package [green]{pkg_name}[/]")
282
+ logger.I(
283
+ _("skipping already installed package [green]{pkg}[/]").format(
284
+ pkg=pkg_name,
285
+ )
286
+ )
253
287
  return 0
254
288
 
255
289
  logger.W(
256
- f"package [green]{pkg_name}[/] seems already installed; purging and re-installing due to [yellow]--reinstall[/]"
290
+ _(
291
+ "package [green]{pkg}[/] seems already installed; purging and re-installing due to [yellow]--reinstall[/]"
292
+ ).format(pkg=pkg_name)
257
293
  )
258
294
  # Remove from state tracking before purging
259
295
  rgs.remove_installation(
@@ -290,7 +326,12 @@ def _do_install_binary_pkg(
290
326
  install_path=install_root,
291
327
  )
292
328
 
293
- logger.I(f"package [green]{pkg_name}[/] installed to [yellow]{install_root}[/]")
329
+ logger.I(
330
+ _("package [green]{pkg}[/] installed to [yellow]{install_root}[/]").format(
331
+ pkg=pkg_name,
332
+ install_root=install_root,
333
+ )
334
+ )
294
335
  return 0
295
336
 
296
337
 
@@ -312,7 +353,10 @@ def _do_install_binary_pkg_to(
312
353
  distfiles_for_host = bm.get_distfile_names_for_host(str(canonicalized_host))
313
354
  if not distfiles_for_host:
314
355
  logger.F(
315
- f"package [green]{pkg_name}[/] declares no binary for host {canonicalized_host}"
356
+ _("package [green]{pkg}[/] declares no binary for host {host}").format(
357
+ pkg=pkg_name,
358
+ host=canonicalized_host,
359
+ )
316
360
  )
317
361
  return 2
318
362
 
@@ -323,10 +367,17 @@ def _do_install_binary_pkg_to(
323
367
  df.ensure(logger)
324
368
 
325
369
  if fetch_only:
326
- logger.D("skipping installation because [yellow]--fetch-only[/] is given")
370
+ logger.D(
371
+ _("skipping installation because [yellow]--fetch-only[/] is given")
372
+ )
327
373
  continue
328
374
 
329
- logger.I(f"extracting [green]{df_name}[/] for package [green]{pkg_name}[/]")
375
+ logger.I(
376
+ _("extracting [green]{distfile}[/] for package [green]{pkg}[/]").format(
377
+ distfile=df_name,
378
+ pkg=pkg_name,
379
+ )
380
+ )
330
381
  df.unpack(install_root, logger)
331
382
 
332
383
  return 0
@@ -361,11 +412,17 @@ def _do_install_blob_pkg(
361
412
 
362
413
  if is_installed:
363
414
  if not reinstall:
364
- logger.I(f"skipping already installed package [green]{pkg_name}[/]")
415
+ logger.I(
416
+ _("skipping already installed package [green]{pkg}[/]").format(
417
+ pkg=pkg_name,
418
+ )
419
+ )
365
420
  return 0
366
421
 
367
422
  logger.W(
368
- f"package [green]{pkg_name}[/] seems already installed; purging and re-installing due to [yellow]--reinstall[/]"
423
+ _(
424
+ "package [green]{pkg}[/] seems already installed; purging and re-installing due to [yellow]--reinstall[/]"
425
+ ).format(pkg=pkg_name)
369
426
  )
370
427
  # Remove from state tracking before purging
371
428
  rgs.remove_installation(
@@ -401,7 +458,12 @@ def _do_install_blob_pkg(
401
458
  install_path=install_root,
402
459
  )
403
460
 
404
- logger.I(f"package [green]{pkg_name}[/] installed to [yellow]{install_root}[/]")
461
+ logger.I(
462
+ _("package [green]{pkg}[/] installed to [yellow]{install_root}[/]").format(
463
+ pkg=pkg_name,
464
+ install_root=install_root,
465
+ )
466
+ )
405
467
  return 0
406
468
 
407
469
 
@@ -420,7 +482,9 @@ def _do_install_blob_pkg_to(
420
482
  dfs = pm.distfiles
421
483
  distfile_names = bm.get_distfile_names()
422
484
  if not distfile_names:
423
- logger.F(f"package [green]{pkg_name}[/] declares no blob distfile")
485
+ logger.F(
486
+ _("package [green]{pkg}[/] declares no blob distfile").format(pkg=pkg_name)
487
+ )
424
488
  return 2
425
489
 
426
490
  for df_name in distfile_names:
@@ -430,10 +494,17 @@ def _do_install_blob_pkg_to(
430
494
  df.ensure(logger)
431
495
 
432
496
  if fetch_only:
433
- logger.D("skipping installation because [yellow]--fetch-only[/] is given")
497
+ logger.D(
498
+ _("skipping installation because [yellow]--fetch-only[/] is given")
499
+ )
434
500
  continue
435
501
 
436
- logger.I(f"extracting [green]{df_name}[/] for package [green]{pkg_name}[/]")
502
+ logger.I(
503
+ _("extracting [green]{distfile}[/] for package [green]{pkg}[/]").format(
504
+ distfile=df_name,
505
+ pkg=pkg_name,
506
+ )
507
+ )
437
508
  df.unpack_or_symlink(install_root, logger)
438
509
 
439
510
  return 0
@@ -457,21 +528,31 @@ def do_uninstall_atoms(
457
528
  a = Atom.parse(a_str)
458
529
  pm = a.match_in_repo(bis, config.include_prereleases)
459
530
  if pm is None:
460
- logger.F(f"atom [yellow]{a_str}[/] is non-existent or not installed")
531
+ logger.F(
532
+ _("atom [yellow]{atom}[/] is non-existent or not installed").format(
533
+ atom=a_str,
534
+ )
535
+ )
461
536
  return 1
462
537
  pms_to_uninstall.append((a_str, pm))
463
538
 
464
539
  if not pms_to_uninstall:
465
- logger.I("no packages to uninstall")
540
+ logger.I(_("no packages to uninstall"))
466
541
  return 0
467
542
 
468
- logger.I("the following packages will be uninstalled:")
469
- for _, pm in pms_to_uninstall:
470
- logger.I(f" - [green]{pm.category}/{pm.name}[/] ({pm.ver})")
543
+ logger.I(_("the following packages will be uninstalled:"))
544
+ for _unused, pm in pms_to_uninstall:
545
+ logger.I(
546
+ _(" - [green]{category}/{name}[/] ({version})").format(
547
+ category=pm.category,
548
+ name=pm.name,
549
+ version=pm.ver,
550
+ )
551
+ )
471
552
 
472
553
  if not assume_yes:
473
- if not ask_for_yesno_confirmation(logger, "Proceed?", default=False):
474
- logger.I("uninstallation aborted")
554
+ if not ask_for_yesno_confirmation(logger, _("Proceed?"), default=False):
555
+ logger.I(_("uninstallation aborted"))
475
556
  return 0
476
557
 
477
558
  for a_str, pm in pms_to_uninstall:
@@ -504,7 +585,11 @@ def do_uninstall_atoms(
504
585
  return ret
505
586
  continue
506
587
 
507
- logger.F(f"don't know how to handle non-binary package [green]{pkg_name}[/]")
588
+ logger.F(
589
+ _("don't know how to handle non-binary package [green]{pkg}[/]").format(
590
+ pkg=pkg_name,
591
+ )
592
+ )
508
593
  return 2
509
594
 
510
595
  return 0
@@ -534,21 +619,29 @@ def _do_uninstall_binary_pkg(
534
619
  # Check directory existence if the PM state says the package is not installed
535
620
  if not is_installed:
536
621
  if not os.path.exists(install_root):
537
- logger.I(f"skipping not-installed package [green]{pkg_name}[/]")
622
+ logger.I(
623
+ _("skipping not-installed package [green]{pkg}[/]").format(
624
+ pkg=pkg_name,
625
+ )
626
+ )
538
627
  return 0
539
628
 
540
629
  # There may be potentially user-generated data in the directory,
541
630
  # let's be safe and fail the process.
542
631
  logger.F(
543
- f"package [green]{pkg_name}[/] is not tracked as installed, but its directory [yellow]{install_root}[/] exists."
632
+ _(
633
+ "package [green]{pkg}[/] is not tracked as installed, but its directory [yellow]{install_root}[/] exists."
634
+ ).format(pkg=pkg_name, install_root=install_root)
544
635
  )
545
- logger.I("Please remove it manually if you are sure it's safe to do so.")
636
+ logger.I(_("Please remove it manually if you are sure it's safe to do so."))
546
637
  logger.I(
547
- "If you believe this is a bug, please file an issue at [yellow]https://github.com/ruyisdk/ruyi/issues[/]."
638
+ _(
639
+ "If you believe this is a bug, please file an issue at [yellow]https://github.com/ruyisdk/ruyi/issues[/]."
640
+ )
548
641
  )
549
642
  return 1
550
643
 
551
- logger.I(f"uninstalling package [green]{pkg_name}[/]")
644
+ logger.I(_("uninstalling package [green]{pkg}[/]").format(pkg=pkg_name))
552
645
  if is_installed:
553
646
  rgs.remove_installation(
554
647
  pm.repo_id,
@@ -561,7 +654,7 @@ def _do_uninstall_binary_pkg(
561
654
  if os.path.exists(install_root):
562
655
  shutil.rmtree(install_root)
563
656
 
564
- logger.I(f"package [green]{pkg_name}[/] uninstalled")
657
+ logger.I(_("package [green]{pkg}[/] uninstalled").format(pkg=pkg_name))
565
658
  return 0
566
659
 
567
660
 
@@ -588,21 +681,29 @@ def _do_uninstall_blob_pkg(
588
681
  # Check directory existence if the PM state says the package is not installed
589
682
  if not is_installed:
590
683
  if not os.path.exists(install_root):
591
- logger.I(f"skipping not-installed package [green]{pkg_name}[/]")
684
+ logger.I(
685
+ _("skipping not-installed package [green]{pkg}[/]").format(
686
+ pkg=pkg_name,
687
+ )
688
+ )
592
689
  return 0
593
690
 
594
691
  # There may be potentially user-generated data in the directory,
595
692
  # let's be safe and fail the process.
596
693
  logger.F(
597
- f"package [green]{pkg_name}[/] is not tracked as installed, but its directory [yellow]{install_root}[/] exists."
694
+ _(
695
+ "package [green]{pkg}[/] is not tracked as installed, but its directory [yellow]{install_root}[/] exists."
696
+ ).format(pkg=pkg_name, install_root=install_root)
598
697
  )
599
- logger.I("Please remove it manually if you are sure it's safe to do so.")
698
+ logger.I(_("Please remove it manually if you are sure it's safe to do so."))
600
699
  logger.I(
601
- "If you believe this is a bug, please file an issue at [yellow]https://github.com/ruyisdk/ruyi/issues[/]."
700
+ _(
701
+ "If you believe this is a bug, please file an issue at [yellow]https://github.com/ruyisdk/ruyi/issues[/]."
702
+ )
602
703
  )
603
704
  return 1
604
705
 
605
- logger.I(f"uninstalling package [green]{pkg_name}[/]")
706
+ logger.I(_("uninstalling package [green]{pkg}[/]").format(pkg=pkg_name))
606
707
  if is_installed:
607
708
  rgs.remove_installation(
608
709
  pm.repo_id,
@@ -615,5 +716,5 @@ def _do_uninstall_blob_pkg(
615
716
  if os.path.exists(install_root):
616
717
  shutil.rmtree(install_root)
617
718
 
618
- logger.I(f"package [green]{pkg_name}[/] uninstalled")
719
+ logger.I(_("package [green]{pkg}[/] uninstalled").format(pkg=pkg_name))
619
720
  return 0
@@ -3,6 +3,7 @@ import pathlib
3
3
  from typing import TYPE_CHECKING
4
4
 
5
5
  from ..cli.cmd import RootCommand
6
+ from ..i18n import _
6
7
  from .cli_completion import package_completer_builder
7
8
  from .host import get_native_host
8
9
 
@@ -14,7 +15,7 @@ if TYPE_CHECKING:
14
15
  class ExtractCommand(
15
16
  RootCommand,
16
17
  cmd="extract",
17
- help="Fetch package(s) then extract to current directory",
18
+ help=_("Fetch package(s) then extract to current directory"),
18
19
  ):
19
20
  @classmethod
20
21
  def configure_args(cls, gc: "GlobalConfig", p: "ArgumentParser") -> None:
@@ -22,7 +23,7 @@ class ExtractCommand(
22
23
  "atom",
23
24
  type=str,
24
25
  nargs="+",
25
- help="Specifier (atom) of the package(s) to extract",
26
+ help=_("Specifier (atom) of the package(s) to extract"),
26
27
  )
27
28
  if gc.is_cli_autocomplete:
28
29
  a.completer = package_completer_builder(gc)
@@ -33,24 +34,26 @@ class ExtractCommand(
33
34
  type=str,
34
35
  metavar="DESTDIR",
35
36
  default=".",
36
- help="Destination directory to extract to (default: current directory)",
37
+ help=_("Destination directory to extract to (default: current directory)"),
37
38
  )
38
39
  p.add_argument(
39
40
  "--extract-without-subdir",
40
41
  action="store_true",
41
- help="Extract files directly into DESTDIR instead of package-named subdirectories",
42
+ help=_(
43
+ "Extract files directly into DESTDIR instead of package-named subdirectories"
44
+ ),
42
45
  )
43
46
  p.add_argument(
44
47
  "-f",
45
48
  "--fetch-only",
46
49
  action="store_true",
47
- help="Fetch distribution files only without installing",
50
+ help=_("Fetch distribution files only without installing"),
48
51
  )
49
52
  p.add_argument(
50
53
  "--host",
51
54
  type=str,
52
55
  default=get_native_host(),
53
- help="Override the host architecture (normally not needed)",
56
+ help=_("Override the host architecture (normally not needed)"),
54
57
  )
55
58
 
56
59
  @classmethod
@@ -81,7 +84,7 @@ class InstallCommand(
81
84
  RootCommand,
82
85
  cmd="install",
83
86
  aliases=["i"],
84
- help="Install package from configured repository",
87
+ help=_("Install package from configured repository"),
85
88
  ):
86
89
  @classmethod
87
90
  def configure_args(cls, gc: "GlobalConfig", p: "ArgumentParser") -> None:
@@ -89,7 +92,7 @@ class InstallCommand(
89
92
  "atom",
90
93
  type=str,
91
94
  nargs="+",
92
- help="Specifier (atom) of the package to install",
95
+ help=_("Specifier (atom) of the package to install"),
93
96
  )
94
97
  if gc.is_cli_autocomplete:
95
98
  a.completer = package_completer_builder(gc)
@@ -98,18 +101,18 @@ class InstallCommand(
98
101
  "-f",
99
102
  "--fetch-only",
100
103
  action="store_true",
101
- help="Fetch distribution files only without installing",
104
+ help=_("Fetch distribution files only without installing"),
102
105
  )
103
106
  p.add_argument(
104
107
  "--host",
105
108
  type=str,
106
109
  default=get_native_host(),
107
- help="Override the host architecture (normally not needed)",
110
+ help=_("Override the host architecture (normally not needed)"),
108
111
  )
109
112
  p.add_argument(
110
113
  "--reinstall",
111
114
  action="store_true",
112
- help="Force re-installation of already installed packages",
115
+ help=_("Force re-installation of already installed packages"),
113
116
  )
114
117
 
115
118
  @classmethod
@@ -136,7 +139,7 @@ class UninstallCommand(
136
139
  RootCommand,
137
140
  cmd="uninstall",
138
141
  aliases=["remove", "rm"],
139
- help="Uninstall installed packages",
142
+ help=_("Uninstall installed packages"),
140
143
  ):
141
144
  @classmethod
142
145
  def configure_args(cls, gc: "GlobalConfig", p: argparse.ArgumentParser) -> None:
@@ -144,20 +147,20 @@ class UninstallCommand(
144
147
  "atom",
145
148
  type=str,
146
149
  nargs="+",
147
- help="Specifier (atom) of the package to uninstall",
150
+ help=_("Specifier (atom) of the package to uninstall"),
148
151
  )
149
152
  p.add_argument(
150
153
  "--host",
151
154
  type=str,
152
155
  default=get_native_host(),
153
- help="Override the host architecture (normally not needed)",
156
+ help=_("Override the host architecture (normally not needed)"),
154
157
  )
155
158
  p.add_argument(
156
159
  "-y",
157
160
  "--yes",
158
161
  action="store_true",
159
162
  dest="assume_yes",
160
- help="Assume yes to all prompts",
163
+ help=_("Assume yes to all prompts"),
161
164
  )
162
165
 
163
166
  @classmethod