This repository was archived by the owner on Feb 29, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 21
Expand file tree
/
Copy pathdpstrings.py
More file actions
executable file
·162 lines (127 loc) · 5.9 KB
/
dpstrings.py
File metadata and controls
executable file
·162 lines (127 loc) · 5.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
import io
import argparse
import codecs
import os
import re
class DPStringExtractor:
pattern_src_1 = re.compile("(?<=DPLocalizedString\(@\").*?(?=\")")
pattern_src_2 = re.compile(".*?\.autolocalizationKey\s*=\s*@?\"(.*?)\"")
pattern_src_3 = re.compile("\[.*?\ssetAutolocalizationKey:\s*@\"(.*?)\"\]")
pattern_src_4 = re.compile(".*?\sautolocalizationKey\s*=\s*@?\"(.*?)\"")
pattern_src_5 = re.compile("(?<=DPLocalizedString\(\").*?(?=\")")
pattern_xib_1 = re.compile(
"<string\skey=\"keyPath\">autolocalizationKey</string>\s*<string\skey=\"value\">(.*?)</string>")
pattern_xib_2 = re.compile(
"<userDefinedRuntimeAttribute\stype=\"string\"\skeyPath=\"autolocalizationKey\"\svalue=\"(.*?)\"/>")
@staticmethod
def is_source_file(filename):
extension = os.path.splitext(filename)[1].lower()
return extension == ".m" or extension == ".mm" or extension == ".swift"
@staticmethod
def is_xib_file(filename):
extension = os.path.splitext(filename)[1].lower()
return extension == ".xib" or extension == ".storyboard"
def __init__(self):
self.strings_info = {}
def add_strings(self, strings, path):
for string in strings:
if not self.strings_info.has_key(string):
self.strings_info[string] = []
self.strings_info[string].append(path)
def extract_strings(self, path, patterns):
all_results = []
text = codecs.open(path, encoding='utf-8').read()
for pattern in patterns:
result = pattern.findall(text)
if len(result):
all_results.extend(result)
self.add_strings(all_results, path)
def scan_dir(self, dir_path):
files = os.listdir(dir_path)
for filename in files:
full_path = os.path.join(dir_path, filename)
if os.path.isfile(full_path):
patterns = None
if DPStringExtractor.is_source_file(filename):
patterns = [self.pattern_src_1, self.pattern_src_2, self.pattern_src_3, self.pattern_src_4, self.pattern_src_5]
elif DPStringExtractor.is_xib_file(filename):
patterns = [self.pattern_xib_1, self.pattern_xib_2]
if patterns is not None:
self.extract_strings(full_path, patterns)
else:
self.scan_dir(full_path)
return self.strings_info
class DPLocalizableStringsParser:
localizable_str_1 = re.compile("\"(.*?)\"\s*=\s*\"(.*?)\";")
@staticmethod
def is_strings_file(filename):
return filename == "Localizable.strings"
#extension = os.path.splitext(filename)[1].lower()
#return extension == ".strings"
def __init__(self):
self.strings_info = {}
def extract_strings(self, path, patterns, nil=None):
locale_pattern = re.compile("(?<=/)[a-zA-Z_]*(?=\.lproj/)")
locale = locale_pattern.findall(path)[0]
try:
text = io.open(path, 'r', encoding = 'utf-8').read()
except UnicodeDecodeError:
text = None
if text == None:
try:
text = io.open(path, 'r', encoding = 'utf-16').read()
except UnicodeError:
text = None
print u"WARNING: File \"{0}\" contains non UTF-8/UTF-16 characters, and will be ignored".format(path)
if text != None:
for pattern in patterns:
result = pattern.findall(text)
for kv_tuple in result:
if len(kv_tuple) == 2:
key, value = kv_tuple
if not self.strings_info.has_key(key):
self.strings_info[key] = {}
if not self.strings_info[key].has_key(locale):
self.strings_info[key][locale] = value
else:
print u"WARNING: Duplicate key: \"{0} in file \"{1}\"".format(key, path)
def scan_dir(self, dir_path):
files = os.listdir(dir_path)
for filename in files:
full_path = os.path.join(dir_path, filename)
if os.path.isfile(full_path):
patterns = None
if DPLocalizableStringsParser.is_strings_file(filename):
patterns = [self.localizable_str_1]
if patterns is not None:
self.extract_strings(full_path, patterns)
else:
self.scan_dir(full_path)
return self.strings_info
if __name__ == '__main__':
parser = argparse.ArgumentParser(description='''Usage example: dpstrings.py -p "./Project" -l "en;ru;"''')
parser.add_argument("-l", help='''List of localizations (i.e. ru, en, fr, de) separated by ';'. Default value is "en"''', default="en")
parser.add_argument("-p", help='''Search path. Default value is "./"''', default="./")
args = parser.parse_args()
search_path = args.p
locales = set()
for loc in args.l.split(";"):
loc = loc.strip()
if len(loc):
locales.add(loc)
used_strings = DPStringExtractor().scan_dir(search_path)
local_strings = DPLocalizableStringsParser().scan_dir(search_path)
sorted_keys = sorted(local_strings)
sorted_used_strings = sorted(used_strings)
for key in sorted_keys:
string_info = local_strings[key]
string_locales = string_info.keys()
if not locales.issubset(string_locales):
print u"WARNING: Not enough localizations for key: {0}. Exist locales: {1}".format(key, string_info.keys())
for key in sorted_keys:
if not used_strings.has_key(key):
print u"WARNING: Not used key: \"{0}\"".format(key)
for key in sorted_used_strings:
if not local_strings.has_key(key):
paths = u"; ".join(set(used_strings[key]))
print u"WARNING: No localization for key: \"{0}\" in {1}".format(key, paths)