-
-
Notifications
You must be signed in to change notification settings - Fork 76
/
Copy pathlocalizations.py
139 lines (115 loc) · 5.2 KB
/
localizations.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
import os
import argparse
import re
import glob
from pathlib import Path
# example usages:
# python localizations.py generate
# python localizations.py validate
parser = argparse.ArgumentParser()
parser.add_argument('command', type=str, help="Possible options: generate | validate")
arguments = parser.parse_args()
command = arguments.command
if command not in ['generate', 'validate']:
parser.print_help()
exit()
input_file_name = Path("Support/en.lproj/Localizable.strings")
comment_file_name = Path("Support/qqq.lproj/Localizable.strings")
enum_name = "LocalString"
target_dir = "Support"
template_file_name = "StringLocalExtension.swift_temp"
class Generate:
def __init__(self, input_file_name, template_file, enum_name, target_dir):
self.enum_name = enum_name
reader = Reader(input_file_name)
vars = self.__variables(reader)
with open(os.path.join(target_dir, template_file)) as template_file:
template_content = template_file.read()
output_path = os.path.join(target_dir, enum_name + ".swift")
file = open(output_path, 'w')
file.write("""//
// !! DO NOT EDIT THIS FILE DIRECTLY !!
// !! IT HAS BEEN AUTO-GENERATED !!
//
""")
file.write(template_content)
file.write(self.__code_for("\n\t".join(vars)))
file.close()
def __variables(self, reader):
vars = list()
for key, has_arguments in sorted(reader.keys()):
if has_arguments:
vars.append(self.__static_func_for(key))
else:
vars.append(self.__static_let_for(key))
return vars
def __code_for(self, variables):
return """enum {} {{
{}
}}
""".format(self.enum_name, variables)
def __static_let_for(self, key):
return """static let {} = "{}".localized""".format(self.__get_var_name(key), key)
def __static_func_for(self, key):
return """static func {}(withArgs args: CVarArg...) -> String {{ "{}".localizedWithFormat(withArgs: args) }}""".format(self.__get_var_name(key), key)
def __get_var_name(self, key):
return re.sub('[^a-z0-9]', '_', key.lower())
class Reader:
def __init__(self, input_file_name):
self.input_file_name = input_file_name
def keys(self):
pattern = re.compile(r'"(?P<key>.+)"\s{1,}=\s{1,}"(?P<value>.+)"')
with open(self.input_file_name) as input_file:
for line in input_file:
match = pattern.match(line)
if match:
groups = match.groupdict()
key = groups.get('key')
value = groups.get('value')
has_arguments = "%@" in value
yield key, has_arguments
class Validate:
def __init__(self, input_file_name, comment_file_name, enum_name, search_directory=os.getcwd()):
reader = Reader(input_file_name)
vars = list()
for key, _ in reader.keys():
assert "." in key, "Invalid translation key: {}, it should contain at least one '.' (dot)".format(key)
vars.append(key)
vars = sorted(vars)
matches = dict()
counter = dict()
for var in vars:
swift_var = self.__get_var_name(var)
counter[swift_var] = 0
for swift_file_name in glob.iglob(os.path.join(search_directory, '**/*.swift'), recursive=True):
if Path(swift_file_name).name != "{}.swift".format(enum_name):
with open(swift_file_name, 'r') as swift_file:
content = swift_file.read()
for var in vars:
if var in content:
if var in matches:
matches[var].append(swift_file_name)
else:
matches[var] = [swift_file_name]
swift_var = self.__get_var_name(var)
if swift_var in content:
counter[swift_var] += 1
assert len(matches.keys()) == 0, "localization strings cannot not be directly used in swift (use LocalString instead): {}".format(matches)
unused_swift_vars = {k: v for k, v in counter.items() if v == 0 }.keys()
assert len(unused_swift_vars) == 0, "unused localizations entries (delete them from localizations, and run: python localizations.py generate): {}".format(sorted(unused_swift_vars))
comment_keys = list()
comment_reader = Reader(comment_file_name)
for comment_key, _ in comment_reader.keys():
assert comment_key in vars, "extra qqq key found: {}".format(comment_key)
comment_keys.append(comment_key)
missing = sorted(set(vars).difference(comment_keys))
assert len(missing) == 0, "undocumented keys (please add them to qqq): {}".format(missing)
def __get_var_name(self, key):
return re.sub('[^a-z0-9]', '_', key.lower())
match command:
case "generate":
Generate(input_file_name, template_file_name, enum_name, target_dir)
case "validate":
Validate(input_file_name, comment_file_name, enum_name)
case _:
exit(-1)