Files
yunohost/maintenance/autofix_locale_format.py
machine-a-tsoins edb4c397df
Some checks failed
Check for new n releases / updater (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
🍽 Fork YunoHost — snapshot mangé par la machine à tsoins
Upstream: https://github.com/YunoHost/yunohost @ 3a5f8bac8301c450897b96cbd43a4c7d3ba750fb
But (José) : transformer tout le code en bions + ploxions du xerboxion.
La carte de digestion vit au labo : /yunohost-digest.json
2026-07-03 17:20:06 +00:00

188 lines
5.7 KiB
Python
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env python3
#
# Copyright (c) 2024 YunoHost Contributors
#
# This file is part of YunoHost (see https://yunohost.org)
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
import json
import re
import sys
import textwrap
from collections import OrderedDict
from pathlib import Path
Locale = dict[str, str]
def autofix_i18n_placeholders(
reference: Locale, locale: Locale, reference_filename: str, filename: str
) -> tuple[bool, Locale]:
"""
This tries for magically fix mismatch between en.json format and other.json format
e.g. an i18n string with:
source: "Lorem ipsum {some_var}"
fr: "Lorem ipsum {une_variable}"
(ie the keyword in {} was translated but shouldnt have been)
"""
fatal_errors = False
# We iterate over all keys/string in en.json
for key, string in reference.items():
# Ignore check if there's no translation yet for this key
if key not in locale:
continue
# Then we check that every "{stuff}" (for python's .format())
# should also be in the translated string, otherwise the .format
# will trigger an exception!
subkeys_in_ref = [k[0] for k in re.findall(r"{(\w+)(:\w)?}", string)]
subkeys_in_this_locale = [
k[0] for k in re.findall(r"{(\w+)(:\w)?}", locale[key])
]
if set(subkeys_in_ref) != set(subkeys_in_this_locale) and (
len(subkeys_in_ref) == len(subkeys_in_this_locale)
):
for i, subkey in enumerate(subkeys_in_ref):
locale[key] = locale[key].replace(
"{%s}" % subkeys_in_this_locale[i], "{%s}" % subkey
)
# Validate that now it's okay ?
subkeys_in_ref = [k[0] for k in re.findall(r"{(\w+)(:\w)?}", string)]
subkeys_in_this_locale = [
k[0] for k in re.findall(r"{(\w+)(:\w)?}", locale[key])
]
if any(k not in subkeys_in_ref for k in subkeys_in_this_locale):
errmsg = textwrap.dedent(f"""\
==========================
Format inconsistency for string {key} in {filename}:
{reference_filename} -> {string.encode("utf-8")}
{filename} -> {locale[key].encode("utf-8")}
Please fix it manually !
""")
print(errmsg)
fatal_errors = True
return fatal_errors, locale
def autofix_orthotypography_and_standardized_words(
locale: Locale, filename: str
) -> Locale:
godamn_spaces_of_hell = [
"\u00a0",
"\u2000",
"\u2001",
"\u2002",
"\u2003",
"\u2004",
"\u2005",
"\u2006",
"\u2007",
"\u2008",
"\u2009",
"\u200a",
# "\u202f",
# "\u202F",
"\u3000",
]
transformations_space = {s: " " for s in godamn_spaces_of_hell}
transformations_misc = {
r"\.\.\.": "",
"https ://": "https://",
}
transformations_fr = {
"courriel": "email",
"e-mail": "email",
"Courriel": "Email",
"E-mail": "Email",
"« ": "'",
"«": "'",
" »": "'",
"»": "'",
"": "'",
# r"$(\w{1,2})'|( \w{1,2})'": r"\1\2",
}
match filename:
case "en.json":
transformations = transformations_space | transformations_misc
case "fr.json":
transformations = (
transformations_space | transformations_misc | transformations_fr
)
case _:
transformations = {}
for pattern, replace in transformations.items():
for key, value in locale.items():
locale[key] = re.sub(pattern, replace, value)
return locale
def remove_stale_translated_strings(reference: Locale, locale: Locale) -> Locale:
return {k: v for k, v in locale.items() if k in reference}
def sort_locale(locale: Locale) -> Locale:
return dict(sorted(locale.items()))
def main() -> None:
project_dir: Path = Path(__file__).resolve().parent.parent
locale_dir = project_dir / "locales"
reference_file = locale_dir / "en.json"
locale_files = list(locale_dir.glob("*.json"))
locale_files.remove(reference_file)
reference = json.load(reference_file.open())
fatal_errors = []
for file in locale_files:
locale = json.load(file.open(), object_pairs_hook=OrderedDict)
locale = autofix_orthotypography_and_standardized_words(locale, file.name)
locale = remove_stale_translated_strings(reference, locale)
errors, locale = autofix_i18n_placeholders(
reference, locale, reference_file.name, file.name
)
if errors:
fatal_errors.append(file.name)
# locale = sort_locale(locale)
with file.open("w") as locale_io:
json.dump(
locale,
locale_io,
indent=4,
ensure_ascii=False,
)
locale_io.write("\n")
if fatal_errors:
print(f"Errors found in files: {', '.join(fatal_errors)}.")
sys.exit(1)
if __name__ == "__main__":
main()