Skip to content

Instantly share code, notes, and snippets.

@oadam
Last active November 8, 2021 09:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oadam/a02f862ac7a88579ea2743986c9be121 to your computer and use it in GitHub Desktop.
Save oadam/a02f862ac7a88579ea2743986c9be121 to your computer and use it in GitHub Desktop.
Gettext po file git merge driver
*.po merge=pofile
[merge "pofile"]
name = custom merge driver for gettext po files
driver = po-merge-driver.py %A %O %B
#!/usr/bin/env python3
import importlib
import subprocess
import sys
def default_merge_and_exit():
print(f"running default git merge", file=sys.stderr)
subprocess.run(['git', 'merge-file', '-L', 'ours', '-L', 'base', '-L', 'theirs', sys.argv[1], sys.argv[2], sys.argv[3]])
exit(1)
# check if polib is available
try:
import polib
except ModuleNotFoundError as err:
print('polib is not installed', file=sys.stderr)
default_merge_and_exit()
try:
# create 3 dictionnaries
ours={}
for e in polib.pofile(sys.argv[1]):
ours[e.msgid]=e.msgstr
base={}
for e in polib.pofile(sys.argv[2]):
base[e.msgid]=e.msgstr
theirs={}
for e in polib.pofile(sys.argv[3]):
theirs[e.msgid]=e.msgstr
all_keys=set(ours.keys())
all_keys.update(base.keys())
all_keys.update(theirs.keys())
# check for conflicts
conflicts=[]
for key in sorted(all_keys):
presence = (key in ours, key in base, key in theirs)
if presence == (False, True, True) and base[key] != theirs[key]:
conflicts.append(f"key removed by us and modified by them : {key}")
if presence == (True, True, False) and base[key] != ours[key]:
conflicts.append(f"key removed by them and modified by us : {key}")
if presence == (True, False, True) and ours[key] != theirs[key]:
conflicts.append(f"key added by them and us in a different way : {key}")
if presence == (True, True, True) and base[key] != ours[key] and base[key] != theirs[key] and ours[key] != theirs[key]:
conflicts.append(f"key modified by them and us in a different way : {key}")
if conflicts:
print(f"\nERROR : automerge for {sys.argv[1]} will conflict :", file=sys.stderr)
for c in conflicts:
print(c, file=sys.stderr)
print("\n", file=sys.stderr)
default_merge_and_exit()
# update ours_po, knowing that there are no conflicts
ours_po=polib.pofile(sys.argv[1])
# mutate all entries with their modifications
for e in ours_po:
key=e.msgid
if key in theirs and key in base and theirs[key] != base[key]:
e.msgstr = theirs[key]
# remove all entries removed by them
# mutate the object without creating a new one https://stackoverflow.com/a/1208792/436792
ours_po[:] = [e for e in ours_po if e.msgid in theirs]
# add all entries introduced by them
theirs_po=polib.pofile(sys.argv[3])
for e in theirs_po:
key=e.msgid
if key not in ours:
ours_po.append(e)
# save result
ours_po.save(sys.argv[1])
# format result
formatted = subprocess.check_output(['msgcat', '--sort-output',sys.argv[1]], text=True)
open(sys.argv[1], 'w').write(formatted)
except BaseException:
default_merge_and_exit()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment