Update handling of unsupported translations (#1467)
* Handle unsupported fonts * Update archinstall/locales/README.md Co-authored-by: codefiles <11915375+codefiles@users.noreply.github.com> Co-authored-by: Daniel Girtler <girtler.daniel@gmail.com> Co-authored-by: codefiles <11915375+codefiles@users.noreply.github.com>
This commit is contained in:
parent
c373607f8c
commit
94df913e0f
|
|
@ -1,7 +1,7 @@
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from enum import Enum, auto
|
from enum import Enum, auto
|
||||||
from os import system
|
from os import system
|
||||||
from typing import Dict, List, Union, Any, TYPE_CHECKING, Optional
|
from typing import Dict, List, Union, Any, TYPE_CHECKING, Optional, Callable
|
||||||
|
|
||||||
from archinstall.lib.menu.simple_menu import TerminalMenu
|
from archinstall.lib.menu.simple_menu import TerminalMenu
|
||||||
|
|
||||||
|
|
@ -52,9 +52,9 @@ class Menu(TerminalMenu):
|
||||||
sort :bool = True,
|
sort :bool = True,
|
||||||
preset_values :Union[str, List[str]] = None,
|
preset_values :Union[str, List[str]] = None,
|
||||||
cursor_index : Optional[int] = None,
|
cursor_index : Optional[int] = None,
|
||||||
preview_command=None,
|
preview_command: Optional[Callable] = None,
|
||||||
preview_size=0.75,
|
preview_size: float = 0.75,
|
||||||
preview_title='Info',
|
preview_title: str = 'Info',
|
||||||
header :Union[List[str],str] = None,
|
header :Union[List[str],str] = None,
|
||||||
raise_error_on_interrupt :bool = False,
|
raise_error_on_interrupt :bool = False,
|
||||||
raise_error_warning_msg :str = '',
|
raise_error_warning_msg :str = '',
|
||||||
|
|
@ -152,6 +152,7 @@ class Menu(TerminalMenu):
|
||||||
self._multi = multi
|
self._multi = multi
|
||||||
self._raise_error_on_interrupt = raise_error_on_interrupt
|
self._raise_error_on_interrupt = raise_error_on_interrupt
|
||||||
self._raise_error_warning_msg = raise_error_warning_msg
|
self._raise_error_warning_msg = raise_error_warning_msg
|
||||||
|
self._preview_command = preview_command
|
||||||
|
|
||||||
menu_title = f'\n{title}\n\n'
|
menu_title = f'\n{title}\n\n'
|
||||||
|
|
||||||
|
|
@ -198,7 +199,7 @@ class Menu(TerminalMenu):
|
||||||
# show_search_hint=True,
|
# show_search_hint=True,
|
||||||
preselected_entries=self.preset_values,
|
preselected_entries=self.preset_values,
|
||||||
cursor_index=self.cursor_index,
|
cursor_index=self.cursor_index,
|
||||||
preview_command=preview_command,
|
preview_command=lambda x: self._preview_wrapper(preview_command, x),
|
||||||
preview_size=preview_size,
|
preview_size=preview_size,
|
||||||
preview_title=preview_title,
|
preview_title=preview_title,
|
||||||
raise_error_on_interrupt=self._raise_error_on_interrupt,
|
raise_error_on_interrupt=self._raise_error_on_interrupt,
|
||||||
|
|
@ -235,6 +236,13 @@ class Menu(TerminalMenu):
|
||||||
else:
|
else:
|
||||||
return MenuSelection(type_=MenuSelectionType.Esc)
|
return MenuSelection(type_=MenuSelectionType.Esc)
|
||||||
|
|
||||||
|
def _preview_wrapper(self, preview_command: Optional[Callable], current_selection: str) -> Optional[str]:
|
||||||
|
if preview_command:
|
||||||
|
if self._default_option is not None and f'{self._default_option} {self._default_str}' == current_selection:
|
||||||
|
current_selection = self._default_option
|
||||||
|
return preview_command(current_selection)
|
||||||
|
return None
|
||||||
|
|
||||||
def run(self) -> MenuSelection:
|
def run(self) -> MenuSelection:
|
||||||
ret = self._show()
|
ret = self._show()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,41 +17,55 @@ if TYPE_CHECKING:
|
||||||
@dataclass
|
@dataclass
|
||||||
class Language:
|
class Language:
|
||||||
abbr: str
|
abbr: str
|
||||||
lang: str
|
name_en: str
|
||||||
translation: gettext.NullTranslations
|
translation: gettext.NullTranslations
|
||||||
translation_percent: int
|
translation_percent: int
|
||||||
translated_lang: Optional[str]
|
translated_lang: Optional[str]
|
||||||
|
external_dep: Optional[str]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def display_name(self) -> str:
|
def display_name(self) -> str:
|
||||||
if self.translated_lang:
|
if not self.external_dep and self.translated_lang:
|
||||||
name = self.translated_lang
|
name = self.translated_lang
|
||||||
else:
|
else:
|
||||||
name = self.lang
|
name = self.name_en
|
||||||
|
|
||||||
return f'{name} ({self.translation_percent}%)'
|
return f'{name} ({self.translation_percent}%)'
|
||||||
|
|
||||||
def is_match(self, lang_or_translated_lang: str) -> bool:
|
def is_match(self, lang_or_translated_lang: str) -> bool:
|
||||||
if self.lang == lang_or_translated_lang:
|
if self.name_en == lang_or_translated_lang:
|
||||||
return True
|
return True
|
||||||
elif self.translated_lang == lang_or_translated_lang:
|
elif self.translated_lang == lang_or_translated_lang:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def json(self) -> str:
|
def json(self) -> str:
|
||||||
return self.lang
|
return self.name_en
|
||||||
|
|
||||||
|
|
||||||
class TranslationHandler:
|
class TranslationHandler:
|
||||||
_base_pot = 'base.pot'
|
|
||||||
_languages = 'languages.json'
|
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
# to display latin, greek, cyrillic characters
|
self._base_pot = 'base.pot'
|
||||||
self._set_font('LatGrkCyr-8x16')
|
self._languages = 'languages.json'
|
||||||
|
|
||||||
|
# check if a custom font was provided, otherwise we'll
|
||||||
|
# use one that can display latin, greek, cyrillic characters
|
||||||
|
if self.is_custom_font_enabled():
|
||||||
|
self._set_font(self.custom_font_path().name)
|
||||||
|
else:
|
||||||
|
self._set_font('LatGrkCyr-8x16')
|
||||||
|
|
||||||
self._total_messages = self._get_total_active_messages()
|
self._total_messages = self._get_total_active_messages()
|
||||||
self._translated_languages = self._get_translations()
|
self._translated_languages = self._get_translations()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def custom_font_path(cls) -> Path:
|
||||||
|
return Path('/usr/share/kbd/consolefonts/archinstall_font.psfu.gz')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def is_custom_font_enabled(cls) -> bool:
|
||||||
|
return cls.custom_font_path().exists()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def translated_languages(self) -> List[Language]:
|
def translated_languages(self) -> List[Language]:
|
||||||
return self._translated_languages
|
return self._translated_languages
|
||||||
|
|
@ -70,6 +84,7 @@ class TranslationHandler:
|
||||||
abbr = mapping_entry['abbr']
|
abbr = mapping_entry['abbr']
|
||||||
lang = mapping_entry['lang']
|
lang = mapping_entry['lang']
|
||||||
translated_lang = mapping_entry.get('translated_lang', None)
|
translated_lang = mapping_entry.get('translated_lang', None)
|
||||||
|
external_dep = mapping_entry.get('external_dep', False)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# get a translation for a specific language
|
# get a translation for a specific language
|
||||||
|
|
@ -84,7 +99,7 @@ class TranslationHandler:
|
||||||
# prevent cases where the .pot file is out of date and the percentage is above 100
|
# prevent cases where the .pot file is out of date and the percentage is above 100
|
||||||
percent = min(100, percent)
|
percent = min(100, percent)
|
||||||
|
|
||||||
language = Language(abbr, lang, translation, percent, translated_lang)
|
language = Language(abbr, lang, translation, percent, translated_lang, external_dep)
|
||||||
languages.append(language)
|
languages.append(language)
|
||||||
except FileNotFoundError as error:
|
except FileNotFoundError as error:
|
||||||
raise TranslationError(f"Could not locate language file for '{lang}': {error}")
|
raise TranslationError(f"Could not locate language file for '{lang}': {error}")
|
||||||
|
|
@ -138,7 +153,7 @@ class TranslationHandler:
|
||||||
Get a language object by it's name, e.g. English
|
Get a language object by it's name, e.g. English
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return next(filter(lambda x: x.lang == name, self._translated_languages))
|
return next(filter(lambda x: x.name_en == name, self._translated_languages))
|
||||||
except Exception:
|
except Exception:
|
||||||
raise ValueError(f'No language with name found: {name}')
|
raise ValueError(f'No language with name found: {name}')
|
||||||
|
|
||||||
|
|
@ -175,8 +190,7 @@ class TranslationHandler:
|
||||||
translation_files = []
|
translation_files = []
|
||||||
for filename in filenames:
|
for filename in filenames:
|
||||||
if len(filename) == 2 or filename == 'pt_BR':
|
if len(filename) == 2 or filename == 'pt_BR':
|
||||||
if filename not in ['ur', 'ta']:
|
translation_files.append(filename)
|
||||||
translation_files.append(filename)
|
|
||||||
|
|
||||||
return translation_files
|
return translation_files
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ from ..output import log
|
||||||
from ..profiles import Profile, list_profiles
|
from ..profiles import Profile, list_profiles
|
||||||
from ..mirrors import list_mirrors
|
from ..mirrors import list_mirrors
|
||||||
|
|
||||||
from ..translationhandler import Language
|
from ..translationhandler import Language, TranslationHandler
|
||||||
from ..packages.packages import validate_package_list
|
from ..packages.packages import validate_package_list
|
||||||
|
|
||||||
from ..storage import storage
|
from ..storage import storage
|
||||||
|
|
@ -125,16 +125,34 @@ def select_archinstall_language(languages: List[Language], preset_value: Languag
|
||||||
# name of the language in its own language
|
# name of the language in its own language
|
||||||
options = {lang.display_name: lang for lang in languages}
|
options = {lang.display_name: lang for lang in languages}
|
||||||
|
|
||||||
|
def dependency_preview(current_selection: str) -> Optional[str]:
|
||||||
|
current_lang = options[current_selection]
|
||||||
|
|
||||||
|
if current_lang.external_dep and not TranslationHandler.is_custom_font_enabled():
|
||||||
|
font_file = TranslationHandler.custom_font_path()
|
||||||
|
text = str(_('To be able to use this translation, please install a font manually that supports the language.')) + '\n'
|
||||||
|
text += str(_('The font should be stored as {}')).format(font_file)
|
||||||
|
return text
|
||||||
|
return None
|
||||||
|
|
||||||
choice = Menu(
|
choice = Menu(
|
||||||
_('Archinstall language'),
|
_('Archinstall language'),
|
||||||
list(options.keys()),
|
list(options.keys()),
|
||||||
default_option=preset_value.display_name
|
default_option=preset_value.display_name,
|
||||||
|
preview_command=lambda x: dependency_preview(x),
|
||||||
|
preview_size=0.5
|
||||||
).run()
|
).run()
|
||||||
|
|
||||||
match choice.type_:
|
match choice.type_:
|
||||||
case MenuSelectionType.Esc: return preset_value
|
case MenuSelectionType.Esc:
|
||||||
|
return preset_value
|
||||||
case MenuSelectionType.Selection:
|
case MenuSelectionType.Selection:
|
||||||
return options[choice.value]
|
language: Language = options[choice.value]
|
||||||
|
# we have to make sure that the proper AUR dependency is
|
||||||
|
# present to be able to use this language
|
||||||
|
if not language.external_dep or TranslationHandler.is_custom_font_enabled():
|
||||||
|
return language
|
||||||
|
return select_archinstall_language(languages, preset_value)
|
||||||
|
|
||||||
|
|
||||||
def select_profile(preset) -> Optional[Profile]:
|
def select_profile(preset) -> Optional[Profile]:
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,26 @@
|
||||||
# Nationalization
|
# Nationalization
|
||||||
|
|
||||||
Archinstall supports multiple languages, which depend on translations coming from the community :)
|
Archinstall supports multiple languages, which depend on translations coming from the community :)
|
||||||
|
|
||||||
New languages can be added simply by creating a new folder with the proper language abbrevation (see list `languages.json` if unsure).
|
## Important Note
|
||||||
|
Before starting a new language translation be aware that a font for that language may not be
|
||||||
|
available on the ISO. We are using the pre-installed font `/usr/share/kbd/consolefonts/LatGrkCyr-8x16.psfu.gz` in archinstall
|
||||||
|
which should cover a fair amount of different languages but unfortunately not all of them.
|
||||||
|
|
||||||
|
We have the option to provide a custom font in case the above is not covering a specific language, which can
|
||||||
|
be achieved by installing the font yourself on the ISO and saving it to `/usr/share/kbd/consolefonts/archinstall_font.psfu.gz`.
|
||||||
|
If this font is present it will be automatically loaded and all languages which are not supported by the default font will
|
||||||
|
be enabled (but only some might actually work).
|
||||||
|
|
||||||
|
Please make sure that the provided language works with the default font on the ISO, and if not mark it in the `languages.json`
|
||||||
|
that it needs an external dependency
|
||||||
|
```
|
||||||
|
{"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو", "external_dep": true},
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding new languages
|
||||||
|
|
||||||
|
New languages can be added simply by creating a new folder with the proper language abbreviation (see list `languages.json` if unsure).
|
||||||
Run the following command to create a new template for a language
|
Run the following command to create a new template for a language
|
||||||
```
|
```
|
||||||
mkdir -p <abbr>/LC_MESSAGES/ && touch <abbr>/LC_MESSAGES/base.po
|
mkdir -p <abbr>/LC_MESSAGES/ && touch <abbr>/LC_MESSAGES/base.po
|
||||||
|
|
|
||||||
|
|
@ -155,7 +155,7 @@
|
||||||
{"abbr": "sw", "lang": "Swahili (macrolanguage)"},
|
{"abbr": "sw", "lang": "Swahili (macrolanguage)"},
|
||||||
{"abbr": "sv", "lang": "Swedish", "translated_lang": "Svenska"},
|
{"abbr": "sv", "lang": "Swedish", "translated_lang": "Svenska"},
|
||||||
{"abbr": "ty", "lang": "Tahitian"},
|
{"abbr": "ty", "lang": "Tahitian"},
|
||||||
{"abbr": "ta", "lang": "Tamil", "translated_lang": "தமிழ்"},
|
{"abbr": "ta", "lang": "Tamil", "translated_lang": "தமிழ்", "external_dep": true},
|
||||||
{"abbr": "tt", "lang": "Tatar"},
|
{"abbr": "tt", "lang": "Tatar"},
|
||||||
{"abbr": "te", "lang": "Telugu"},
|
{"abbr": "te", "lang": "Telugu"},
|
||||||
{"abbr": "tg", "lang": "Tajik"},
|
{"abbr": "tg", "lang": "Tajik"},
|
||||||
|
|
@ -170,7 +170,7 @@
|
||||||
{"abbr": "tw", "lang": "Twi"},
|
{"abbr": "tw", "lang": "Twi"},
|
||||||
{"abbr": "ug", "lang": "Uighur"},
|
{"abbr": "ug", "lang": "Uighur"},
|
||||||
{"abbr": "uk", "lang": "Ukrainian"},
|
{"abbr": "uk", "lang": "Ukrainian"},
|
||||||
{"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو"},
|
{"abbr": "ur", "lang": "Urdu", "translated_lang": "اردو", "external_dep": true},
|
||||||
{"abbr": "uz", "lang": "Uzbek"},
|
{"abbr": "uz", "lang": "Uzbek"},
|
||||||
{"abbr": "ve", "lang": "Venda"},
|
{"abbr": "ve", "lang": "Venda"},
|
||||||
{"abbr": "vi", "lang": "Vietnamese"},
|
{"abbr": "vi", "lang": "Vietnamese"},
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue