[PR #11824/39f4cda6 backport][stable-12] locale_gen: support locales not yet listed in /etc/locale.gen (#11883)

locale_gen: support locales not yet listed in /etc/locale.gen (#11824)

* locale_gen: support locales not yet listed in /etc/locale.gen

On systems like Gentoo where /etc/locale.gen starts with only a handful
of commented examples, set_locale_glibc() now appends missing locale
entries sourced from /usr/share/i18n/SUPPORTED instead of silently
doing nothing. Also extracts the shared locale-entry regex into a
module-level constant RE_LOCALE_ENTRY.



* locale_gen: add changelog fragment for issue 2399



---------


(cherry picked from commit 39f4cda6b5)

Co-authored-by: Alexei Znamensky <103110+russoz@users.noreply.github.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
patchback[bot]
2026-04-19 12:49:10 +02:00
committed by GitHub
parent 449a179d8f
commit 973b5be063
2 changed files with 33 additions and 7 deletions

View File

@@ -87,6 +87,7 @@ ETC_LOCALE_GEN = "/etc/locale.gen"
VAR_LIB_LOCALES = "/var/lib/locales/supported.d"
VAR_LIB_LOCALES_LOCAL = os.path.join(VAR_LIB_LOCALES, "local")
SUPPORTED_LOCALES = ["/usr/share/i18n/SUPPORTED", "/usr/local/share/i18n/SUPPORTED"]
RE_LOCALE_ENTRY = re.compile(r"^\s*#?\s*(?P<locale>\S+[\._\S]+) (?P<charset>\S+)\s*$")
LOCALE_NORMALIZATION = {
".utf8": ".UTF-8",
".eucjp": ".EUC-JP",
@@ -165,8 +166,7 @@ class LocaleGen(StateModuleHelper):
with open(locale_path) as fd:
self.vars.available_lines.extend(fd.readlines())
re_locale_entry = re.compile(r"^\s*#?\s*(?P<locale>\S+[\._\S]+) (?P<charset>\S+)\s*$")
available_locale_entry_re_matches.extend([re_locale_entry.match(line) for line in self.vars.available_lines])
available_locale_entry_re_matches.extend([RE_LOCALE_ENTRY.match(line) for line in self.vars.available_lines])
locales_not_found = []
for locale in self.vars.name:
@@ -206,12 +206,24 @@ class LocaleGen(StateModuleHelper):
name = name.replace(s, r)
return name
def _get_charset_from_supported(self, locale):
"""Look up the charset for a locale from the SUPPORTED files."""
for locale_path in SUPPORTED_LOCALES:
if os.path.exists(locale_path):
with open(locale_path) as fd:
for line in fd:
match = RE_LOCALE_ENTRY.match(line)
if match and match.group("locale") == locale:
return match.group("charset")
return None
def set_locale_glibc(self, names, enabled=True):
"""Sets the state of the locale. Defaults to enabled."""
with open(ETC_LOCALE_GEN) as fr:
lines = fr.readlines()
locale_regexes = []
locale_regexes = {}
matched = set()
for name in names:
search_string = rf"^#?\s*{re.escape(name)} (?P<charset>.+)"
@@ -219,16 +231,26 @@ class LocaleGen(StateModuleHelper):
new_string = rf"{name} \g<charset>"
else:
new_string = rf"# {name} \g<charset>"
re_search = re.compile(search_string)
locale_regexes.append([re_search, new_string])
locale_regexes[name] = (re.compile(search_string), new_string)
def search_replace(line):
for [search, replace] in locale_regexes:
line = search.sub(replace, line)
for name, (search, replace) in locale_regexes.items():
new_line = search.sub(replace, line)
if new_line != line:
matched.add(name)
line = new_line
return line
lines = [search_replace(line) for line in lines]
# For locales not found in /etc/locale.gen (e.g. on Gentoo), add them
if enabled:
for name in names:
if name not in matched:
charset = self._get_charset_from_supported(name)
if charset:
lines.append(f"{name} {charset}\n")
# Write the modified content back to the file
with open(ETC_LOCALE_GEN, "w") as fw:
fw.writelines(lines)