check_shortcut_keys.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. #!/usr/bin/env python3
  2. #
  3. # This script checks for duplicate shortcut keys in all translation files.
  4. #
  5. import collections
  6. import os
  7. import sys
  8. from typing import Optional
  9. COLOR_WARNING = '\033[93m'
  10. COLOR_ENDC = '\033[0m'
  11. regex_patter = '(&[\w])' #"&[a-zA-Z0-9]" - Search char '&' and at least one character after it
  12. # Directory where this python file resides
  13. SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
  14. class ShortcutKeysChecker:
  15. MSGCTXT = "msgctxt" # Scope of the text . Like : msgctxt "@action:inmenu menubar:help"
  16. MSGID = "msgid" # The id tag, also English text version
  17. MSGSTR = "msgstr" # The translation tag
  18. def has_duplicates(self, filename: str) -> bool:
  19. """
  20. Checks if the given file has duplicate shortcut keys.
  21. """
  22. with open(filename, "r", encoding = "utf-8") as f:
  23. all_lines = f.readlines()
  24. all_lines = [l.strip() for l in all_lines]
  25. shortcut_dict = collections.defaultdict(dict)
  26. found_ctxt = False
  27. current_data = dict()
  28. current_field = None
  29. start_line = None
  30. for idx, line in enumerate(all_lines):
  31. if line.startswith(self.MSGCTXT):
  32. found_ctxt = True
  33. current_data.clear()
  34. current_field = self.MSGCTXT
  35. current_data[current_field] = self._fetch_data(line)
  36. start_line = idx
  37. continue
  38. elif found_ctxt and line.startswith(self.MSGID):
  39. current_field = self.MSGID
  40. current_data[current_field] = self._fetch_data(line)
  41. continue
  42. elif found_ctxt and line.startswith(self.MSGSTR):
  43. current_field = self.MSGSTR
  44. current_data[current_field] = self._fetch_data(line)
  45. continue
  46. elif found_ctxt and line.startswith('"'):
  47. data = line[1:-1] # strip the beginning and ending double-quotes
  48. current_data[current_field] += data
  49. continue
  50. if current_data:
  51. self._process_translation(shortcut_dict, current_data, start_line)
  52. current_data.clear()
  53. current_field = None
  54. found_ctxt = False
  55. start_line = None
  56. return self._show_all_duplicates(shortcut_dict, filename)
  57. def _fetch_data(self, line: str) -> str:
  58. return (line.split(" ", 1)[-1])[1:-1]
  59. def _process_translation(self, shortcut_dict: dict, data_dict: dict, start_line: int) -> None:
  60. # Only check the ones with shortcuts
  61. msg = data_dict[self.MSGID]
  62. if data_dict[self.MSGSTR]:
  63. msg = data_dict[self.MSGSTR]
  64. shortcut_key = self._get_shortcut_key(msg)
  65. if shortcut_key is None:
  66. return
  67. msg_section = data_dict[self.MSGCTXT]
  68. keys_dict = shortcut_dict[msg_section]
  69. if shortcut_key not in keys_dict:
  70. keys_dict[shortcut_key] = {"shortcut_key": shortcut_key,
  71. "section": msg_section,
  72. "existing_lines": dict(),
  73. }
  74. existing_data_dict = keys_dict[shortcut_key]["existing_lines"]
  75. existing_data_dict[start_line] = {"message": msg,
  76. }
  77. def _get_shortcut_key(self, text: str) -> Optional[str]:
  78. key = None
  79. if text.count("&") == 1:
  80. idx = text.find("&") + 1
  81. if idx < len(text):
  82. character = text[idx]
  83. if not character.isspace():
  84. key = character.lower()
  85. return key
  86. def _show_all_duplicates(self, shortcut_dict: dict, filename: str) -> bool:
  87. has_duplicates = False
  88. for keys_dict in shortcut_dict.values():
  89. for shortcut_key, data_dict in keys_dict.items():
  90. if len(data_dict["existing_lines"]) == 1:
  91. continue
  92. has_duplicates = True
  93. print("")
  94. print("The following messages have the same shortcut key '%s':" % shortcut_key)
  95. print(" shortcut: '%s'" % data_dict["shortcut_key"])
  96. print(" section : '%s'" % data_dict["section"])
  97. for line, msg in data_dict["existing_lines"].items():
  98. relative_filename = (filename.rsplit("..", 1)[-1])[1:]
  99. print(" - [%s] L%7d : '%s'" % (relative_filename, line, msg["message"]))
  100. return has_duplicates
  101. if __name__ == "__main__":
  102. checker = ShortcutKeysChecker()
  103. all_dirnames = [""]
  104. for _, dirnames, _ in os.walk(os.path.join(SCRIPT_DIR, "..", "resources", "i18n")):
  105. all_dirnames += [dn for dn in dirnames]
  106. break
  107. found_duplicates = False
  108. for dirname in all_dirnames:
  109. file_name = "cura.pot" if not dirname else "cura.po"
  110. file_path = os.path.join(SCRIPT_DIR, "..", "resources", "i18n", dirname, file_name)
  111. found_duplicates = found_duplicates or checker.has_duplicates(file_path)
  112. sys.exit(0 if not found_duplicates else 1)