Last active
October 4, 2025 18:02
-
-
Save gwennlbh/c5c64b3fe9c6aa99916f545cd1a6baa2 to your computer and use it in GitHub Desktop.
Paraglide to Wuchale migration scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from pathlib import Path | |
import json | |
import re | |
src = Path(__file__).parent.parent | |
english = json.loads(Path(src.parent / "messages/en.json").read_text(encoding="utf8")) | |
french = json.loads(Path(src.parent / "messages/fr.json").read_text(encoding="utf8")) | |
del english["$schema"] | |
del french["$schema"] | |
def named_to_positional(text_with_placeholders: str) -> str: | |
pattern = re.compile(r"\{(?P<name>[a-z0-9_]+)\}") | |
names = [] | |
def replacer(match: re.Match) -> str: | |
name = match.group("name") | |
if name not in names: | |
names.append(name) | |
return "{" + str(names.index(name)) + "}" | |
result = pattern.sub(replacer, text_with_placeholders) | |
if result != text_with_placeholders: | |
print(f"Converted '{text_with_placeholders}' to '{result}'") | |
return result | |
french_to_english = { | |
named_to_positional(french[key]): named_to_positional(english[key]) | |
for key in french.keys() | |
if key in english | |
} | |
pofile = Path(src / "locales/en.po") | |
def red(text: str) -> str: | |
return f"\033[91m{text}\033[0m" | |
def try_surrounding_with_tags(in_french: str) -> str | None: | |
prefixed = french_to_english.get(in_french.removeprefix("<0/> ")) | |
if prefixed: | |
return f"<0/> {prefixed}" | |
suffixed = french_to_english.get(in_french.removesuffix(" <0/>")) | |
if suffixed: | |
return f"{suffixed} <0/>" | |
inside = french_to_english.get(in_french.removeprefix("<0>").removesuffix("</0>")) | |
if inside: | |
return f"<0>{inside}</0>" | |
wrapped = french_to_english.get( | |
in_french.removeprefix("<0/> ").removesuffix(" <1/>") | |
) | |
if wrapped: | |
return f"<0/> {wrapped} <1/>" | |
return None | |
lines = list(pofile.read_text(encoding="utf8").splitlines()) | |
for i, line in enumerate(lines): | |
match = re.match(r'msgid "(?P<key>.+)"', line) | |
if not match: | |
continue | |
key = match.group("key") | |
message = french_to_english.get(key) or try_surrounding_with_tags(key) | |
if not message: | |
print(red(f"Not found: {key}")) | |
continue | |
if lines[i + 1] != 'msgstr ""': | |
continue | |
print(f"Found {key} in {pofile.relative_to(src.parent)}:{i+1} -> {line}") | |
pofile.write_text( | |
pofile.read_text(encoding="utf8").replace( | |
f'msgid "{key}"\nmsgstr ""', | |
f'msgid "{key}"\nmsgstr "{message.replace('"', r'\"')}"', | |
), | |
encoding="utf8", | |
) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import json | |
from pathlib import Path | |
import re | |
here = Path(__file__).parent | |
src = here.parent | |
messages: dict[str, str] = json.loads( | |
Path(src.parent / "messages/fr.json").read_text(encoding="utf8") | |
) | |
paraglide_call_pattern = re.compile(r"\bm\.(?P<key>[a-z0-9_]+)\(\)") | |
def process_directory(directory: Path): | |
for file in directory.glob("*"): | |
if file.is_dir(): | |
process_directory(file) | |
continue | |
if not file.suffix in {".js", ".svelte"}: | |
continue | |
text = file.read_text(encoding="utf8") | |
if "m." not in text: | |
continue | |
lines = list(text.splitlines()) | |
print(f"\nProcessing {file}") | |
for i, line in enumerate(lines): | |
for call in paraglide_call_pattern.finditer(line): | |
print( | |
f'Found {call.group("key")} in {file.relative_to(src.parent)}:{i+1} -> {line.replace(call.group(0), bold(call.group(0)))}' | |
) | |
message = messages.get(call.group("key")) | |
if not message: | |
raise ValueError(f"Key {call.group('key')} not found in messages") | |
lines[i] = line.replace( | |
call.group(0), f"'{message.replace("'", r"\'")}'" | |
) | |
file.write_text("\n".join(lines), encoding="utf8") | |
# ANSI bold for terminal | |
def bold(text: str) -> str: | |
return f"\033[1m{text}\033[0m" | |
if __name__ == "__main__": | |
process_directory(src) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment