1#!/usr/bin/env python2 2# -*- coding: utf-8 -*- 3# 4# Copyright (C) 2018 Wildfire Games. 5# This file is part of 0 A.D. 6# 7# 0 A.D. is free software: you can redistribute it and/or modify 8# it under the terms of the GNU General Public License as published by 9# the Free Software Foundation, either version 2 of the License, or 10# (at your option) any later version. 11# 12# 0 A.D. is distributed in the hope that it will be useful, 13# but WITHOUT ANY WARRANTY; without even the implied warranty of 14# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. 19 20from __future__ import absolute_import, division, print_function, unicode_literals 21 22import codecs, datetime, json, os, string, textwrap 23 24from pology.catalog import Catalog 25from pology.message import Message 26from pology.monitored import Monpair, Monlist 27 28from lxml import etree 29 30 31l10nToolsDirectory = os.path.dirname(os.path.realpath(__file__)) 32projectRootDirectory = os.path.abspath(os.path.join(l10nToolsDirectory, os.pardir, os.pardir, os.pardir)) 33l10nFolderName = "l10n" 34messagesFilename = "messages.json" 35 36 37def warnAboutUntouchedMods(): 38 """ 39 Warn about mods that are not properly configured to get their messages extracted. 40 """ 41 modsRootFolder = os.path.join(projectRootDirectory, "binaries", "data", "mods") 42 untouchedMods = {} 43 for modFolder in os.listdir(modsRootFolder): 44 if modFolder[0] != "_": 45 if not os.path.exists(os.path.join(modsRootFolder, modFolder, l10nFolderName)): 46 untouchedMods[modFolder] = "There is no '{folderName}' folder in the root folder of this mod.".format(folderName=l10nFolderName) 47 elif not os.path.exists(os.path.join(modsRootFolder, modFolder, l10nFolderName, messagesFilename)): 48 untouchedMods[modFolder] = "There is no '{filename}' file within the '{folderName}' folder in the root folder of this mod.".format(folderName=l10nFolderName, filename=messagesFilename) 49 if untouchedMods: 50 print(textwrap.dedent(""" 51 Warning: No messages were extracted from the following mods: 52 """)) 53 for mod in untouchedMods: 54 print("• {modName}: {warningMessage}".format(modName=mod, warningMessage=untouchedMods[mod])) 55 print(textwrap.dedent(""" 56 For this script to extract messages from a mod folder, this mod folder must contain a '{folderName}' 57 folder, and this folder must contain a '{filename}' file that describes how to extract messages for the 58 mod. See the folder of the main mod ('public') for an example, and see the documentation for more 59 information. 60 """.format(folderName=l10nFolderName, filename=messagesFilename) 61 )) 62 63 64def generateTemplatesForMessagesFile(messagesFilePath): 65 66 with open(messagesFilePath, 'r') as fileObject: 67 settings = json.load(fileObject) 68 69 rootPath = os.path.dirname(messagesFilePath) 70 71 for templateSettings in settings: 72 if "skip" in templateSettings and templateSettings["skip"] == "yes": 73 continue 74 75 inputRootPath = rootPath 76 if "inputRoot" in templateSettings: 77 inputRootPath = os.path.join(rootPath, templateSettings["inputRoot"]) 78 79 template = Catalog(os.path.join(rootPath, templateSettings["output"]), create=True, truncate=True) 80 h = template.update_header( 81 templateSettings["project"], 82 "Translation template for %project.", 83 "Copyright (C) {year} {holder}".format( 84 year=datetime.datetime.now().year, 85 holder=templateSettings["copyrightHolder"] 86 ), 87 "This file is distributed under the same license as the %project project.", 88 plforms="nplurals=2; plural=(n != 1);" 89 ) 90 h.remove_field("Report-Msgid-Bugs-To") 91 h.remove_field("Last-Translator") 92 h.remove_field("Language-Team") 93 h.remove_field("Language") 94 h.author = Monlist() 95 96 for rule in templateSettings["rules"]: 97 if "skip" in rule and rule["skip"] == "yes": 98 continue 99 100 options = rule.get("options", {}) 101 extractorClass = getattr(__import__("extractors.extractors", {}, {}, [rule["extractor"]]), rule["extractor"]) 102 extractor = extractorClass(inputRootPath, rule["filemasks"], options) 103 formatFlag = None 104 if "format" in options: 105 formatFlag = options["format"] 106 for message, plural, context, location, comments in extractor.run(): 107 msg = Message({"msgid": message, "msgid_plural": plural, "msgctxt": context, "auto_comment": comments, "flag": [formatFlag] if formatFlag and string.find(message, "%") != -1 else None, "source": [location]}) 108 if template.get(msg): 109 template.get(msg).source.append(Monpair(location)) 110 else: 111 template.add(msg) 112 113 template.set_encoding("utf-8") 114 template.sync(fitplural=True) 115 print(u"Generated \"{}\" with {} messages.".format(templateSettings["output"], len(template))) 116 117 118def main(): 119 120 for root, folders, filenames in os.walk(projectRootDirectory): 121 for folder in folders: 122 if folder == l10nFolderName: 123 messagesFilePath = os.path.join(root, folder, messagesFilename) 124 if os.path.exists(messagesFilePath): 125 generateTemplatesForMessagesFile(messagesFilePath) 126 127 warnAboutUntouchedMods() 128 129 130if __name__ == "__main__": 131 main() 132