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:
Daniel Girtler 2022-09-12 05:23:21 +10:00 committed by GitHub
parent c373607f8c
commit 94df913e0f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 85 additions and 27 deletions

View File

@ -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()

View File

@ -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

View File

@ -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]:

View File

@ -2,7 +2,25 @@
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

View File

@ -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"},