This commit is contained in:
Softer 2026-07-14 10:10:14 +00:00 committed by GitHub
commit bc28db9c47
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 217 additions and 56 deletions

View File

@ -8,11 +8,15 @@ from archinstall.lib.bootloader.bootloader_menu import BootloaderMenu
from archinstall.lib.bootloader.utils import validate_bootloader_layout
from archinstall.lib.configuration import save_config
from archinstall.lib.disk.disk_menu import DiskLayoutConfigurationMenu
from archinstall.lib.exceptions import SysCallError
from archinstall.lib.general.general_menu import select_hostname, select_ntp, select_timezone
from archinstall.lib.general.system_menu import select_kernel, select_swap
from archinstall.lib.hardware import SysInfo
from archinstall.lib.locale import list_timezones
from archinstall.lib.locale.locale_menu import LocaleMenu
from archinstall.lib.log import debug
from archinstall.lib.menu.abstract_menu import AbstractMenu, SpecialMenuKey
from archinstall.lib.menu.helpers import Confirmation
from archinstall.lib.mirror.mirror_handler import MirrorListHandler
from archinstall.lib.mirror.mirror_menu import MirrorMenu
from archinstall.lib.models.application import ApplicationConfiguration, ZramConfiguration
@ -30,10 +34,11 @@ from archinstall.lib.network.network_menu import select_network
from archinstall.lib.packages.packages import list_available_packages, select_additional_packages
from archinstall.lib.pacman.config import PacmanConfig
from archinstall.lib.pacman.pacman_menu import PacmanMenu
from archinstall.lib.translationhandler import Language, tr, translation_handler
from archinstall.lib.translationhandler import DEFAULT_TIMEZONE, Language, tr, translation_handler
from archinstall.lib.utils.format import as_table
from archinstall.tui.components import tui
from archinstall.tui.menu_item import MenuItem, MenuItemGroup, MsgLevelType, PreviewResult
from archinstall.tui.result import ResultType
class GlobalMenu(AbstractMenu[None]):
@ -160,7 +165,7 @@ class GlobalMenu(AbstractMenu[None]):
MenuItem(
text=tr('Timezone'),
action=select_timezone,
value='UTC',
value=DEFAULT_TIMEZONE,
preview_action=self._prev_tz,
key='timezone',
),
@ -254,8 +259,80 @@ class GlobalMenu(AbstractMenu[None]):
self._update_lang_text()
await self._maybe_apply_language_to_locale(language)
return language
async def _maybe_apply_language_to_locale(self, language: Language) -> None:
"""Offer to mirror the selected archinstall language into the target system locale.
Triggered only when the language has a sys_lang mapping, since otherwise
there is no target locale to offer. Console font and timezone rows are
added to the prompt only when their language-derived target value differs
from the current setting, so re-picking a language with fewer mappings
(for example switching from Ukrainian to German, which has no console_font
of its own) resets the stale Ukrainian font alongside the new locale.
"""
if not language.sys_lang:
return
locale_item = self._item_group.find_by_key('locale_config')
locale_config: LocaleConfiguration | None = locale_item.value
if not locale_config:
return
tz_item = self._item_group.find_by_key('timezone')
current_tz: str = tz_item.value or DEFAULT_TIMEZONE
target_tz = language.target_timezone
offer_tz = self._is_timezone_offerable(target_tz, current_tz)
diff = locale_config.language_diff(language)
if diff.is_empty() and not offer_tz:
return
rows = diff.labeled_rows()
if offer_tz:
rows.append((tr('Timezone'), target_tz))
if not await self._confirm_locale_apply(rows):
return
locale_config.apply_language_diff(diff)
if offer_tz:
tz_item.value = target_tz
def _is_timezone_offerable(self, target_tz: str, current_tz: str) -> bool:
"""Return True when the candidate differs from the current and exists in tzdata.
The same source the timezone menu reads from, so we never offer a value
the user could not have selected manually. UTC is always present, so this
is effectively a no-op for the reset-to-default case.
"""
if target_tz == current_tz:
return False
try:
return target_tz in list_timezones()
except SysCallError as err:
debug(f'Failed to validate target timezone {target_tz}: {err}')
return False
async def _confirm_locale_apply(self, rows: list[tuple[str, str]]) -> bool:
"""Render and show the confirmation dialog for the locale changes."""
label_w = max(len(label) for label, _ in rows)
data_lines = [f' {label.ljust(label_w)} : {value}' for label, value in rows]
question = tr('Use this language as the target system language as well?')
header = tr('The following settings will be applied:')
# The TUI centers every line of the prompt independently, so pad all
# lines to a common width; otherwise the colon column drifts.
width = max(len(question), len(header), *(len(line) for line in data_lines))
separator = '=' * width
prompt = question.ljust(width) + '\n\n' + header.ljust(width) + '\n' + separator + '\n' + '\n'.join(line.ljust(width) for line in data_lines) + '\n'
result = await Confirmation(header=prompt, preset=True).show()
return result.type_ == ResultType.Selection and result.item() == MenuItem.yes()
def _prev_archinstall_language(self, item: MenuItem) -> str | None:
if not item.value:
return None

View File

@ -3,7 +3,36 @@ from typing import Any, Self, override
from archinstall.lib.locale.utils import get_kb_layout
from archinstall.lib.models.config import SubConfig
from archinstall.lib.translationhandler import tr
from archinstall.lib.translationhandler import DEFAULT_CONSOLE_FONT, Language, tr
@dataclass
class LocaleLanguageDiff:
"""Locale fields to write when applying a Language to a LocaleConfiguration.
Each field carries the new value, or None when no change is needed. sys_enc
is paired with sys_lang so the encoding row is shown alongside the locale
row in the confirmation dialog, even when the encoding portion itself does
not change.
"""
sys_lang: str | None = None
sys_enc: str | None = None
console_font: str | None = None
def is_empty(self) -> bool:
return self.sys_lang is None and self.sys_enc is None and self.console_font is None
def labeled_rows(self) -> list[tuple[str, str]]:
"""Return [(label, value)] for fields that would change."""
rows: list[tuple[str, str]] = []
if self.sys_lang is not None:
rows.append((tr('Locale language'), self.sys_lang))
if self.sys_enc is not None:
rows.append((tr('Locale encoding'), self.sys_enc))
if self.console_font is not None:
rows.append((tr('Console font'), self.console_font))
return rows
@dataclass
@ -15,7 +44,7 @@ class LocaleConfiguration(SubConfig):
# can be checked using
# zgrep "CONFIG_FONT" /proc/config.gz
# https://wiki.archlinux.org/title/Linux_console#Font
console_font: str = 'default8x16'
console_font: str = DEFAULT_CONSOLE_FONT
@classmethod
def default(cls) -> Self:
@ -49,6 +78,36 @@ class LocaleConfiguration(SubConfig):
output += '{}: {}'.format(tr('Console font'), self.console_font)
return output
def language_diff(self, language: Language) -> LocaleLanguageDiff:
"""Compute the locale fields that would change if applying this language.
Returns an empty diff for languages without a sys_lang mapping. console_font
is offered when the language-derived target value differs - so re-picking
a language with fewer mappings still resets stale fonts left over from a
previous pick.
"""
diff = LocaleLanguageDiff()
if not language.sys_lang:
return diff
if self.sys_lang != language.sys_lang:
diff.sys_lang = language.sys_lang
diff.sys_enc = language.target_sys_enc or self.sys_enc
target_font = language.target_console_font
if self.console_font != target_font:
diff.console_font = target_font
return diff
def apply_language_diff(self, diff: LocaleLanguageDiff) -> None:
if diff.sys_lang is not None:
self.sys_lang = diff.sys_lang
if diff.sys_enc is not None:
self.sys_enc = diff.sys_enc
if diff.console_font is not None:
self.console_font = diff.console_font
def _load_config(self, args: dict[str, str]) -> None:
if 'sys_lang' in args:
self.sys_lang = args['sys_lang']

View File

@ -21,12 +21,31 @@ class Language:
translation_percent: int
translated_lang: str | None
console_font: str | None = None
sys_lang: str | None = None
default_timezone: str | None = None
@property
def display_name(self) -> str:
name = self.name_en
return f'{name} ({self.translation_percent}%)'
@property
def target_sys_enc(self) -> str | None:
"""Encoding portion of sys_lang (e.g. 'UTF-8' from 'uk_UA.UTF-8'). None when sys_lang has no '.'."""
if self.sys_lang and '.' in self.sys_lang:
return self.sys_lang.split('.', 1)[1]
return None
@property
def target_console_font(self) -> str:
"""Console font implied by this language; falls back to the system default."""
return self.console_font or DEFAULT_CONSOLE_FONT
@property
def target_timezone(self) -> str:
"""Timezone implied by this language; falls back to UTC."""
return self.default_timezone or DEFAULT_TIMEZONE
def is_match(self, lang_or_translated_lang: str) -> bool:
if self.name_en == lang_or_translated_lang:
return True
@ -38,7 +57,8 @@ class Language:
return self.name_en
_DEFAULT_FONT = 'default8x16'
DEFAULT_CONSOLE_FONT = 'default8x16'
DEFAULT_TIMEZONE = 'UTC'
_ENV_FONT = os.environ.get('FONT')
@ -69,7 +89,7 @@ class TranslationHandler:
if not running_from_iso():
return False
target = font_name or _DEFAULT_FONT
target = font_name or DEFAULT_CONSOLE_FONT
try:
SysCommand(['setfont', target])
return True
@ -132,6 +152,8 @@ class TranslationHandler:
lang = mapping_entry['lang']
translated_lang = mapping_entry.get('translated_lang', None)
console_font = mapping_entry.get('console_font', None)
sys_lang = mapping_entry.get('sys_lang', None)
default_timezone = mapping_entry.get('default_timezone', None)
try:
# get a translation for a specific language
@ -146,7 +168,7 @@ class TranslationHandler:
# prevent cases where the .pot file is out of date and the percentage is above 100
percent = min(100, percent)
language = Language(abbr, lang, translation, percent, translated_lang, console_font)
language = Language(abbr, lang, translation, percent, translated_lang, console_font, sys_lang, default_timezone)
languages.append(language)
except FileNotFoundError as err:
raise FileNotFoundError(f"Could not locate language file for '{lang}': {err}")

View File

@ -629,6 +629,12 @@ msgid ""
"greeter"
msgstr ""
msgid "Use this language as the target system language as well?"
msgstr ""
msgid "The following settings will be applied:"
msgstr ""
msgid "Language"
msgstr ""

View File

@ -3,7 +3,7 @@
{"abbr": "af", "lang": "Afrikaans"},
{"abbr": "ak", "lang": "Akan"},
{"abbr": "am", "lang": "Amharic"},
{"abbr": "ar", "lang": "Arabic"},
{"abbr": "ar", "lang": "Arabic", "sys_lang": "ar_SA.UTF-8", "default_timezone": "Asia/Riyadh"},
{"abbr": "an", "lang": "Aragonese"},
{"abbr": "as", "lang": "Assamese"},
{"abbr": "av", "lang": "Avaric"},
@ -19,8 +19,8 @@
{"abbr": "bs", "lang": "Bosnian"},
{"abbr": "br", "lang": "Breton"},
{"abbr": "bg", "lang": "Bulgarian"},
{"abbr": "ca", "lang": "Catalan"},
{"abbr": "cs", "lang": "Czech", "translated_lang": "čeština"},
{"abbr": "ca", "lang": "Catalan", "sys_lang": "ca_ES.UTF-8"},
{"abbr": "cs", "lang": "Czech", "translated_lang": "čeština", "sys_lang": "cs_CZ.UTF-8", "default_timezone": "Europe/Prague"},
{"abbr": "ch", "lang": "Chamorro"},
{"abbr": "ce", "lang": "Chechen"},
{"abbr": "cu", "lang": "Church Slavic"},
@ -30,37 +30,37 @@
{"abbr": "cr", "lang": "Cree"},
{"abbr": "cy", "lang": "Welsh"},
{"abbr": "da", "lang": "Danish", "translated_lang": "Dansk"},
{"abbr": "de", "lang": "German", "translated_lang": "Deutsch"},
{"abbr": "de", "lang": "German", "translated_lang": "Deutsch", "sys_lang": "de_DE.UTF-8", "default_timezone": "Europe/Berlin"},
{"abbr": "dv", "lang": "Dhivehi"},
{"abbr": "dz", "lang": "Dzongkha"},
{"abbr": "el", "lang": "Modern Greek (1453-)", "translated_lang": "Ελληνικά"},
{"abbr": "en", "lang": "English"},
{"abbr": "el", "lang": "Modern Greek (1453-)", "translated_lang": "Ελληνικά", "sys_lang": "el_GR.UTF-8", "default_timezone": "Europe/Athens"},
{"abbr": "en", "lang": "English", "sys_lang": "en_US.UTF-8"},
{"abbr": "eo", "lang": "Esperanto"},
{"abbr": "et", "lang": "Estonian", "translated_lang": "Eesti" },
{"abbr": "et", "lang": "Estonian", "translated_lang": "Eesti", "sys_lang": "et_EE.UTF-8" , "default_timezone": "Europe/Tallinn"},
{"abbr": "eu", "lang": "Basque"},
{"abbr": "ee", "lang": "Ewe"},
{"abbr": "fo", "lang": "Faroese"},
{"abbr": "fa", "lang": "Persian"},
{"abbr": "fj", "lang": "Fijian"},
{"abbr": "fi", "lang": "Finnish", "translated_lang": "Suomi"},
{"abbr": "fr", "lang": "French", "translated_lang": "Français"},
{"abbr": "fi", "lang": "Finnish", "translated_lang": "Suomi", "sys_lang": "fi_FI.UTF-8", "default_timezone": "Europe/Helsinki"},
{"abbr": "fr", "lang": "French", "translated_lang": "Français", "sys_lang": "fr_FR.UTF-8", "default_timezone": "Europe/Paris"},
{"abbr": "fy", "lang": "Western Frisian"},
{"abbr": "ff", "lang": "Fulah"},
{"abbr": "gd", "lang": "Scottish Gaelic"},
{"abbr": "ga", "lang": "Irish"},
{"abbr": "gl", "lang": "Galician"},
{"abbr": "ga", "lang": "Irish", "sys_lang": "ga_IE.UTF-8", "default_timezone": "Europe/Dublin"},
{"abbr": "gl", "lang": "Galician", "sys_lang": "gl_ES.UTF-8"},
{"abbr": "gv", "lang": "Manx"},
{"abbr": "gn", "lang": "Guarani"},
{"abbr": "gu", "lang": "Gujarati"},
{"abbr": "ht", "lang": "Haitian"},
{"abbr": "ha", "lang": "Hausa"},
{"abbr": "sh", "lang": "Serbo-Croatian"},
{"abbr": "he", "lang": "Hebrew"},
{"abbr": "he", "lang": "Hebrew", "sys_lang": "he_IL.UTF-8", "default_timezone": "Asia/Jerusalem"},
{"abbr": "hz", "lang": "Herero"},
{"abbr": "hi", "lang": "Hindi"},
{"abbr": "hi", "lang": "Hindi", "sys_lang": "hi_IN.UTF-8", "default_timezone": "Asia/Kolkata"},
{"abbr": "ho", "lang": "Hiri Motu"},
{"abbr": "hr", "lang": "Croatian"},
{"abbr": "hu", "lang": "Hungarian"},
{"abbr": "hu", "lang": "Hungarian", "sys_lang": "hu_HU.UTF-8", "default_timezone": "Europe/Budapest"},
{"abbr": "hy", "lang": "Armenian"},
{"abbr": "ig", "lang": "Igbo"},
{"abbr": "io", "lang": "Ido"},
@ -68,16 +68,16 @@
{"abbr": "iu", "lang": "Inuktitut"},
{"abbr": "ie", "lang": "Interlingue"},
{"abbr": "ia", "lang": "Interlingua (International Auxiliary Language Association)"},
{"abbr": "id", "lang": "Indonesian", "translated_lang": "Indonesian"},
{"abbr": "id", "lang": "Indonesian", "translated_lang": "Indonesian", "sys_lang": "id_ID.UTF-8"},
{"abbr": "ik", "lang": "Inupiaq"},
{"abbr": "is", "lang": "Icelandic"},
{"abbr": "it", "lang": "Italian", "translated_lang": "Italiano"},
{"abbr": "it", "lang": "Italian", "translated_lang": "Italiano", "sys_lang": "it_IT.UTF-8", "default_timezone": "Europe/Rome"},
{"abbr": "jv", "lang": "Javanese"},
{"abbr": "ja", "lang": "Japanese"},
{"abbr": "ja", "lang": "Japanese", "sys_lang": "ja_JP.UTF-8", "default_timezone": "Asia/Tokyo"},
{"abbr": "kl", "lang": "Kalaallisut"},
{"abbr": "kn", "lang": "Kannada"},
{"abbr": "ks", "lang": "Kashmiri"},
{"abbr": "ka", "lang": "Georgian"},
{"abbr": "ka", "lang": "Georgian", "sys_lang": "ka_GE.UTF-8", "default_timezone": "Asia/Tbilisi"},
{"abbr": "kr", "lang": "Kanuri"},
{"abbr": "kk", "lang": "Kazakh"},
{"abbr": "km", "lang": "Central Khmer"},
@ -86,15 +86,15 @@
{"abbr": "ky", "lang": "Kirghiz"},
{"abbr": "kv", "lang": "Komi"},
{"abbr": "kg", "lang": "Kongo"},
{"abbr": "ko", "lang": "Korean", "translated_lang": "한글", "external_dep": true},
{"abbr": "ko", "lang": "Korean", "translated_lang": "한글", "external_dep": true, "sys_lang": "ko_KR.UTF-8", "default_timezone": "Asia/Seoul"},
{"abbr": "kj", "lang": "Kuanyama"},
{"abbr": "ku", "lang": "Kurdish"},
{"abbr": "ku", "lang": "Kurdish", "sys_lang": "ku_TR.UTF-8", "default_timezone": "Europe/Istanbul"},
{"abbr": "lo", "lang": "Lao"},
{"abbr": "la", "lang": "Latin"},
{"abbr": "lv", "lang": "Latvian"},
{"abbr": "li", "lang": "Limburgan"},
{"abbr": "ln", "lang": "Lingala"},
{"abbr": "lt", "lang": "Lithuanian", "translated_lang": "Lietuvių"},
{"abbr": "lt", "lang": "Lithuanian", "translated_lang": "Lietuvių", "sys_lang": "lt_LT.UTF-8", "default_timezone": "Europe/Vilnius"},
{"abbr": "lb", "lang": "Luxembourgish"},
{"abbr": "lu", "lang": "Luba-Katanga"},
{"abbr": "lg", "lang": "Ganda"},
@ -113,8 +113,8 @@
{"abbr": "nr", "lang": "South Ndebele"},
{"abbr": "nd", "lang": "North Ndebele"},
{"abbr": "ng", "lang": "Ndonga"},
{"abbr": "ne", "lang": "Nepali", "translated_lang": "नेपाली"},
{"abbr": "nl", "lang": "Dutch", "translated_lang": "Nederlands"},
{"abbr": "ne", "lang": "Nepali", "translated_lang": "नेपाली", "sys_lang": "ne_NP.UTF-8", "default_timezone": "Asia/Kathmandu"},
{"abbr": "nl", "lang": "Dutch", "translated_lang": "Nederlands", "sys_lang": "nl_NL.UTF-8", "default_timezone": "Europe/Amsterdam"},
{"abbr": "nn", "lang": "Norwegian Nynorsk"},
{"abbr": "nb", "lang": "Norwegian Bokmål", "translated_lang": "Norsk bokmål"},
{"abbr": "no", "lang": "Norwegian"},
@ -126,15 +126,15 @@
{"abbr": "os", "lang": "Ossetian"},
{"abbr": "pa", "lang": "Panjabi"},
{"abbr": "pi", "lang": "Pali"},
{"abbr": "pl", "lang": "Polish", "translated_lang": "Polski"},
{"abbr": "pt", "lang": "Portuguese", "translated_lang": "Português"},
{"abbr": "pt_BR", "lang": "Brazilian Portuguese", "translated_lang": "Português do Brasil"},
{"abbr": "pl", "lang": "Polish", "translated_lang": "Polski", "sys_lang": "pl_PL.UTF-8", "default_timezone": "Europe/Warsaw"},
{"abbr": "pt", "lang": "Portuguese", "translated_lang": "Português", "sys_lang": "pt_PT.UTF-8"},
{"abbr": "pt_BR", "lang": "Brazilian Portuguese", "translated_lang": "Português do Brasil", "sys_lang": "pt_BR.UTF-8"},
{"abbr": "ps", "lang": "Pushto"},
{"abbr": "qu", "lang": "Quechua"},
{"abbr": "rm", "lang": "Romansh"},
{"abbr": "ro", "lang": "Romanian", "translated_lang": "Română"},
{"abbr": "ro", "lang": "Romanian", "translated_lang": "Română", "sys_lang": "ro_RO.UTF-8", "default_timezone": "Europe/Bucharest"},
{"abbr": "rn", "lang": "Rundi"},
{"abbr": "ru", "lang": "Russian", "translated_lang": "Русский"},
{"abbr": "ru", "lang": "Russian", "translated_lang": "Русский", "sys_lang": "ru_RU.UTF-8"},
{"abbr": "sg", "lang": "Sango"},
{"abbr": "sa", "lang": "Sanskrit"},
{"abbr": "si", "lang": "Sinhala"},
@ -146,16 +146,16 @@
{"abbr": "sd", "lang": "Sindhi"},
{"abbr": "so", "lang": "Somali"},
{"abbr": "st", "lang": "Southern Sotho"},
{"abbr": "es", "lang": "Spanish", "translated_lang": "Español"},
{"abbr": "es", "lang": "Spanish", "translated_lang": "Español", "sys_lang": "es_ES.UTF-8"},
{"abbr": "sq", "lang": "Albanian"},
{"abbr": "sc", "lang": "Sardinian"},
{"abbr": "sr", "lang": "Serbian"},
{"abbr": "ss", "lang": "Swati"},
{"abbr": "su", "lang": "Sundanese"},
{"abbr": "sw", "lang": "Swahili (macrolanguage)"},
{"abbr": "sv", "lang": "Swedish", "translated_lang": "Svenska"},
{"abbr": "sv", "lang": "Swedish", "translated_lang": "Svenska", "sys_lang": "sv_SE.UTF-8", "default_timezone": "Europe/Stockholm"},
{"abbr": "ty", "lang": "Tahitian"},
{"abbr": "ta", "lang": "Tamil", "translated_lang": "தமிழ்"},
{"abbr": "ta", "lang": "Tamil", "translated_lang": "தமிழ்", "sys_lang": "ta_IN.UTF-8", "default_timezone": "Asia/Kolkata"},
{"abbr": "tt", "lang": "Tatar"},
{"abbr": "te", "lang": "Telugu"},
{"abbr": "tg", "lang": "Tajik"},
@ -166,12 +166,12 @@
{"abbr": "tn", "lang": "Tswana"},
{"abbr": "ts", "lang": "Tsonga"},
{"abbr": "tk", "lang": "Turkmen"},
{"abbr": "tr", "lang": "Turkish", "translated_lang" : "Türkçe"},
{"abbr": "tr", "lang": "Turkish", "translated_lang" : "Türkçe", "sys_lang": "tr_TR.UTF-8", "default_timezone": "Europe/Istanbul"},
{"abbr": "tw", "lang": "Twi"},
{"abbr": "ug", "lang": "Uighur"},
{"abbr": "uk", "lang": "Ukrainian", "console_font": "UniCyr_8x16"},
{"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو"},
{"abbr": "uz", "lang": "Uzbek", "translated_lang": "O'zbek"},
{"abbr": "uk", "lang": "Ukrainian", "console_font": "UniCyr_8x16", "sys_lang": "uk_UA.UTF-8", "default_timezone": "Europe/Kyiv"},
{"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو", "sys_lang": "ur_PK.UTF-8", "default_timezone": "Asia/Karachi"},
{"abbr": "uz", "lang": "Uzbek", "translated_lang": "O'zbek", "sys_lang": "uz_UZ.UTF-8", "default_timezone": "Asia/Tashkent"},
{"abbr": "ve", "lang": "Venda"},
{"abbr": "vi", "lang": "Vietnamese", "translated_lang": "Tiếng Việt"},
{"abbr": "vo", "lang": "Volapük"},
@ -181,6 +181,6 @@
{"abbr": "yi", "lang": "Yiddish"},
{"abbr": "yo", "lang": "Yoruba"},
{"abbr": "za", "lang": "Zhuang"},
{"abbr": "zh-CN", "lang": "Simplified Chinese", "translated_lang": "简体中文"},
{"abbr": "zh-TW", "lang": "Traditional Chinese", "translated_lang": "繁體中文"},
{"abbr": "zh-CN", "lang": "Simplified Chinese", "translated_lang": "简体中文", "sys_lang": "zh_CN.UTF-8"},
{"abbr": "zh-TW", "lang": "Traditional Chinese", "translated_lang": "繁體中文", "sys_lang": "zh_TW.UTF-8", "default_timezone": "Asia/Taipei"},
{"abbr": "zu", "lang": "Zulu"}]

View File

@ -175,6 +175,12 @@ msgstr "Введіть бажаний тип файлової системи д
msgid "Archinstall language"
msgstr "Мова Archinstall"
msgid "Use this language as the target system language as well?"
msgstr "Використати цю мову як мову цільової системи також?"
msgid "The following settings will be applied:"
msgstr "Будуть застосовані такі налаштування:"
msgid "Wipe all selected drives and use a best-effort default partition layout"
msgstr "Стерти усі вибрані диски та використовувати отпимальну схему розмітки розділів"

View File

@ -4,7 +4,7 @@ from collections.abc import Awaitable, Callable, Iterable
from dataclasses import dataclass, field
from enum import Enum, StrEnum, auto
from functools import cached_property
from typing import Any, ClassVar, Self, override
from typing import Any, Self, override
from archinstall.lib.translationhandler import tr
@ -55,9 +55,6 @@ class MenuItem:
_id: str = ''
_yes: ClassVar[Self | None] = None
_no: ClassVar[Self | None] = None
def __post_init__(self) -> None:
if self.key is not None:
self._id = self.key
@ -77,17 +74,11 @@ class MenuItem:
@classmethod
def yes(cls, action: Callable[[Any], Any] | None = None) -> Self:
if cls._yes is None:
cls._yes = cls(tr('Yes'), value=True, key='yes', action=action)
return cls._yes
return cls(tr('Yes'), value=True, key='yes', action=action)
@classmethod
def no(cls, action: Callable[[Any], Any] | None = None) -> Self:
if cls._no is None:
cls._no = cls(tr('No'), value=False, key='no', action=action)
return cls._no
return cls(tr('No'), value=False, key='no', action=action)
def is_empty(self) -> bool:
return self.text == '' or self.text is None