Skip to content

Commit 9a2d546

Browse files
authored
Add translation support for TUI help groups and binding descriptions (#4363)
* Add translation support for TUI help groups and binding descriptions Help group names shown via F1 (General, Navigation, Selection, Search) and key binding descriptions in the Textual footer (Down, Up, Cancel, Confirm, etc.) were hardcoded in English and never went through the translation system. * ruff_format_check and mypy fixes * Refactor _translate_bindings to accept BindingsMap instead of Any Add TApp.translate_bindings() to avoid exporting private functions across modules. * Revert deprecated curses help.py change * Move TApp import to module level in global_menu * Change translate_bindings from staticmethod to member method
1 parent d6de03a commit 9a2d546

5 files changed

Lines changed: 275 additions & 2 deletions

File tree

archinstall/lib/global_menu.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from archinstall.lib.packages.packages import list_available_packages, select_additional_packages
2929
from archinstall.lib.pacman.config import PacmanConfig
3030
from archinstall.lib.translationhandler import Language, tr, translation_handler
31+
from archinstall.tui.ui.components import tui
3132
from archinstall.tui.ui.menu_item import MenuItem, MenuItemGroup
3233

3334

@@ -275,6 +276,8 @@ def _update_lang_text(self) -> None:
275276
if o.key is not None:
276277
self._item_group.find_by_key(o.key).text = o.text
277278

279+
tui.translate_bindings()
280+
278281
async def _locale_selection(self, preset: LocaleConfiguration) -> LocaleConfiguration | None:
279282
locale_config = await LocaleMenu(preset).show()
280283
return locale_config

archinstall/locales/base.pot

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,123 @@ msgstr ""
17091709
msgid "Exit search mode"
17101710
msgstr ""
17111711

1712+
msgid "General"
1713+
msgstr ""
1714+
1715+
msgid "Navigation"
1716+
msgstr ""
1717+
1718+
msgid "Selection"
1719+
msgstr ""
1720+
1721+
msgid "Search"
1722+
msgstr ""
1723+
1724+
msgid "Down"
1725+
msgstr ""
1726+
1727+
msgid "Up"
1728+
msgstr ""
1729+
1730+
msgid "Confirm"
1731+
msgstr ""
1732+
1733+
msgid "Focus right"
1734+
msgstr ""
1735+
1736+
msgid "Focus left"
1737+
msgstr ""
1738+
1739+
msgid "Toggle"
1740+
msgstr ""
1741+
1742+
msgid "Show/Hide help"
1743+
msgstr ""
1744+
1745+
msgid "Quit"
1746+
msgstr ""
1747+
1748+
msgid "First"
1749+
msgstr ""
1750+
1751+
msgid "Last"
1752+
msgstr ""
1753+
1754+
msgid "Select"
1755+
msgstr ""
1756+
1757+
msgid "Page Up"
1758+
msgstr ""
1759+
1760+
msgid "Page Down"
1761+
msgstr ""
1762+
1763+
msgid "Page up"
1764+
msgstr ""
1765+
1766+
msgid "Page down"
1767+
msgstr ""
1768+
1769+
msgid "Page Left"
1770+
msgstr ""
1771+
1772+
msgid "Page Right"
1773+
msgstr ""
1774+
1775+
msgid "Cursor up"
1776+
msgstr ""
1777+
1778+
msgid "Cursor down"
1779+
msgstr ""
1780+
1781+
msgid "Cursor right"
1782+
msgstr ""
1783+
1784+
msgid "Cursor left"
1785+
msgstr ""
1786+
1787+
msgid "Top"
1788+
msgstr ""
1789+
1790+
msgid "Bottom"
1791+
msgstr ""
1792+
1793+
msgid "Home"
1794+
msgstr ""
1795+
1796+
msgid "End"
1797+
msgstr ""
1798+
1799+
msgid "Toggle option"
1800+
msgstr ""
1801+
1802+
msgid "Scroll Up"
1803+
msgstr ""
1804+
1805+
msgid "Scroll Down"
1806+
msgstr ""
1807+
1808+
msgid "Scroll Left"
1809+
msgstr ""
1810+
1811+
msgid "Scroll Right"
1812+
msgstr ""
1813+
1814+
msgid "Scroll Home"
1815+
msgstr ""
1816+
1817+
msgid "Scroll End"
1818+
msgstr ""
1819+
1820+
msgid "Focus Next"
1821+
msgstr ""
1822+
1823+
msgid "Focus Previous"
1824+
msgstr ""
1825+
1826+
msgid "Copy selected text"
1827+
msgstr ""
1828+
17121829
msgid ""
17131830
"labwc needs access to your seat (collection of hardware devices i.e. "
17141831
"keyboard, mouse, etc)"
2.1 KB
Binary file not shown.

archinstall/locales/uk/LC_MESSAGES/base.po

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1663,6 +1663,123 @@ msgstr "Запустити режим пошуку"
16631663
msgid "Exit search mode"
16641664
msgstr "Вийти з режиму пошуку"
16651665

1666+
msgid "General"
1667+
msgstr "Загальне"
1668+
1669+
msgid "Navigation"
1670+
msgstr "Навігація"
1671+
1672+
msgid "Selection"
1673+
msgstr "Вибір"
1674+
1675+
msgid "Search"
1676+
msgstr "Пошук"
1677+
1678+
msgid "Down"
1679+
msgstr "Вниз"
1680+
1681+
msgid "Up"
1682+
msgstr "Вгору"
1683+
1684+
msgid "Confirm"
1685+
msgstr "Підтвердити"
1686+
1687+
msgid "Focus right"
1688+
msgstr "Фокус вправо"
1689+
1690+
msgid "Focus left"
1691+
msgstr "Фокус вліво"
1692+
1693+
msgid "Toggle"
1694+
msgstr "Перемкнути"
1695+
1696+
msgid "Show/Hide help"
1697+
msgstr "Показати/Сховати довідку"
1698+
1699+
msgid "Quit"
1700+
msgstr "Вийти"
1701+
1702+
msgid "First"
1703+
msgstr "На початок"
1704+
1705+
msgid "Last"
1706+
msgstr "В кінець"
1707+
1708+
msgid "Select"
1709+
msgstr "Обрати"
1710+
1711+
msgid "Page Up"
1712+
msgstr "Сторінка вгору"
1713+
1714+
msgid "Page Down"
1715+
msgstr "Сторінка вниз"
1716+
1717+
msgid "Page up"
1718+
msgstr "Сторінка вгору"
1719+
1720+
msgid "Page down"
1721+
msgstr "Сторінка вниз"
1722+
1723+
msgid "Page Left"
1724+
msgstr "Сторінка вліво"
1725+
1726+
msgid "Page Right"
1727+
msgstr "Сторінка вправо"
1728+
1729+
msgid "Cursor up"
1730+
msgstr "Курсор вгору"
1731+
1732+
msgid "Cursor down"
1733+
msgstr "Курсор вниз"
1734+
1735+
msgid "Cursor right"
1736+
msgstr "Курсор вправо"
1737+
1738+
msgid "Cursor left"
1739+
msgstr "Курсор вліво"
1740+
1741+
msgid "Top"
1742+
msgstr "На початок"
1743+
1744+
msgid "Bottom"
1745+
msgstr "В кінець"
1746+
1747+
msgid "Home"
1748+
msgstr "Початок"
1749+
1750+
msgid "End"
1751+
msgstr "Кінець"
1752+
1753+
msgid "Toggle option"
1754+
msgstr "Перемкнути опцію"
1755+
1756+
msgid "Scroll Up"
1757+
msgstr "Прокрутка вгору"
1758+
1759+
msgid "Scroll Down"
1760+
msgstr "Прокрутка вниз"
1761+
1762+
msgid "Scroll Left"
1763+
msgstr "Прокрутка вліво"
1764+
1765+
msgid "Scroll Right"
1766+
msgstr "Прокрутка вправо"
1767+
1768+
msgid "Scroll Home"
1769+
msgstr "Прокрутка на початок"
1770+
1771+
msgid "Scroll End"
1772+
msgstr "Прокрутка в кінець"
1773+
1774+
msgid "Focus Next"
1775+
msgstr "Фокус на наступний"
1776+
1777+
msgid "Focus Previous"
1778+
msgstr "Фокус на попередній"
1779+
1780+
msgid "Copy selected text"
1781+
msgstr "Копіювати виділений текст"
1782+
16661783
msgid "labwc needs access to your seat (collection of hardware devices i.e. keyboard, mouse, etc)"
16671784
msgstr "labwc потребує доступ до вашого місця (набору апаратних пристроїв, таких як клавіатура, миша тощо)"
16681785

archinstall/tui/ui/components.py

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
import sys
22
from abc import ABC, abstractmethod
33
from collections.abc import Awaitable, Callable
4-
from dataclasses import dataclass
4+
from dataclasses import dataclass, replace
55
from enum import Enum, auto
66
from typing import Any, ClassVar, Literal, TypeVar, cast, override
77

88
from textual import work
99
from textual.app import App, ComposeResult
10-
from textual.binding import Binding
10+
from textual.binding import Binding, BindingsMap
1111
from textual.containers import Center, Horizontal, ScrollableContainer, Vertical
1212
from textual.events import Key
1313
from textual.geometry import Offset
@@ -27,6 +27,18 @@
2727
ValueT = TypeVar('ValueT')
2828

2929

30+
def _translate_bindings(source: BindingsMap | None, target: BindingsMap) -> None:
31+
"""Translate binding descriptions from source to target.
32+
33+
Uses source (original, immutable class-level cache) to avoid
34+
double-translation on repeated calls (e.g. language switch).
35+
"""
36+
if source is None:
37+
return
38+
for key, bindings in source.key_to_bindings.items():
39+
target.key_to_bindings[key] = [replace(b, description=tr(b.description)) if b.description else b for b in bindings]
40+
41+
3042
class BaseScreen(Screen[Result[ValueT]]):
3143
BINDINGS: ClassVar = [
3244
Binding('escape', 'cancel_operation', 'Cancel', show=True),
@@ -97,6 +109,7 @@ def compose(self) -> ComposeResult:
97109
yield Footer()
98110

99111
def on_mount(self) -> None:
112+
_translate_bindings(self._merged_bindings, self._bindings)
100113
if self._data_callback:
101114
self._exec_callback()
102115
else:
@@ -129,6 +142,10 @@ class _OptionList(OptionList):
129142
Binding('k', 'cursor_up', 'Up', show=False),
130143
]
131144

145+
@override
146+
def on_mount(self) -> None:
147+
_translate_bindings(self._merged_bindings, self._bindings)
148+
132149

133150
class OptionListScreen(BaseScreen[ValueT]):
134151
"""
@@ -271,6 +288,7 @@ def compose(self) -> ComposeResult:
271288
yield Footer()
272289

273290
def on_mount(self) -> None:
291+
_translate_bindings(self._merged_bindings, self._bindings)
274292
self._update_options(self._options)
275293
self.query_one(OptionList).focus()
276294

@@ -356,6 +374,10 @@ class _SelectionList(SelectionList[ValueT]):
356374
Binding('space', 'select', 'Toggle', show=True),
357375
]
358376

377+
@override
378+
def on_mount(self) -> None:
379+
_translate_bindings(self._merged_bindings, self._bindings)
380+
359381

360382
class SelectListScreen(BaseScreen[ValueT]):
361383
"""
@@ -500,6 +522,7 @@ def on_input_submitted(self, event: Input.Submitted) -> None:
500522
self._handle_search_action()
501523

502524
def on_mount(self) -> None:
525+
_translate_bindings(self._merged_bindings, self._bindings)
503526
self._update_options(self._options)
504527
self.query_one(SelectionList).focus()
505528

@@ -670,6 +693,7 @@ def compose(self) -> ComposeResult:
670693
yield Footer()
671694

672695
def on_mount(self) -> None:
696+
_translate_bindings(self._merged_bindings, self._bindings)
673697
self._update_selection()
674698

675699
def action_focus_right(self) -> None:
@@ -825,6 +849,7 @@ def compose(self) -> ComposeResult:
825849
yield Footer()
826850

827851
def on_mount(self) -> None:
852+
_translate_bindings(self._merged_bindings, self._bindings)
828853
input_field = self.query_one('#main_input', Input)
829854
input_field.focus()
830855

@@ -872,6 +897,10 @@ class _DataTable(DataTable[ValueT]):
872897
Binding('enter', 'select_cursor', 'Confirm', show=True),
873898
]
874899

900+
@override
901+
def on_mount(self) -> None:
902+
_translate_bindings(self._merged_bindings, self._bindings)
903+
875904

876905
class TableSelectionScreen(BaseScreen[ValueT]):
877906
BINDINGS: ClassVar = [
@@ -992,6 +1021,7 @@ def compose(self) -> ComposeResult:
9921021
yield Footer()
9931022

9941023
def on_mount(self) -> None:
1024+
_translate_bindings(self._merged_bindings, self._bindings)
9951025
self._display_header(True)
9961026
data_table = self.query_one(DataTable)
9971027
data_table.cell_padding = 2
@@ -1245,6 +1275,7 @@ def action_trigger_help(self) -> None:
12451275
_ = self.screen.mount(HelpPanel())
12461276

12471277
def on_mount(self) -> None:
1278+
_translate_bindings(self._merged_bindings, self._bindings)
12481279
self._run_worker()
12491280

12501281
@work
@@ -1291,5 +1322,10 @@ def exit(self, result: Any) -> None:
12911322
assert TApp.app
12921323
TApp.app.exit(result)
12931324

1325+
def translate_bindings(self) -> None:
1326+
"""Re-translate app-level binding descriptions after language change."""
1327+
if TApp.app is not None:
1328+
_translate_bindings(TApp.app._merged_bindings, TApp.app._bindings)
1329+
12941330

12951331
tui = TApp()

0 commit comments

Comments
 (0)