update_po_with_changes.py 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import argparse
  2. from typing import List
  3. """
  4. Takes in one of the po files in resources/i18n/[LANG_CODE]/cura.po and updates it with translations from a
  5. new po file without changing the translation ordering.
  6. This script should be used when we get a po file that has updated translations but is no longer correctly ordered
  7. so the merge becomes messy.
  8. If you are importing files from lionbridge/smartling use lionbridge_import.py.
  9. Note: This does NOT include new strings, it only UPDATES existing strings
  10. """
  11. class Msg:
  12. def __init__(self, msgctxt: str = "", msgid: str = "", msgstr: str = "") -> None:
  13. self.msgctxt = msgctxt
  14. self.msgid = msgid
  15. self.msgstr = msgstr
  16. def __str__(self):
  17. return self.msgctxt + self.msgid + self.msgstr
  18. def parsePOFile(filename: str) -> List[Msg]:
  19. messages = []
  20. with open(filename) as f:
  21. iterator = iter(f.readlines())
  22. for line in iterator:
  23. if line.startswith("msgctxt"):
  24. # Start of a translation item block
  25. msg = Msg()
  26. msg.msgctxt = line
  27. while True:
  28. line = next(iterator)
  29. if line.startswith("msgid"):
  30. msg.msgid = line
  31. break
  32. while True:
  33. # msgstr can be split over multiple lines
  34. line = next(iterator)
  35. if line == "\n":
  36. break
  37. if line.startswith("msgstr"):
  38. msg.msgstr = line
  39. else:
  40. msg.msgstr += line
  41. messages.append(msg)
  42. return messages
  43. def getDifferentMessages(messages_original: List[Msg], messages_new: List[Msg]) -> List[Msg]:
  44. # Return messages that have changed in messages_new
  45. different_messages = []
  46. for m_new in messages_new:
  47. for m_original in messages_original:
  48. if m_new.msgstr != m_original.msgstr \
  49. and m_new.msgid == m_original.msgid and m_new.msgctxt == m_original.msgctxt \
  50. and m_new.msgid != 'msgid ""\n':
  51. different_messages.append(m_new)
  52. return different_messages
  53. def updatePOFile(input_filename: str, output_filename: str, messages: List[Msg]) -> None:
  54. # Takes a list of changed messages and writes a copy of input file with updated message strings
  55. with open(input_filename, "r") as input_file, open(output_filename, "w") as output_file:
  56. iterator = iter(input_file.readlines())
  57. for line in iterator:
  58. output_file.write(line)
  59. if line.startswith("msgctxt"):
  60. # Start of translation block
  61. msgctxt = line
  62. msgid = next(iterator)
  63. output_file.write(msgid)
  64. # Check for updated version of msgstr
  65. message = list(filter(lambda m: m.msgctxt == msgctxt and m.msgid == msgid, messages))
  66. if message and message[0]:
  67. # Write update translation
  68. output_file.write(message[0].msgstr)
  69. # Skip lines until next translation. This should skip multiline msgstr
  70. while True:
  71. line = next(iterator)
  72. if line == "\n":
  73. output_file.write(line)
  74. break
  75. if __name__ == "__main__":
  76. print("********************************************************************************************************************")
  77. print("This creates a new file 'updated.po' that is a copy of original_file with any changed translations from updated_file")
  78. print("This does not change the order of translations")
  79. print("This does not include new translations, only existing changed translations")
  80. print("Do not use this to import lionbridge/smarting translations")
  81. print("********************************************************************************************************************")
  82. parser = argparse.ArgumentParser(description="Update po file with translations from new po file. This ")
  83. parser.add_argument("original_file", type=str, help="Input .po file inside resources/i18n/[LANG]/")
  84. parser.add_argument("updated_file", type=str, help="Input .po file with updated translations added")
  85. args = parser.parse_args()
  86. messages_updated = parsePOFile(args.updated_file)
  87. messages_original = parsePOFile(args.original_file)
  88. different_messages = getDifferentMessages(messages_original, messages_updated)
  89. updatePOFile(args.original_file, "updated.po", different_messages)