forked from exoplatform/mobile-ios
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathobjc_strings.py
executable file
·189 lines (126 loc) · 5 KB
/
objc_strings.py
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
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#!/usr/bin/env python
# Nicolas Seriot
# 2011-05-09 - 2011-12-10
# https://github.com/nst/objc_strings/
"""
Goal: helps Cocoa applications localization by detecting unused and missing keys in '.strings' files
Input: path of an Objective-C project
Output:
1) warnings for untranslated strings in *.m
2) warnings for unused keys in Localization.strings
3) errors for keys defined twice or more in the same .strings file
Typical usage: $ python objc_strings.py /path/to/obj_c/project
Xcode integration:
1. make `objc_strings.py` executable
$ chmod +x objc_strings.py
2. copy `objc_strings.py` to the root of your project
3. add a "Run Script" build phase to your target
4. move this build phase in second position
5. set the script path to `${SOURCE_ROOT}/objc_strings.py`
6. ensure your .strings file are encoded in utf-8
"""
import sys
import os
import re
import codecs
def warning(file_path, line_number, message):
print "%s:%d: warning: %s" % (file_path, line_number, message)
def error(file_path, line_number, message):
print "%s:%d: error: %s" % (file_path, line_number, message)
m_paths_and_line_numbers_for_key = {} # [{'k1':(('f1, n1'), ('f1, n2'), ...), ...}]
s_paths_and_line_numbers_for_key = {} # [{'k1':(('f1, n1'), ('f1, n2'), ...), ...}]
def language_code_in_strings_path(p):
m = re.search(".*/(.*?.lproj)/", p)
if m:
return m.group(1)
return None
def key_in_string(s):
m = re.search("(?u)^\"(.*?)\"", s)
if not m:
return None
key = m.group(1)
if key.startswith("//") or key.startswith("/*"):
return None
return key
def key_in_code_line(s):
m = re.search("Localize\(@\"(.*?)\"", s)
if not m:
return None
key = m.group(1)
return key
def keys_set_in_strings_file_at_path(p):
keys = set()
f = codecs.open(p, encoding='utf-8')
line = 0
for s in f.xreadlines():
line += 1
if s.strip().startswith('//'):
continue
s = s.decode("utf-8", "ignore")
key = key_in_string(s)
if not key:
continue
if key in keys:
error(p, line, "key already defined: \"%s\"" % key)
continue
keys.add(key)
if key not in s_paths_and_line_numbers_for_key:
s_paths_and_line_numbers_for_key[key] = set()
s_paths_and_line_numbers_for_key[key].add((p, line))
return keys
def localized_strings_at_path(p):
f = open(p)#codecs.open(p, encoding='utf-8')
keys = set()
line = 0
for s in f.xreadlines():
line += 1
if s.strip().startswith('//'):
continue
s = unicode(s, 'utf-8') #s.decode('utf-8', 'ignore')
key = key_in_code_line(s)
if not key:
continue
keys.add(key)
if key not in m_paths_and_line_numbers_for_key:
m_paths_and_line_numbers_for_key[key] = set()
m_paths_and_line_numbers_for_key[key].add((p, line))
return keys
def paths_with_files_passing_test_at_path(test, path):
for root, dirs, files in os.walk(path):
for p in (os.path.join(root, f) for f in files if test(f)):
yield p
def keys_set_in_code_at_path(path):
m_paths = paths_with_files_passing_test_at_path(lambda f:f.endswith('.m'), path)
localized_strings = set()
for p in m_paths:
keys = localized_strings_at_path(p)
localized_strings.update(keys)
return localized_strings
def show_untranslated_keys_in_project(project_path):
if not project_path or not os.path.exists(project_path):
error("", 0, "bad project path:%s" % project_path)
return
keys_set_in_code = keys_set_in_code_at_path(project_path)
strings_paths = paths_with_files_passing_test_at_path(lambda f:f == "Localizable.strings", project_path)
for p in strings_paths:
keys_set_in_strings = keys_set_in_strings_file_at_path(p)
missing_keys = keys_set_in_code - keys_set_in_strings
unused_keys = keys_set_in_strings - keys_set_in_code
language_code = language_code_in_strings_path(p)
for k in missing_keys:
message = "missing key in %s: \"%s\"" % (language_code, k)
for (p_, n) in m_paths_and_line_numbers_for_key[k]:
warning(p_, n, message)
for k in unused_keys:
message = "unused key in %s: \"%s\"" % (language_code, k)
for (p, n) in s_paths_and_line_numbers_for_key[k]:
warning(p, n, message)
def main():
project_path = None
if 'PROJECT_DIR' in os.environ:
project_path = os.environ['PROJECT_DIR']
elif len(sys.argv) > 1:
project_path = sys.argv[1]
show_untranslated_keys_in_project(project_path)
if __name__ == "__main__":
main()