0ad/source/tools/i18n/updateTemplates.py
wraitii 1b150b303f Update i18n scripts to run on Python3
The `pology` library runs on Python2 and development appears stalled. It
is also not available on pip.
The `babel` library, BSD-licensed, provides, amongst many other things,
a replacement for .POT / .PO manipulation.

The `poediff` tool that we used to detect spurious i18n change is
replaced with a Python script that does a simpler but good enough job
(it is also much, much faster).

These replacements let the i18n scripts run on Python3 entirely.

Makes D506 redundant.

Comments by: Itms
Reviewed By: Gallaecio
Refs #5694

Differential Revision: https://code.wildfiregames.com/D2757
This was SVN commit r24313.
2020-12-02 10:05:27 +00:00

127 lines
5.1 KiB
Python

#!/usr/bin/env python3
#
# Copyright (C) 2020 Wildfire Games.
# This file is part of 0 A.D.
#
# 0 A.D. 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.
#
# 0 A.D. 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 0 A.D. If not, see <http://www.gnu.org/licenses/>.
import json, os
import multiprocessing
from importlib import import_module
from lxml import etree
from i18n_helper import l10nToolsDirectory, projectRootDirectory
from i18n_helper.catalog import Catalog
from extractors import extractors
l10nFolderName = "l10n"
messagesFilename = "messages.json"
def warnAboutUntouchedMods():
"""
Warn about mods that are not properly configured to get their messages extracted.
"""
modsRootFolder = os.path.join(projectRootDirectory, "binaries", "data", "mods")
untouchedMods = {}
for modFolder in os.listdir(modsRootFolder):
if modFolder[0] != "_" and modFolder[0] != '.':
if not os.path.exists(os.path.join(modsRootFolder, modFolder, l10nFolderName)):
untouchedMods[modFolder] = "There is no '{folderName}' folder in the root folder of this mod.".format(folderName=l10nFolderName)
elif not os.path.exists(os.path.join(modsRootFolder, modFolder, l10nFolderName, messagesFilename)):
untouchedMods[modFolder] = "There is no '{filename}' file within the '{folderName}' folder in the root folder of this mod.".format(folderName=l10nFolderName, filename=messagesFilename)
if untouchedMods:
print(""
"Warning: No messages were extracted from the following mods:"
"")
for mod in untouchedMods:
print("{modName}: {warningMessage}".format(modName=mod, warningMessage=untouchedMods[mod]))
print(""
f"For this script to extract messages from a mod folder, this mod folder must contain a '{l10nFolderName}' "
f"folder, and this folder must contain a '{messagesFilename}' file that describes how to extract messages for the "
f"mod. See the folder of the main mod ('public') for an example, and see the documentation for more "
f"information."
)
def generatePOT(templateSettings, rootPath):
if "skip" in templateSettings and templateSettings["skip"] == "yes":
return
inputRootPath = rootPath
if "inputRoot" in templateSettings:
inputRootPath = os.path.join(rootPath, templateSettings["inputRoot"])
template = Catalog(
project=templateSettings["project"],
copyright_holder=templateSettings["copyrightHolder"],
locale='en',
)
for rule in templateSettings["rules"]:
if "skip" in rule and rule["skip"] == "yes":
return
options = rule.get("options", {})
extractorClass = getattr(import_module("extractors.extractors"), rule['extractor'])
extractor = extractorClass(inputRootPath, rule["filemasks"], options)
formatFlag = None
if "format" in options:
formatFlag = options["format"]
for message, plural, context, location, comments in extractor.run():
message_id = (message, plural) if plural else message
saved_message = template.get(message_id, context) or template.add(
id=message_id,
context=context,
auto_comments=comments,
flags=[formatFlag] if formatFlag and message.find("%") != -1 else []
)
saved_message.locations.append(location)
saved_message.flags.discard('python-format')
template.writeTo(os.path.join(rootPath, templateSettings["output"]))
print(u"Generated \"{}\" with {} messages.".format(templateSettings["output"], len(template)))
def generateTemplatesForMessagesFile(messagesFilePath):
with open(messagesFilePath, 'r') as fileObject:
settings = json.load(fileObject)
for templateSettings in settings:
multiprocessing.Process(
target=generatePOT,
args=(templateSettings, os.path.dirname(messagesFilePath))
).start()
def main():
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("--scandir", help="Directory to start scanning for l10n folders in. "
"Type '.' for current working directory")
args = parser.parse_args()
for root, folders, filenames in os.walk(args.scandir or projectRootDirectory):
for folder in folders:
if folder == l10nFolderName:
messagesFilePath = os.path.join(root, folder, messagesFilename)
if os.path.exists(messagesFilePath):
generateTemplatesForMessagesFile(messagesFilePath)
warnAboutUntouchedMods()
if __name__ == "__main__":
main()