wesnoth/utils/pofix.py
2012-01-29 21:11:31 +00:00

131 lines
4.9 KiB
Python
Executable File

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# pofix - perform string fixups on incoming .po files.
#
# The purpose of this script is to save translators from having to
# apply various string fixes needed before stable release by hand. It is
# intended to be run on each incoming .po file as the Lord of
# Translations receives it. However, translators may run it on their
# own .po files to be sure, as a second application will harmlessly do
# nothing.
#
# To use this script, give it one or more paths to .po files as
# command-line arguments. Each file will be tweaked as needed.
# It should work on Windows and MacOS X as well as Linux, provided
# you have Python installed.
#
# This script will emit a report line for each file it modifies,
# and save a backup copy of the original with extension "-bak".
#
# This script will tell you when it is obsolete. Run it against all .po
# files in the main Wesnoth tree; when it says none are older than this script,
# it can be discarded (assunming that it has in fact been used to transform
# all incoming .po files in the meantime).
#
# Example usage:
# utils/pofix.py po/wesnoth*/*.po*
# find data/campaigns/ -name '*.cfg' -print0 | xargs -0 utils/pofix.py
#
# To make use of >1 CPU core, you have to rely on xargs. In this sample 10 files
# are handed over to 4 instances of pofix.py:
# ls po/wesnoth*/*.po* | xargs -P 4 -n 10 ./utils/pofix.py
#
#
# Please do make sure to add a comment before any new blocks of conversions
# that states when it was added (current version number is enough) so that
# the file can be cleaned up more easily every now and then.
# Example:
# # conversion added in 1.9.5+svn
# ("foo addwd bar", "foo added bar"),
# # conversion added in 1.9.8+svn
# ("fooba foo", "foobar foo"),
stringfixes = {
"1.8-announcement" : (
# conversion added shortly before 1.8.0, might be relevant for the 1.10.0 announcement
("WML events an AI components", "WML events and AI components"),
("1.7.3", "1.7.13"),
("/tags/1.8/", "/tags/1.8.0/"),
),
"1.10-announcement" : (
("roleplaying", "role-playing"),
),
}
# Speak, if all argument files are newer than this timestamp
# Try to use UTC here
# date --utc "+%s # %c"
timecheck = 1283156523 # Mo 30 Aug 2010 08:22:03 UTC
import os, sys, time, stat, re
try:
from multiprocessing import Pool, cpu_count
def parallel_map(*args, **kw):
pool = Pool(cpu_count())
return pool.map(*args, **kw)
except ImportError:
print "Failed to import 'multiprocessing' module. Multiple cpu cores won't be utilized"
parallel_map = map
def process_file(path):
before = open(path, "r").read()
decommented = re.sub("#.*", "", before)
lines = before.split('\n')
for (domain, fixes) in stringfixes.items():
# In case of screwed-up pairs that are hard to find, uncomment the following:
#for fix in fixes:
# if len(fix) != 2:
# print fix
for (old, new) in fixes:
if old is new:
#complain loudly
print "pofix: old string\n\t\"%s\"\n equals new string\n\t\"%s\"\nexiting." % (old, new)
sys.exit(1)
#this check is problematic and the last clause is added to prevent false
#positives in case that new is a substring of old, though this can also
#lead to "real" probs not found, the real check would be "does replacing
#old with new lead to duplicate msgids? (including old ones marked with #~)"
#which is not easily done in the current design...
elif new in decommented and old in decommented and not new in old:
print "pofix: %s already includes the new string\n\t\"%s\"\nbut also the old\n\t\"%s\"\nthis needs handfixing for now since it likely creates duplicate msgids." % (path, new, old)
else:
for (i, line) in enumerate(lines):
if line and line[0] != '#':
lines[i] = lines[i].replace(old, new)
after = '\n'.join(lines)
if after != before:
print "pofix: %s modified" % path
# Save a backup
os.rename(path, path + "-bak")
# Write out transformed version
ofp = open(path, "w")
ofp.write(after)
ofp.close()
return 1
else:
return 0
if __name__ == '__main__':
newer = 0
modified = 0
pocount = 0
files = []
for path in sys.argv[1:]:
if not path.endswith(".po") and not path.endswith(".pot") and not path.endswith(".cfg"):
continue
pocount += 1
# Notice how many files are newer than the time check
statinfo = os.stat(path)
if statinfo.st_mtime > timecheck:
newer += 1
files.append(path)
modified = sum(parallel_map(process_file, files))
print "pofix: %d files processed, %d files modified, %d files newer" \
% (pocount, modified, newer)
if pocount > 1 and newer == pocount:
print "pofix: script may be obsolete"