Send patches - preferably formatted by git format-patch - to patches at archlinux32 dot org.
summaryrefslogtreecommitdiff
path: root/archinstall/lib/locale_helpers.py
blob: efb0365fba9d114007b4dc757d11f18e8122abf5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
import logging
from typing import Iterator, List, Callable, Optional

from .exceptions import ServiceException, SysCallError
from .general import SysCommand
from .output import log
from .storage import storage


def list_keyboard_languages() -> Iterator[str]:
	for line in SysCommand("localectl --no-pager list-keymaps", environment_vars={'SYSTEMD_COLORS': '0'}):
		yield line.decode('UTF-8').strip()


def list_locales() -> List[str]:
	with open('/etc/locale.gen', 'r') as fp:
		locales = []
		# before the list of locales begins there's an empty line with a '#' in front
		# so we'll collect the localels from bottom up and halt when we're donw
		entries = fp.readlines()
		entries.reverse()

		for entry in entries:
			text = entry.replace('#', '').strip()
			if text == '':
				break
			locales.append(text)

		locales.reverse()
		return locales

def get_locale_mode_text(mode):
	if mode == 'LC_ALL':
		mode_text = "general (LC_ALL)"
	elif mode == "LC_CTYPE":
		mode_text = "Character set"
	elif mode == "LC_NUMERIC":
		mode_text = "Numeric values"
	elif mode == "LC_TIME":
		mode_text = "Time Values"
	elif mode == "LC_COLLATE":
		mode_text = "sort order"
	elif mode == "LC_MESSAGES":
		mode_text = "text messages"
	else:
		mode_text = "Unassigned"
	return mode_text


def reset_cmd_locale():
	""" sets the cmd_locale to its saved default """
	storage['CMD_LOCALE'] = storage.get('CMD_LOCALE_DEFAULT',{})


def unset_cmd_locale():
	""" archinstall will use the execution environment default """
	storage['CMD_LOCALE'] = {}


def set_cmd_locale(
	general: Optional[str] = None,
	charset :str = 'C',
	numbers :str = 'C',
	time :str = 'C',
	collate :str = 'C',
	messages :str = 'C'
):
	"""
	Set the cmd locale.
	If the parameter general is specified, it takes precedence over the rest (might as well not exist)
	The rest define some specific settings above the installed default language. If anyone of this parameters is none means the installation default
	"""
	installed_locales = list_installed_locales()
	result = {}
	if general:
		if general in installed_locales:
			storage['CMD_LOCALE'] = {'LC_ALL':general}
		else:
			log(f"{get_locale_mode_text('LC_ALL')} {general} is not installed. Defaulting to C",fg="yellow",level=logging.WARNING)
		return

	if numbers:
		if numbers in installed_locales:
			result["LC_NUMERIC"] = numbers
		else:
			log(f"{get_locale_mode_text('LC_NUMERIC')} {numbers} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
	if charset:
		if charset in installed_locales:
			result["LC_CTYPE"] = charset
		else:
			log(f"{get_locale_mode_text('LC_CTYPE')} {charset} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
	if time:
		if time in installed_locales:
			result["LC_TIME"] = time
		else:
			log(f"{get_locale_mode_text('LC_TIME')} {time} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
	if collate:
		if collate in installed_locales:
			result["LC_COLLATE"] = collate
		else:
			log(f"{get_locale_mode_text('LC_COLLATE')} {collate} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
	if messages:
		if messages in installed_locales:
			result["LC_MESSAGES"] = messages
		else:
			log(f"{get_locale_mode_text('LC_MESSAGES')} {messages} is not installed. Defaulting to installation language",fg="yellow",level=logging.WARNING)
	storage['CMD_LOCALE'] = result

def host_locale_environ(func :Callable):
	""" decorator when we want a function executing in the host's locale environment """
	def wrapper(*args, **kwargs):
		unset_cmd_locale()
		result = func(*args,**kwargs)
		reset_cmd_locale()
		return result
	return wrapper

def c_locale_environ(func :Callable):
	""" decorator when we want a function executing in the C locale environment """
	def wrapper(*args, **kwargs):
		set_cmd_locale(general='C')
		result = func(*args,**kwargs)
		reset_cmd_locale()
		return result
	return wrapper

def list_installed_locales() -> List[str]:
	lista = []
	for line in SysCommand('locale -a'):
		lista.append(line.decode('UTF-8').strip())
	return lista

def list_x11_keyboard_languages() -> Iterator[str]:
	for line in SysCommand("localectl --no-pager list-x11-keymap-layouts", environment_vars={'SYSTEMD_COLORS': '0'}):
		yield line.decode('UTF-8').strip()


def verify_keyboard_layout(layout :str) -> bool:
	for language in list_keyboard_languages():
		if layout.lower() == language.lower():
			return True
	return False


def verify_x11_keyboard_layout(layout :str) -> bool:
	for language in list_x11_keyboard_languages():
		if layout.lower() == language.lower():
			return True
	return False


def search_keyboard_layout(layout :str) -> Iterator[str]:
	for language in list_keyboard_languages():
		if layout.lower() in language.lower():
			yield language


def set_keyboard_language(locale :str) -> bool:
	if len(locale.strip()):
		if not verify_keyboard_layout(locale):
			log(f"Invalid keyboard locale specified: {locale}", fg="red", level=logging.ERROR)
			return False

		try:
			SysCommand(f'localectl set-keymap {locale}')
		except SysCallError as error:
			raise ServiceException(f"Unable to set locale '{locale}' for console: {error}")

		return True

	return False


def list_timezones() -> Iterator[str]:
	for line in SysCommand("timedatectl --no-pager list-timezones", environment_vars={'SYSTEMD_COLORS': '0'}):
		yield line.decode('UTF-8').strip()