anki/ftl/duplicate-string.py
2021-04-14 18:22:02 +10:00

123 lines
3.2 KiB
Python

#!/usr/bin/env python3
# Copyright: Ankitects Pty Ltd and contributors
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
import copy
import json
import os
import re
import shutil
import sys
from fluent.syntax import parse, serialize
from fluent.syntax.ast import Identifier, Junk, Message, Pattern, TextElement
# clone an existing ftl string as a new key
# eg:
# $ python duplicate-string.py \
# /source/templates/media-check.ftl window-title \
# /dest/templates/something.ftl key-name
#
# after running, you'll need to copy the output template file into Anki's source
src_filename, old_key, dst_filename, new_key = sys.argv[1:]
# add file as prefix to key
src_prefix = os.path.splitext(os.path.basename(src_filename))[0]
dst_prefix = os.path.splitext(os.path.basename(dst_filename))[0]
old_key = f"{src_prefix}-{old_key}"
new_key = f"{dst_prefix}-{new_key}"
def get_entry(fname, key):
if not os.path.exists(fname):
return
with open(fname) as file:
orig = file.read()
obj = parse(orig)
for ent in obj.body:
if isinstance(ent, Junk):
raise Exception(f"file had junk! {fname} {ent}")
elif isinstance(ent, Message):
if ent.id.name == old_key:
return copy.deepcopy(ent)
def write_entry(fname, key, entry):
assert entry
entry.id.name = key
if not os.path.exists(fname):
orig = ""
else:
with open(fname) as file:
orig = file.read()
obj = parse(orig)
for ent in obj.body:
if isinstance(ent, Junk):
raise Exception(f"file had junk! {fname} {ent}")
obj.body.append(entry)
modified = serialize(obj, with_junk=True)
# escape leading dots
modified = re.sub(r"(?ms)^( +)\.", '\\1{"."}', modified)
# ensure the resulting serialized file is valid by parsing again
obj = parse(modified)
for ent in obj.body:
if isinstance(ent, Junk):
raise Exception(f"introduced junk! {fname} {ent}")
# it's ok, write it out
with open(fname, "w") as file:
file.write(modified)
# get all existing entries into lang -> entry
entries = {}
i18ndir = os.path.join(os.path.dirname(src_filename), "..")
langs = os.listdir(i18ndir)
for lang in langs:
if lang == "templates":
# template
ftl_path = src_filename
else:
# translation
ftl_path = src_filename.replace("templates", lang)
ftl_dir = os.path.dirname(ftl_path)
if not os.path.exists(ftl_dir):
continue
entry = get_entry(ftl_path, old_key)
if entry:
entries[lang] = entry
else:
assert lang != "templates"
# write them into target files
i18ndir = os.path.join(os.path.dirname(dst_filename), "..")
langs = os.listdir(i18ndir)
for lang in langs:
if lang == "templates":
# template
ftl_path = dst_filename
else:
# translation
ftl_path = dst_filename.replace("templates", lang)
ftl_dir = os.path.dirname(ftl_path)
if not os.path.exists(ftl_dir):
continue
if lang in entries:
entry = entries[lang]
write_entry(ftl_path, new_key, entry)
print("done")