diff --git a/README.md b/README.md index 1c0d9b43f..9c7001c31 100644 --- a/README.md +++ b/README.md @@ -40,3 +40,35 @@ This command will install all dependencies and start a dev server (based on [web You can also install [Vue Devtools](https://addons.mozilla.org/fr/firefox/addon/vue-js-devtools/) (module for Firefox but also exists for Chromium/Chrome) if you want component trees, performance views and so on. On a YunoHost instance, the web admin files are located at `/usr/share/yunohost/admin`. + +### Translation maintenance + +#### Cleaning + +To clean locales from unused keys: +``` +python3 maintenance/clean_locales.py +``` +This will also reorder keys in `en.json`. + +#### Renaming + +If you need to rename a key or more (from 'my.current.key' to 'my.new.key' for example). + +From a string + +```bash +python3 rename_i18n_keys.py --keys my.current.key:my.new.key +``` + +#### From a file +```bash +python3 rename_i18n_keys.py --file input.txt +``` +input.txt +``` +my.current.key:my.new.key +my.other.key:my.new.other.key +``` + +By default it renames keys only in the `en.json`, pass `--all` to apply changes to all locales file. \ No newline at end of file diff --git a/maintenance/clean_locales.py b/maintenance/clean_locales.py index d2f1873bd..f9e75421e 100644 --- a/maintenance/clean_locales.py +++ b/maintenance/clean_locales.py @@ -24,15 +24,16 @@ def save_locale_json(locale, data, sort=False): fp.write("\n") -def get_flatten_keys(d, parent_key=""): +def get_flatten_keys(d, parent_key="", only_full_keys=False): items = set() for k, v in d.items(): key = f"{parent_key}.{k}" if parent_key else k - items.add(key) if isinstance(v, dict): items |= get_flatten_keys(v, key) + elif not only_full_keys: + items.add(key) return items diff --git a/maintenance/rename_i18n_keys.py b/maintenance/rename_i18n_keys.py new file mode 100644 index 000000000..bcddc93d1 --- /dev/null +++ b/maintenance/rename_i18n_keys.py @@ -0,0 +1,94 @@ +import argparse +import json +from collections import OrderedDict +from pathlib import Path +from typing import cast +from clean_locales import ( + ALL_LOCALES, + get_flatten_keys, + get_locale_json, + save_locale_json, +) + + +def _parse_cli_args() -> argparse.Namespace: + parser = argparse.ArgumentParser(add_help=False) + parser.add_argument( + "--keys", + default=None, + help="A key replace like 'my.previous.key:my.new.k", + ) + parser.add_argument( + "--all", + action="store_true", + default=False, + help="Apply changes to all locales (default: only en.json)", + ) + parser.add_argument( + "--file", default=None, help="File path with 'current:new' keys on each lines" + ) + + return parser.parse_args() + + +def get_keys(params: argparse.Namespace) -> list[tuple[str, str]]: + keys = [] + + if params.file: + file = Path(params.file) + assert file.exists(), "file does'nt exists." + with file.open() as fp: + keys = fp.readlines() + + if params.keys: + keys.append(params.keys) + + keys = [ks.strip() for ks in keys] + keys = [ks for ks in keys if ks] + + return [cast(tuple[str, str], tuple(key.split(":", 1))) for key in keys] + + +def pop_key(keys: list[str], data: OrderedDict) -> str: + k, *rest = keys + + if rest: + v = pop_key(rest, data[k]) + if not data[k]: + data.pop(k) + return v + else: + return data.pop(k) + + +def insert_key(keys: list[str], data: OrderedDict, v: str) -> None: + k, *rest = keys + + if rest: + if k not in data: + data[k] = {} + insert_key(rest, data[k], v) + else: + if k in data: + data[k] += "||" + v + else: + data[k] = v + + +if __name__ == "__main__": + params = _parse_cli_args() + keys = get_keys(params) + locales = ALL_LOCALES if params.all else set(["en"]) + + for locale in locales: + locale_data = get_locale_json(locale) + locale_keys = get_flatten_keys(locale_data) + for k1, k2 in keys: + if k1 not in locale_keys: + print(f"[WARNING] key '{k1}' doesn't exists in file.") + continue + + v = pop_key(k1.split("."), locale_data) + insert_key(k2.split("."), locale_data, v) + + save_locale_json(locale, locale_data, sort=locale == "en")