diff options
Diffstat (limited to 'release/scripts/modules/i18n/merge_po.py')
-rwxr-xr-x | release/scripts/modules/i18n/merge_po.py | 156 |
1 files changed, 156 insertions, 0 deletions
diff --git a/release/scripts/modules/i18n/merge_po.py b/release/scripts/modules/i18n/merge_po.py new file mode 100755 index 00000000000..1a55cd670b0 --- /dev/null +++ b/release/scripts/modules/i18n/merge_po.py @@ -0,0 +1,156 @@ +#!/usr/bin/python3 + +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +# <pep8 compliant> + +# Merge one or more .po files into the first dest one. +# If a msgkey is present in more than one merged po, the one in the first file wins, unless +# it’s marked as fuzzy and one later is not. +# The fuzzy flag is removed if necessary. +# All other comments are never modified. +# However, commented messages in dst will always remain commented, and commented messages are +# never merged from sources. + +import sys +from codecs import open + +import utils + + +def main(): + import argparse + parser = argparse.ArgumentParser(description="" \ + "Merge one or more .po files into the first dest one.\n" \ + "If a msgkey (msgid, msgctxt) is present in more than " \ + "one merged po, the one in the first file wins, unless " \ + "it’s marked as fuzzy and one later is not.\n" \ + "The fuzzy flag is removed if necessary.\n" \ + "All other comments are never modified.\n" \ + "Commented messages in dst will always remain " \ + "commented, and commented messages are never merged " \ + "from sources.") + parser.add_argument('-s', '--stats', action="store_true", + help="Show statistics info.") + parser.add_argument('-r', '--replace', action="store_true", + help="Replace existing messages of same \"level\" already in dest po.") + parser.add_argument('dst', metavar='dst.po', + help="The dest po into which merge the others.") + parser.add_argument('src', metavar='src.po', nargs='+', + help="The po's to merge into the dst.po one.") + args = parser.parse_args() + + + ret = 0 + done_msgkeys = set() + done_fuzzy_msgkeys = set() + nbr_merged = 0 + nbr_replaced = 0 + nbr_added = 0 + nbr_unfuzzied = 0 + + dst_messages, dst_states, dst_stats = utils.parse_messages(args.dst) + if dst_states["is_broken"]: + print("Dest po is BROKEN, aborting.") + return 1 + if args.stats: + print("Dest po, before merging:") + utils.print_stats(dst_stats, prefix="\t") + # If we don’t want to replace existing valid translations, pre-populate + # done_msgkeys and done_fuzzy_msgkeys. + if not args.replace: + done_msgkeys = dst_states["trans_msg"].copy() + done_fuzzy_msgkeys = dst_states["fuzzy_msg"].copy() + for po in args.src: + messages, states, stats = utils.parse_messages(po) + if states["is_broken"]: + print("\tSrc po {} is BROKEN, skipping.".format(po)) + ret = 1 + continue + print("\tMerging {}...".format(po)) + if args.stats: + print("\t\tMerged po stats:") + utils.print_stats(stats, prefix="\t\t\t") + for msgkey, val in messages.items(): + msgctxt, msgid = msgkey + # This msgkey has already been completely merged, or is a commented one, + # or the new message is commented, skip it. + if msgkey in (done_msgkeys | dst_states["comm_msg"] | states["comm_msg"]): + continue + is_ttip = utils.is_tooltip(msgid) + # New messages does not yet exists in dest. + if msgkey not in dst_messages: + dst_messages[msgkey] = messages[msgkey] + if msgkey in states["fuzzy_msg"]: + done_fuzzy_msgkeys.add(msgkey) + dst_states["fuzzy_msg"].add(msgkey) + elif msgkey in states["trans_msg"]: + done_msgkeys.add(msgkey) + dst_states["trans_msg"].add(msgkey) + dst_stats["trans_msg"] += 1 + if is_ttip: + dst_stats["trans_ttips"] += 1 + nbr_added += 1 + dst_stats["tot_msg"] += 1 + if is_ttip: + dst_stats["tot_ttips"] += 1 + # From now on, the new messages is already in dst. + # New message is neither translated nor fuzzy, skip it. + elif msgkey not in (states["trans_msg"] | states["fuzzy_msg"]): + continue + # From now on, the new message is either translated or fuzzy! + # The new message is translated. + elif msgkey in states["trans_msg"]: + dst_messages[msgkey]["msgstr_lines"] = messages[msgkey]["msgstr_lines"] + done_msgkeys.add(msgkey) + done_fuzzy_msgkeys.discard(msgkey) + if msgkey in dst_states["fuzzy_msg"]: + dst_states["fuzzy_msg"].remove(msgkey) + nbr_unfuzzied += 1 + if msgkey not in dst_states["trans_msg"]: + dst_states["trans_msg"].add(msgkey) + dst_stats["trans_msg"] += 1 + if is_ttip: + dst_stats["trans_ttips"] += 1 + else: + nbr_replaced += 1 + nbr_merged += 1 + # The new message is fuzzy, org one is fuzzy too, + # and this msgkey has not yet been merged. + elif msgkey not in (dst_states["trans_msg"] | done_fuzzy_msgkeys): + dst_messages[msgkey]["msgstr_lines"] = messages[msgkey]["msgstr_lines"] + done_fuzzy_msgkeys.add(msgkey) + dst_states["fuzzy_msg"].add(msgkey) + nbr_merged += 1 + nbr_replaced += 1 + + utils.write_messages(args.dst, dst_messages, dst_states["comm_msg"], dst_states["fuzzy_msg"]) + + print("Merged completed. {} messages were merged (among which {} were replaced), " \ + "{} were added, {} were \"un-fuzzied\"." \ + "".format(nbr_merged, nbr_replaced, nbr_added, nbr_unfuzzied)) + if args.stats: + print("Final merged po stats:") + utils.print_stats(dst_stats, prefix="\t") + return ret + + +if __name__ == "__main__": + print("\n\n *** Running {} *** \n".format(__file__)) + sys.exit(main()) |