3 # ***** BEGIN GPL LICENSE BLOCK *****
5 # This program is free software; you can redistribute it and/or
6 # modify it under the terms of the GNU General Public License
7 # as published by the Free Software Foundation; either version 2
8 # of the License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software Foundation,
17 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 # ***** END GPL LICENSE BLOCK *****
23 # Update "languages" text file used by Blender at runtime to build translations menu.
33 from . import (settings, utils)
35 TRUNK_PO_DIR = settings.TRUNK_PO_DIR
36 TRUNK_MO_DIR = settings.TRUNK_MO_DIR
38 LANGUAGES_CATEGORIES = settings.LANGUAGES_CATEGORIES
39 LANGUAGES = settings.LANGUAGES
40 LANGUAGES_FILE = settings.LANGUAGES_FILE
48 MISSING: "No translation yet!",
49 TOOLOW: "Not enough advanced to be included...",
50 FORBIDDEN: "Explicitly forbidden!",
53 def find_matching_po(languages, stats, forbidden):
54 """Match languages defined in LANGUAGES setting to relevant po, if possible!"""
56 for uid, label, org_key, long_loc in languages:
59 # Try to simplify the key (eg from es_ES to es).
61 key = org_key[0:org_key.index('_')]
62 # For stuff like sr_SR@latin -> sr@latin...
64 key = key + org_key[org_key.index('@'):]
67 ret.append((stats[key], uid, label, org_key, long_loc, FORBIDDEN))
69 ret.append((stats[key], uid, label, org_key, long_loc, OK))
71 ret.append((0.0, uid, label, org_key, long_loc, MISSING))
76 parser = argparse.ArgumentParser(description=""
77 "Update 'languages' text file used by Blender at runtime to build translations menu.")
78 parser.add_argument('-m', '--min_translation', type=int, default=-100,
79 help="Minimum level of translation, as a percentage "
80 "(translations below this are commented out in menu).")
81 parser.add_argument('langs', metavar='ISO_code', nargs='*',
82 help="Unconditionally exclude those languages from the menu.")
83 args = parser.parse_args()
86 min_trans = args.min_translation / 100.0
87 forbidden = set(args.langs)
88 # 'DEFAULT' and en_US are always valid, fully-translated "languages"!
89 stats = {"DEFAULT": 1.0, "en_US": 1.0}
91 # Get the "done level" of each po in trunk...
92 for po in os.listdir(TRUNK_PO_DIR):
93 if po.endswith(".po") and not po.endswith("_raw.po"):
94 lang = os.path.basename(po)[:-3]
95 u1, u2, _stats = utils.parse_messages(os.path.join(TRUNK_PO_DIR, po))
96 stats[lang] = _stats["trans_msg"] / _stats["tot_msg"]
98 # Generate languages file used by Blender's i18n system.
99 # First, match all entries in LANGUAGES to a lang in stats, if possible!
100 stats = find_matching_po(LANGUAGES, stats, forbidden)
101 limits = sorted(LANGUAGES_CATEGORIES, key=lambda it: it[0], reverse=True)
103 stats = sorted(stats, key=lambda it: it[0], reverse=True)
104 langs_cats = [[] for i in range(len(limits))]
106 for prop, uid, label, key, long_loc, flag in stats:
107 if prop < limits[idx][0]:
108 # Sub-sort languages by iso-codes.
109 langs_cats[idx].sort(key=lambda it: it[2])
111 if prop < min_trans and flag == OK:
113 langs_cats[idx].append((uid, label, key, long_loc, flag))
114 if abs(uid) > highest_uid:
115 highest_uid = abs(uid)
116 # Sub-sort last group of languages by iso-codes!
117 langs_cats[idx].sort(key=lambda it: it[2])
118 with open(os.path.join(TRUNK_MO_DIR, LANGUAGES_FILE), 'w', encoding="utf-8") as f:
119 f.write("# File used by Blender to know which languages (translations) are available, \n")
120 f.write("# and to generate translation menu.\n")
122 f.write("# File format:\n")
123 f.write("# ID:MENULABEL:ISOCODE:WINCODE\n")
124 f.write("# ID must be unique, except for 0 value (marks categories for menu).\n")
125 f.write("# Line starting with a # are comments!\n")
127 f.write("# Automatically generated by bl_i18n_utils/update_languages_menu.py script.\n")
128 f.write("# Highest ID currently in use: {}\n".format(highest_uid))
129 for cat, langs_cat in zip(limits, langs_cats):
131 # Write "category menu label"...
133 f.write("0:{}::\n".format(cat[1]))
135 # Do not write the category if it has no language!
136 f.write("# Void category! #0:{}:\n".format(cat[1]))
137 # ...and all matching language entries!
138 for uid, label, key, long_loc, flag in langs_cat:
140 f.write("{}:{}:{}:{}\n".format(uid, label, key, long_loc))
142 # Non-existing, commented entry!
143 f.write("# {} #{}:{}:{}:{}\n".format(FLAG_MESSAGES[flag], uid, label, key, long_loc))
146 if __name__ == "__main__":
147 print("\n\n *** Running {} *** \n".format(__file__))