120 lines
3.0 KiB
Python
120 lines
3.0 KiB
Python
#!/usr/bin/env python3
|
|
# -*- coding: UTF-8 -*-
|
|
import os
|
|
import json
|
|
import re
|
|
import sys
|
|
import copy
|
|
import shutil
|
|
from fluent.syntax import parse, serialize
|
|
from fluent.syntax.ast import Message, TextElement, Identifier, Pattern, Junk
|
|
|
|
# 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):
|
|
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}")
|
|
|
|
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")
|