Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/source/tools/i18n/creditTranslators.py
#!/usr/bin/env python2 | #!/usr/bin/env python3 | ||||
# -*- coding:utf-8 -*- | # -*- coding:utf-8 -*- | ||||
# | # | ||||
# Copyright (C) 2018 Wildfire Games. | # Copyright (C) 2019 Wildfire Games. | ||||
# This file is part of 0 A.D. | # This file is part of 0 A.D. | ||||
# | # | ||||
# 0 A.D. is free software: you can redistribute it and/or modify | # 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 | # it under the terms of the GNU General Public License as published by | ||||
# the Free Software Foundation, either version 2 of the License, or | # the Free Software Foundation, either version 2 of the License, or | ||||
# (at your option) any later version. | # (at your option) any later version. | ||||
# | # | ||||
# 0 A.D. is distributed in the hope that it will be useful, | # 0 A.D. is distributed in the hope that it will be useful, | ||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of | # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
# GNU General Public License for more details. | # GNU General Public License for more details. | ||||
# | # | ||||
# You should have received a copy of the GNU General Public License | # 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/>. | # along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
""" | """ | ||||
This file imports the translators credits located in the public mod GUI files and | This file updates the translators credits located in the public mod GUI files, using | ||||
runs through .po files to add possible new translators to it. | translators names from the .po files. | ||||
It only appends new people, so it is possible to manually add names in the credits | |||||
file and they won't be overwritten by running this script. | |||||
Translatable strings will be extracted from the generated file, so this should be ran | If translators change their names on Transifex, the script will remove the old names. | ||||
before updateTemplates.py. | TODO: It should be possible to add people in the list manually, and protect them against | ||||
""" | automatic deletion. This has not been needed so far. A possibility would be to add an | ||||
optional boolean entry to the dictionary containing the name. | |||||
from __future__ import absolute_import, division, print_function, unicode_literals | Translatable strings will be extracted from the generated file, so this should be run | ||||
once before updateTemplates.py. | |||||
""" | |||||
import json, os, glob, re | import json, os, glob, re | ||||
# Credited languages - Keep in sync with source/tools/dist/remove-incomplete-translations.sh | # Credited languages - Keep in sync with source/tools/dist/remove-incomplete-translations.sh | ||||
langs = { | langs = { | ||||
'ast': 'Asturianu', | 'ast': 'Asturianu', | ||||
'bg': 'Български', | 'bg': 'Български', | ||||
'ca': 'Català', | 'ca': 'Català', | ||||
Show All 25 Lines | |||||
poLocations = [ | poLocations = [ | ||||
'binaries/data/l10n/', | 'binaries/data/l10n/', | ||||
'binaries/data/mods/public/l10n/', | 'binaries/data/mods/public/l10n/', | ||||
'binaries/data/mods/mod/l10n/'] | 'binaries/data/mods/mod/l10n/'] | ||||
creditsLocation = 'binaries/data/mods/public/gui/credits/texts/translators.json' | creditsLocation = 'binaries/data/mods/public/gui/credits/texts/translators.json' | ||||
# Load JSON data | |||||
creditsFile = open(root + creditsLocation) | |||||
JSONData = json.load(creditsFile) | |||||
creditsFile.close() | |||||
# This dictionnary will hold creditors lists for each language, indexed by code | # This dictionnary will hold creditors lists for each language, indexed by code | ||||
langsLists = {} | langsLists = {} | ||||
# Create the new JSON data | # Create the new JSON data | ||||
newJSONData = {'Title': 'Translators', 'Content': []} | newJSONData = {'Title': 'Translators', 'Content': []} | ||||
# First get the already existing lists. If they correspond with some of the credited languages, | # Now go through the list of languages and search the .po files for people | ||||
# add them to the new data after processing, else add them immediately. | |||||
# NB: All of this is quite inefficient | |||||
for element in JSONData['Content']: | |||||
if 'LangName' not in element or element['LangName'] not in langs.values(): | |||||
newJSONData['Content'].append(element) | |||||
continue | |||||
for (langCode, langName) in langs.items(): | |||||
if element['LangName'] == langName: | |||||
langsLists[langCode] = element['List'] | |||||
break | |||||
# Now actually go through the list of languages and search the .po files for people | |||||
# Prepare some regexes | # Prepare some regexes | ||||
commentMatch = re.compile('#.*') | commentMatch = re.compile('#.*') | ||||
translatorMatch = re.compile('# ([\w\s]*)(?: <.*>)?, [0-9-]', re.UNICODE) | translatorMatch = re.compile('# ([^,<]*)(?: <.*>)?, [0-9,-]{4,9}') | ||||
deletedUsernameMatch = re.compile('[0-9a-f]{32}') | |||||
# Search | # Search | ||||
for lang in langs.keys(): | for lang in langs.keys(): | ||||
if lang not in langsLists.keys(): | if lang not in langsLists.keys(): | ||||
langsLists[lang] = [] | langsLists[lang] = [] | ||||
for location in poLocations: | for location in poLocations: | ||||
files = glob.glob(root + location + lang + '.*.po') | files = glob.glob(root + location + lang + '.*.po') | ||||
for file in files: | for file in files: | ||||
poFile = open(file.replace('\\', '/')) | poFile = open(file.replace('\\', '/')) | ||||
reached = False | reached = False | ||||
for line in poFile: | for line in poFile: | ||||
line = line.decode('utf8') | |||||
if reached: | if reached: | ||||
if not commentMatch.match(line): | if not commentMatch.match(line): | ||||
break | break | ||||
m = translatorMatch.match(line) | m = translatorMatch.match(line) | ||||
if m: | if m: | ||||
username = m.group(1) | |||||
if not deletedUsernameMatch.match(username): | |||||
langsLists[lang].append(m.group(1)) | langsLists[lang].append(m.group(1)) | ||||
if line.strip() == '# Translators:': | if line.strip() == '# Translators:': | ||||
reached = True | reached = True | ||||
poFile.close() | poFile.close() | ||||
# Sort and remove duplicates | # Sort and remove duplicates | ||||
# Sorting should ignore case to have a neat credits list | # Sorting should ignore case to have a neat credits list | ||||
langsLists[lang] = sorted(set(langsLists[lang]), cmp=lambda x,y: cmp(x.lower(), y.lower())) | langsLists[lang] = sorted(set(langsLists[lang]), key=lambda s: s.lower()) | ||||
# Now insert the new data into the new JSON file | # Now insert the new data into the new JSON file | ||||
for (langCode, langList) in sorted(langsLists.items()): | for (langCode, langList) in sorted(langsLists.items()): | ||||
newJSONData['Content'].append({'LangName': langs[langCode], 'List': []}) | newJSONData['Content'].append({'LangName': langs[langCode], 'List': []}) | ||||
for name in langList: | for name in langList: | ||||
newJSONData['Content'][-1]['List'].append({'name': name}) | newJSONData['Content'][-1]['List'].append({'name': name}) | ||||
# Save the JSON data to the credits file | # Save the JSON data to the credits file | ||||
creditsFile = open(root + creditsLocation, 'w') | creditsFile = open(root + creditsLocation, 'w') | ||||
json.dump(newJSONData, creditsFile, indent=4) | json.dump(newJSONData, creditsFile, indent=4) | ||||
creditsFile.close() | creditsFile.close() |
Wildfire Games · Phabricator