xwords/xwords4/android/scripts/copy-strings.py
Eric House 5ef7495d51 The Japanese translation has a number of plurals with "one" quantities
but no "other", which crashes. "Fix" these by making the copy script
turn one into other, which may well make sense given Japanese
grammer. At any rate it prevents crashes until I can work it out with
the translator and/or weblate.
2016-01-23 21:59:31 -08:00

221 lines
7.1 KiB
Python
Executable file

#!/usr/bin/python
# Go through all the res_src strings.xml files, and copy them over
# into the world where they'll get used in a build. This is meant to
# allow them to be built-in as an alternative to the
# locutils/downloadable system.
import re, sys, os, getopt
from lxml import etree
s_prefix = 'XLATE ME: '
# languages in which it's ok to make a standalone quantity="one" into
# quantity="other"
g_oneToOthers = ['values-ja']
sComment = """
DO NOT EDIT THIS FILE!!!!
It was generated (from %s).
Any changes you make to it will be lost.
"""
def sameOrSameWithPrefix( str1, str2 ):
result = str1 == str2
if not result:
if str1.startswith(s_prefix):
result = str1[len(s_prefix):] == str2
return result
def sameAsEnglishPlural(engNames, strElem):
strs = engNames[strElem.get('name')]['strings']
str = strElem.text
result = 1 == len(strs) and 'other' in strs \
and sameOrSameWithPrefix( str, strs['other'] )
return result
# If has a one and no (or empty) other, convert the one to other
def tryConvertOne( plurals ):
quantities = {}
for item in plurals.getchildren():
quantities[item.get("quantity")] = item
use = False
if "one" in quantities:
if "other" in quantities:
text = quantities['other'].text
if not text or 0 == len(text):
use = True
else:
use = True
if use:
print "converting", plurals.get('name')
plurals.remove(quantities['other'])
quantities['one'].set('quantity', 'other')
def pluralsIsBogus(engNames, plurals, verbose):
haveOther = False # will crash without one
bogus = False
for item in plurals.getchildren():
text = item.text
if not text or 0 == len(text):
bogus = True
if verbose:
quantity = item.get("quantity")
print 'dropping plurals {name} because of empty/missing \"{quantity}\"' \
.format(name=plurals.get("name"), quantity=quantity )
break
if item.get("quantity") == "other":
haveOther = True
if verbose and not bogus and not haveOther:
print "dropping plurals {name} because no \"other\" quantity" \
.format(name=plurals.get("name"))
return bogus or not haveOther
def pluralsIsSame(engNames, plurals):
different = False # all children duplicates of English
engItem = engNames[plurals.get('name')]
strings = engItem['strings']
for item in plurals.getchildren():
text = item.text
if not text or 0 == len(text):
print "bogus empty plurals item in", plurals.get('name')
engItem = engItem
sys.exit(1)
quantity = item.get('quantity')
if quantity in strings:
if sameOrSameWithPrefix( strings[quantity], text ):
different = True
return different
# path will be something like res_src/values-pt/strings.xml. We want
# the next-to-last entry.
def valuesDir( path ):
splits = path.split('/')
return splits[-2]
def checkPlurals( engNames, elem, src, verbose ):
name = elem.get('name')
ok = True
if not name in engNames or not 'plurals' == engNames[name]['type']:
print 'plurals', name, 'not in engNames or not a plurals there'
ok = False
if ok and valuesDir(src) in g_oneToOthers:
tryConvertOne( elem )
if ok and pluralsIsBogus(engNames, elem, verbose):
ok = False
if ok and pluralsIsSame(engNames, elem):
ok = False
if ok:
for item in elem.getchildren():
if 0 == len(item.text):
ok = False
print 'bad empty item', name
sys.exit(1)
return ok
def loadPlural(plural):
items = {}
for child in plural.getchildren():
items[child.get('quantity')] = child.text
return items
def writeDoc(doc, src, dest):
comment = etree.Comment(sComment % (src))
doc.getroot().insert( 0, comment )
dir = os.path.dirname( dest )
try: os.makedirs( dir )
except: pass
out = open( dest, "w" )
out.write( etree.tostring( doc, pretty_print=True, encoding="utf-8", xml_declaration=True ) )
def checkOrConvertString(engNames, elem, verbose):
name = elem.get('name')
if not elem.text:
print "elem", name, "is empty"
sys.exit(1)
elif not name in engNames or elem.text.startswith(s_prefix):
ok = False
elif not 'string' == engNames[name]['type']:
if 'plurals' == engNames[name]['type']:
if sameAsEnglishPlural( engNames, elem ):
ok = False
else:
elem.tag = 'plurals'
item = etree.Element("item")
item.text = elem.text
elem.text = None
item.set('quantity', 'other')
elem.append( item )
if verbose: print 'translated string', name, 'to plural'
ok = True
else:
ok = False
elif sameOrSameWithPrefix(engNames[name]['string'], elem.text ):
if verbose: print "Same as english: name: %s; text: %s" % (name, elem.text)
ok = False
else:
ok = True
return ok
def checkAndCopy( parser, engNames, src, dest, verbose ):
doc = etree.parse(src, parser)
# strings
for elem in doc.findall('string'):
if not checkOrConvertString(engNames, elem, verbose):
elem.getparent().remove(elem)
for elem in doc.findall('plurals'):
if not checkPlurals(engNames, elem, src, verbose):
elem.getparent().remove(elem)
writeDoc(doc, src, dest)
def main():
# add these via params later
excepts = ['values-ca_PS', 'values-ba_CK']
verboses = ['values-ja']
# summarize the english file
wd = os.path.dirname(sys.argv[0])
path = wd + '/../XWords4/res/values/strings.xml'
engNames = {}
engFormats = {}
parser = etree.XMLParser(remove_blank_text=True, encoding="utf-8")
engDoc = etree.parse(path, parser)
pat = re.compile( '(%\d\$[sd])', re.DOTALL | re.MULTILINE )
for typ in ['string', 'plurals']:
for elem in engDoc.findall(typ):
name = elem.get('name')
item = { 'type' : typ }
if typ == 'string':
item['string'] = elem.text
else:
item['strings'] = loadPlural(elem)
engNames[name] = item
# print engNames
# iterate over src files
for subdir, dirs, files in os.walk('res_src'):
for file in [file for file in files if file == "strings.xml"]:
path = "%s/%s" % (subdir, file)
for excpt in excepts:
if excpt in path :
path = None
break
if path:
verbose = 0 == len(verboses) or 0 < len([verb for verb in verboses if verb in path])
print "*** looking at %s ***" % (path)
dest = path.replace( 'res_src', 'res', 1 )
checkAndCopy( parser, engNames, path, dest, verbose )
##############################################################################
if __name__ == '__main__':
main()