Created
March 21, 2019 19:11
-
-
Save mmdock/20d89dacdd4bdf6364a4f2cfa134f604 to your computer and use it in GitHub Desktop.
Script to help me compare two .strings files. Use during Xcode build phase to ensure localizations contain all keys
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
import codecs | |
import optparse | |
import os | |
import re | |
""" | |
This small script compares Cocoa / iOS development Localizable.strings files. | |
These are usually UTF-16 and difficult to compare. In addition to that, | |
the order of the contents of the files varies per export, making diff very | |
difficult. This script reads all keys and compares them unrelated of order | |
It is based on diffstrings.py | |
(https://raw.github.com/facebook/three20/master/diffstrings.py) | |
but far easier. diffstrings does all kinds of fancy things like reading | |
an xcode project, and whatnot. I really just wanted to compare two .strings | |
files. | |
""" | |
# the default local file if no options are provided | |
default_localfile = "./Her/Base.lproj/Localizable.strings" | |
# the default other file if no options are provided | |
default_otherfile = "./Her/fr.lproj/Localizable.strings" | |
def openWithProperEncoding(path): | |
if not os.path.isfile(path): | |
return [] | |
try: | |
f = codecs.open(path, 'r', 'utf-16') | |
lines = f.read().splitlines() | |
f.close() | |
except UnicodeError: | |
f = codecs.open(path, 'r', 'utf-8') | |
lines = f.read().splitlines() | |
f.close() | |
return lines | |
def findKeys(path): | |
reString = re.compile(r'\s*"((\\.|.)+?)"\s*=\s*"(.+?)";') | |
keys = [] | |
keyTable = {} | |
for line in openWithProperEncoding(path): | |
m = reString.search(line) | |
if m: | |
source = m.groups()[0] | |
keys.append(source) | |
keyTable[source] = line | |
return (keys, keyTable) | |
def compareKeysForLocals(lc1, lc2, detailed=False): | |
error = False | |
def missingKeys(k1, k2): | |
for key in k1: | |
if not key in k2: | |
yield key | |
keys1, keyTable1 = findKeys(lc1) | |
keys2, keyTable2 = findKeys(lc2) | |
print("Number of Base language keys: ", len(keys1)) | |
print("Number of Other language keys: ", len(keys2)) | |
if not detailed: | |
# Non-detailed print | |
for key in missingKeys(keys1, keys2): | |
error = True | |
print ("Other language Missing: ", (key,)) | |
for key in missingKeys(keys2, keys1): | |
error = True | |
print ("Base language Missing: ", (key,)) | |
else: | |
# Detailed Print | |
print ("-----------------Base-----------------------") | |
for key in missingKeys(keys1, keys2): | |
error = True | |
print (keyTable1.get(key)) | |
print ("-----------------Other----------------------") | |
for key in missingKeys(keys2, keys1): | |
error = True | |
print (keyTable2.get(key)) | |
if error: | |
raise ValueError("Localization Error") | |
def parseOptions(): | |
usage = """usage: %prog [options] | |
difflocal commpares two local files: your primary local that contains all the additions from your work on the project, and another local which doesn't contain the additions yet. | |
It will compare the two files and list all the additions. The arguments are the paths of the two Localizable.strings files.""" | |
parser = optparse.OptionParser(usage) | |
parser.set_defaults(originalLocaleFile=default_localfile, | |
otherLocalFile=default_otherfile, detailed=False) | |
parser.add_option("-l", "--originalLocaleFile", dest="originalLocaleFile", type="str", | |
help = "The filename of your source locale. The default is 'en'.") | |
parser.add_option("-o", "--otherLocalFile", dest="otherLocalFile", type="str", | |
help = "The filename of the other locale to operate on") | |
parser.add_option("-d", "--detailed", dest="detailed", type="int", | |
help = "Should the script also print the complete missing line") | |
options, arguments = parser.parse_args() | |
return options | |
def main(): | |
options = parseOptions() | |
print(options.originalLocaleFile) | |
if options.originalLocaleFile and options.otherLocalFile: | |
compareKeysForLocals(options.originalLocaleFile, | |
options.otherLocalFile, | |
options.detailed) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment