Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions archinstall/lib/translationhandler.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,15 @@ def tr(message: str) -> str:
return str(_DeferredTranslation(message))


def tr_noop(message: str) -> str:
"""Mark a string for xgettext extraction without translating it here.

Use for strings that are translated later from a variable, e.g.
binding descriptions passed through tr() at runtime.
"""
return message


builtins._ = _DeferredTranslation # type: ignore[attr-defined]


Expand Down
190 changes: 190 additions & 0 deletions archinstall/locales/base.pot
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ msgstr ""
msgid "Install to removable location"
msgstr ""

msgid "Plymouth"
msgstr ""

msgid "Will install to /EFI/BOOT/ (removable location, safe default)"
msgstr ""

Expand Down Expand Up @@ -248,6 +251,9 @@ msgstr ""
msgid "UEFI is not detected and some options are disabled"
msgstr ""

msgid "Select Plymouth theme"
msgstr ""

msgid "The specified configuration will be applied"
msgstr ""

Expand Down Expand Up @@ -882,6 +888,10 @@ msgstr ""
msgid "Removable"
msgstr ""

#, python-brace-format
msgid "Plymouth \"{}\""
msgstr ""

msgid "Use a best-effort default partition layout"
msgstr ""

Expand Down Expand Up @@ -1196,12 +1206,192 @@ msgstr ""
msgid "Starting device modifications in "
msgstr ""

msgid "Bottom"
msgstr ""

msgid "Copy selected text"
msgstr ""

msgid "Cursor down"
msgstr ""

msgid "Cursor left"
msgstr ""

msgid "Cursor right"
msgstr ""

msgid "Cursor up"
msgstr ""

msgid "Cut selected text"
msgstr ""

msgid "Delete all to the left"
msgstr ""

msgid "Delete all to the right"
msgstr ""

msgid "Delete character left"
msgstr ""

msgid "Delete character right"
msgstr ""

msgid "Delete left to start of word"
msgstr ""

msgid "Delete right to start of word"
msgstr ""

msgid "Down"
msgstr ""

msgid "End"
msgstr ""

msgid "First"
msgstr ""

msgid "Focus Next"
msgstr ""

msgid "Focus Previous"
msgstr ""

msgid "Go to end"
msgstr ""

msgid "Go to start"
msgstr ""

msgid "Home"
msgstr ""

msgid "Last"
msgstr ""

msgid "Move cursor left"
msgstr ""

msgid "Move cursor left a word"
msgstr ""

msgid "Move cursor left a word and select"
msgstr ""

msgid "Move cursor left and select"
msgstr ""

msgid "Move cursor right a word"
msgstr ""

msgid "Move cursor right a word and select"
msgstr ""

msgid "Move cursor right and select"
msgstr ""

msgid "Move cursor right or accept the completion suggestion"
msgstr ""

msgid "Page Down"
msgstr ""

msgid "Page Left"
msgstr ""

msgid "Page Right"
msgstr ""

msgid "Page Up"
msgstr ""

msgid "Page down"
msgstr ""

msgid "Page up"
msgstr ""

msgid "Paste text from the clipboard"
msgstr ""

msgid "Press button"
msgstr ""

msgid "Quit"
msgstr ""

msgid "Scroll Down"
msgstr ""

msgid "Scroll End"
msgstr ""

msgid "Scroll Home"
msgstr ""

msgid "Scroll Left"
msgstr ""

msgid "Scroll Right"
msgstr ""

msgid "Scroll Up"
msgstr ""

msgid "Select"
msgstr ""

msgid "Select all"
msgstr ""

msgid "Select line end"
msgstr ""

msgid "Select line start"
msgstr ""

msgid "Submit"
msgstr ""

msgid "Toggle option"
msgstr ""

msgid "Top"
msgstr ""

msgid "Up"
msgstr ""

msgid "Reset"
msgstr ""

msgid "Search"
msgstr ""

msgid "Toggle"
msgstr ""

msgid "Confirm"
msgstr ""

msgid "Focus right"
msgstr ""

msgid "Focus left"
msgstr ""

msgid "Ok"
msgstr ""

msgid "Input cannot be empty"
msgstr ""

msgid "Show/Hide help"
msgstr ""

msgid "Yes"
msgstr ""

Expand Down
8 changes: 7 additions & 1 deletion archinstall/locales/locales_generator.sh
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,14 @@ usage() {
}

generate_pot() {
# tr - regular translation calls
# tr_noop - extraction-only marker for strings translated later from a variable
# Binding:3 - the description argument of textual Binding() definitions,
# translated at runtime by _translate_bindings(). The description
# must be passed positionally - xgettext cannot see keyword arguments.
find . -type f -iname '*.py' | sort \
| xargs xgettext --no-location --omit-header --keyword='tr' \
| xargs xgettext --no-location --omit-header \
--keyword='tr' --keyword='tr_noop' --keyword='Binding:3' \
-d base -o locales/base.pot
}

Expand Down
77 changes: 77 additions & 0 deletions archinstall/tui/binding_descriptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""Textual's built-in key binding descriptions, listed for xgettext.

These strings live inside the textual package, so xgettext cannot find them
when scanning this code base. At runtime _translate_bindings() in
components.py translates every binding description with tr(), including the
ones inherited from textual widgets - this module only makes those strings
visible to the extraction in locales_generator.sh (via the tr_noop keyword).

The list covers the MRO-merged bindings of the textual classes used in
components.py: _translate_bindings() operates on the merged bindings map, so
descriptions inherited from ancestors (e.g. Scroll Up from ScrollView) are
translated at runtime too and must be listed here.

Verify or regenerate the list after a textual upgrade or after introducing
a new textual widget in components.py:

python3 test_tooling/check_binding_descriptions.py
"""

from archinstall.lib.translationhandler import tr_noop

# textual 8.2.7
TEXTUAL_BINDING_DESCRIPTIONS: tuple[str, ...] = (
tr_noop('Bottom'),
tr_noop('Copy selected text'),
tr_noop('Cursor down'),
tr_noop('Cursor left'),
tr_noop('Cursor right'),
tr_noop('Cursor up'),
tr_noop('Cut selected text'),
tr_noop('Delete all to the left'),
tr_noop('Delete all to the right'),
tr_noop('Delete character left'),
tr_noop('Delete character right'),
tr_noop('Delete left to start of word'),
tr_noop('Delete right to start of word'),
tr_noop('Down'),
tr_noop('End'),
tr_noop('First'),
tr_noop('Focus Next'),
tr_noop('Focus Previous'),
tr_noop('Go to end'),
tr_noop('Go to start'),
tr_noop('Home'),
tr_noop('Last'),
tr_noop('Move cursor left'),
tr_noop('Move cursor left a word'),
tr_noop('Move cursor left a word and select'),
tr_noop('Move cursor left and select'),
tr_noop('Move cursor right a word'),
tr_noop('Move cursor right a word and select'),
tr_noop('Move cursor right and select'),
tr_noop('Move cursor right or accept the completion suggestion'),
tr_noop('Page Down'),
tr_noop('Page Left'),
tr_noop('Page Right'),
tr_noop('Page Up'),
tr_noop('Page down'),
tr_noop('Page up'),
tr_noop('Paste text from the clipboard'),
tr_noop('Press button'),
tr_noop('Quit'),
tr_noop('Scroll Down'),
tr_noop('Scroll End'),
tr_noop('Scroll Home'),
tr_noop('Scroll Left'),
tr_noop('Scroll Right'),
tr_noop('Scroll Up'),
tr_noop('Select'),
tr_noop('Select all'),
tr_noop('Select line end'),
tr_noop('Select line start'),
tr_noop('Submit'),
tr_noop('Toggle option'),
tr_noop('Top'),
tr_noop('Up'),
)
23 changes: 18 additions & 5 deletions archinstall/tui/components.py
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,19 @@ def action_pop_screen(self) -> None:
_ = self.dismiss()


class _Input(Input):
@override
def on_mount(self) -> None:
_translate_bindings(self._merged_bindings, self._bindings)


class _Button(Button):
# no @override: Button has no on_mount in its MRO,
# textual dispatches the handler by naming convention
def on_mount(self) -> None:
_translate_bindings(self._merged_bindings, self._bindings)


class _OptionList(OptionList):
BINDINGS: ClassVar = [
Binding('down', 'cursor_down', 'Down', show=True),
Expand Down Expand Up @@ -309,7 +322,7 @@ def compose(self) -> ComposeResult:
yield ScrollableContainer(preview_label)

if self._filter:
yield Input(placeholder='/filter', id='filter-input')
yield _Input(placeholder='/filter', id='filter-input')

yield Footer()

Expand Down Expand Up @@ -540,7 +553,7 @@ def compose(self) -> ComposeResult:
yield ScrollableContainer(preview_label)

if self._filter:
yield Input(placeholder='/filter', id='filter-input')
yield _Input(placeholder='/filter', id='filter-input')

yield Footer()

Expand Down Expand Up @@ -702,12 +715,12 @@ def compose(self) -> ComposeResult:
with Vertical(classes='content-container'):
with Horizontal(classes='buttons-container'):
for item in self._group.items:
yield Button(item.text, id=item.key)
yield _Button(item.text, id=item.key)
else:
with Vertical():
with Horizontal(classes='buttons-container'):
for item in self._group.items:
yield Button(item.text, id=item.key)
yield _Button(item.text, id=item.key)

yield Rule(orientation='horizontal')
if self._preview_header is not None:
Expand Down Expand Up @@ -848,7 +861,7 @@ def compose(self) -> ComposeResult:

with Center(classes='container-wrapper'):
with Vertical(classes='input-content'):
yield Input(
yield _Input(
placeholder=self._placeholder,
password=self._password,
value=self._default_value,
Expand Down
Loading
Loading