Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 18 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

**ams** (android-missing-strings) is a simple command line reporting tool to know what strings need to be translated on an android project.

The output of ams is a pdf file friendly to a non-coding person who can be in charge of managing the translators involved in the project.
The output of ams is a text file friendly to a non-coding person who can be in charge of managing the translators involved in the project.

It can also be used to delete left over translation entries that have been deleted from your main string.xml

## Requirements
- Python 2.6+
- [pyPDF](https://code.google.com/p/pyfpdf/)


## Installation
Make sure you have the **ams** source folder on your $PATH environment variable.
Expand All @@ -15,7 +17,10 @@ Make sure you have the **ams** source folder on your $PATH environment variable.
from within any android project, just execute

```bash
ams [-l xx[,yy,zz...]] -o <output_file>
ams - Android Missing Strings reporting tool.

Usage:
ams [-l xx[,yy,zz...]] [--cleanleftovers] -o <output_file>

Options:
-h --help Print this help
Expand All @@ -29,11 +34,19 @@ ams [-l xx[,yy,zz...]] -o <output_file>
If this parameter is ommited, a report with every language file found will be created.


-o --oFile Specify the output file name for the PDF report
-o --oFile Specify the output file name for the report

--cleanleftovers Removes left over translations on other language files

Copyright (c) 2014-2017 - The Mit License (MIT)

Authors:
Angel Leon <gubatron@gmail.com>
Katay Santos <kataysantos@gmail.com>
```

## License
Copyright (c) 2014 - The Mit License (MIT)
Copyright (c) 2014-2017 - The Mit License (MIT)

## Authors
- [Angel Leon](https://github.com/gubatron/)
Expand Down
138 changes: 93 additions & 45 deletions ams
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
#!/usr/bin/env python
#!/usr/bin/env python3
# authors: Angel Leon (@gubatron), Katay Santos (@cateye), Bohdan Horbeshko (@bodqhrohro)

import re
import os
import sys
import getopt
from fpdf import FPDF

PATTERN=re.compile(r'<string name="(.*?)".*>(.*?)</string>', re.I | re.MULTILINE)
from time import gmtime
import xml.etree.ElementTree as ET

class MissingStringsReport:
filePath = None
Expand All @@ -20,12 +21,17 @@ class MissingStringsReport:
self.stringsFilePath = stringsFilePath
self.originalStringsDict = originalStringsDict
self.myStringsDict = MissingStringsReport.readXML(self.stringsFilePath)
self.missingKeys = MissingStringsReport.findMissingKeys(self.originalStringsDict, self.myStringsDict)
self.missingKeys = MissingStringsReport.findMissingKeys(self.originalStringsDict, self.myStringsDict)
self.leftOverKeys = MissingStringsReport.findLeftoverKeys(self.originalStringsDict, self.myStringsDict)

def getMissingKeys(self):
'''Returns a list with the missing keys.'''
return self.missingKeys

def getLeftoverKeys(self):
'''Returns a list of left over keys that should be deleted'''
return self.leftOverKeys

def getMyStringsDict(self):
return self.myStringsDict

Expand All @@ -42,34 +48,56 @@ class MissingStringsReport:
missingKeys.append(k)
return missingKeys

@staticmethod
def findLeftoverKeys(fullDict, incompleteDict):
'''Given the original (fullDict) strings dictionary, this returns a list of the keys that no longer exist on the
full dictionary but still exist on the incompleteDict'''
leftOverKeys = []
for k in incompleteDict:
if k not in fullDict:
leftOverKeys.append(k)
return leftOverKeys

@staticmethod
def readXML(fileName):
result={}
global PATTERN
f=open(fileName,'r')
line = f.readline()
while line!="":
matcher = PATTERN.search(line)
if matcher != None:
result[matcher.group(1)]=matcher.group(2)
line = f.readline()
f.close()
tree = ET.parse(fileName)
root = tree.getroot()
for string in root.findall('string'):
if 'translatable' not in string.attrib or string.attrib['translatable'] != 'False':
result[string.attrib['name']] = string.text
return result


def getStringsFilePaths():
'''Gets all the relative paths to strings.xml files in a list.'''
p = os.popen("find . | grep strings.xml")
p = os.popen("find ./res | grep strings.xml")
filesPath = p.readlines()
p.close()
return filesPath

def cleanLeftoverTranslations(filePath, leftOverKeys):
print("Cleaning " + str(len(leftOverKeys)) + " leftover translations in " + filePath + "\n")
print(leftOverKeys)
print("="*80)

tree = ET.parse(filePath)
root = tree.getroot()

for string in root.findall('string'):
if string.attrib['name'] in leftOverKeys:
root.remove(string)

tmpFilePath = filePath + '.tmp'
tree.write(tmpFilePath, encoding='utf-8', xml_declaration=True)
os.rename(tmpFilePath, filePath)

def usage():
usage = """
ams - Android Missing Strings reporting tool.

Usage:
ams [-l xx[,yy,zz...]] -o <output_file>
ams [-l xx[,yy,zz...]] [--cleanleftovers] -o <output_file>

Options:
-h --help Print this help
Expand All @@ -83,30 +111,33 @@ def usage():
If this parameter is ommited, a report with every language file found will be created.


-o --oFile Specify the output file name for the PDF report
-o --oFile Specify the output file name for the report

Copyright (c) 2014 - The Mit License (MIT)
--cleanleftovers Removes left over translations on other language files

Copyright (c) 2014-%d - The Mit License (MIT)

Authors:
Angel Leon <gubatron@gmail.com>
Katay Santos <kataysantos@gmail.com>

"""
print usage
""" % (gmtime()[0])
print(usage)

def main(argv):
xmlFilePaths=[]
outputFile = ''
cleanLeftovers = False
try:
opts, args = getopt.getopt(argv, "ho:l:",["ofile=","lang="])
opts, args = getopt.getopt(argv, "ho:l:",["ofile=","lang=","cleanleftovers"])
except getopt.GetoptError:
print "unhandled option"
print("unhandled option")
usage()
sys.exit(2)

if len(opts) == 0:
usage()
print "Error: missing parameters."
print("Error: missing parameters.")
sys.exit(2)

for opt, arg in opts:
Expand All @@ -124,10 +155,12 @@ def main(argv):
xmlFilePaths.append("./res/values-" + l + "/strings.xml")
else:
xmlFilePaths=["./res/values-" + arg + "/strings.xml"]
if opt in ("--cleanleftovers"):
cleanLeftovers = True

if outputFile == '':
usage()
print "Error: missing -o (output file) parameter."
print("Error: missing -o (output file) parameter.")
sys.exit(2)

if len(xmlFilePaths) == 0:
Expand All @@ -136,33 +169,48 @@ def main(argv):
xmlOriginalFile="./res/values/strings.xml"
originalDict=MissingStringsReport.readXML(xmlOriginalFile)

pdf=FPDF()
pdf.add_page()
fd = open(outputFile,'w')

# in case we're going to clean up, we don't need to re-calculate reports
# if we keep them in this dictionary (path -> MissingStringReport)
missingStringReports = {}

for xmlFilePath in xmlFilePaths:
filePath = xmlFilePath.strip()

if filePath != xmlOriginalFile:
report = MissingStringsReport(filePath, originalDict)
print "Generating report for " + filePath + "..."
pdf.set_font('Arial','B',12)
pdf.cell(100,10,"Language file: " + filePath,0,0)
pdf.cell(40,10,"%d%% completed " % (report.getCompletePercentage()),0,1,'R')
pdf.cell(40,10,"Missing elements: ",0,1)

for missingKey in report.getMissingKeys():
pdf.set_font('Arial','I',8)
tag = "<string name=\"%s\">%s</string>" % (missingKey, originalDict[missingKey])
pdf.multi_cell(190,10,tag,1,1)

pdf.add_page()

pdf.output(outputFile,'F')
print "\nSuccess: Android Missing String report ready at " + outputFile

if cleanLeftovers:
missingStringReports[filePath] = report
print("Generating report for " + filePath + "...")
fd.write("Language file: " + filePath + "\n")
fd.write("%d%% completed " % (report.getCompletePercentage()) + "\n")

if len(report.getMissingKeys()) > 0:
fd.write("Missing elements: \n\n")
for missingKey in report.getMissingKeys():
tag = "<string name=\"%s\">%s</string>\n" % (missingKey, originalDict[missingKey])
fd.write(tag)
fd.write("========================================================================\n\n")
if len(report.getLeftoverKeys()) > 0:
fd.write("Leftover elements: \n\n")
for leftoverKey in report.getLeftoverKeys():
tag = u"<string name=\"%s\">...</string>\n" % (leftoverKey)
fd.write(tag)
fd.write("========================================================================\n")
fd.write("\n-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.-.\n\n");
fd.close()
print("\nSuccess: Android Missing String report ready at " + outputFile)

if cleanLeftovers:
print("")
print("="*80)
print("")
for xmlFilePath in xmlFilePaths:
filePath = xmlFilePath.strip()
if filePath != xmlOriginalFile:
report = missingStringReports[filePath]
cleanLeftoverTranslations(filePath, report.getLeftoverKeys())

if __name__ == '__main__':

main(sys.argv[1:])