lokale 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/a.sh +4 -0
- data/bin/lokale +2 -60
- data/lib/lokale/.lokale +16 -0
- data/lib/lokale/agent.rb +231 -0
- data/lib/lokale/config.rb +68 -0
- data/lib/lokale/find_dir.rb +51 -30
- data/lib/lokale/lokalefile.rb +98 -0
- data/lib/lokale/model.rb +137 -0
- data/lib/lokale/reporter.rb +102 -0
- data/lib/lokale/util.rb +16 -0
- data/lib/lokale/version.rb +1 -1
- data/lib/lokale.rb +52 -273
- data/lokale.gemspec +2 -0
- data/test.sh +1 -0
- metadata +26 -4
- data/lib/lokale/options.rb +0 -70
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1605552979ae04cc32ed6b6eae40be4491cb6d43
|
4
|
+
data.tar.gz: 240de056b27a37bd6b7fc2cf7b07a147ccc0c9b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 272fa81006f2b4f4cf0a0f4066e34d4926433c4998e364604dcc7701f1a0c562e93895acc3050d5d40dfd4af588e900dcebfce5fc5f939ce53b4ce709111e29f
|
7
|
+
data.tar.gz: c9d92c14f1cbef0bf2faa8884d10c3e63a058c9af00664c8be534137171c0375b81adf163579969db4ae866962242de00590f242c43bccf4c33ced8fcf91322a
|
data/a.sh
ADDED
data/bin/lokale
CHANGED
@@ -1,64 +1,6 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
3
|
require 'lokale'
|
4
|
-
require 'lokale/find_dir'
|
5
|
-
require 'lokale/colorize'
|
6
|
-
require 'lokale/options'
|
7
4
|
|
8
|
-
|
9
|
-
|
10
|
-
git_path = find_git_repo
|
11
|
-
if git_path.nil?
|
12
|
-
puts "Could not find any git repository."
|
13
|
-
exit
|
14
|
-
end
|
15
|
-
|
16
|
-
project_name = xcode_project_name(git_path)
|
17
|
-
if project_name.nil?
|
18
|
-
puts "Found git repository (#{git_path}) does not contain an Xcode project."
|
19
|
-
exit
|
20
|
-
end
|
21
|
-
|
22
|
-
puts "Target Xcode project: '#{project_name}'".green
|
23
|
-
|
24
|
-
########################################################################################
|
25
|
-
|
26
|
-
class Action
|
27
|
-
def perform(agent, reporter)
|
28
|
-
send(("perform_" + @type.to_s).to_sym, agent, reporter)
|
29
|
-
end
|
30
|
-
|
31
|
-
def perform_summary(agent, reporter)
|
32
|
-
puts "Printing summary".blue
|
33
|
-
reporter.print_summary
|
34
|
-
end
|
35
|
-
|
36
|
-
def perform_copy_base(agent, reporter)
|
37
|
-
puts "Copying `en` strings files to `Base`".blue
|
38
|
-
agent.copy_base
|
39
|
-
puts
|
40
|
-
end
|
41
|
-
|
42
|
-
def perform_append(agent, reporter)
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
settings = Settings.get
|
50
|
-
|
51
|
-
macros = [
|
52
|
-
Lokale::Macro.new("NSLocalizedString", /NSLocalizedString\("(.+?)",\s*comment:\s*"(.*?)"\)/, "Localizable.strings"),
|
53
|
-
Lokale::Macro.new("PluralString", /String.localizedPlural\("(.+?)"/, nil),
|
54
|
-
#LocalizationMacro.new("ObjC String", /NSLocalizedString\("(.*)",\s*(.*)\)/),
|
55
|
-
#LocalizationMacro.new("ObjC Table String", /NSLocalizedStringFromTableInBundle\((.*?),/)
|
56
|
-
]
|
57
|
-
|
58
|
-
agent = Lokale::Agent.new(git_path, macros)
|
59
|
-
reporter = Lokale::Reporter.new(agent)
|
60
|
-
|
61
|
-
|
62
|
-
settings.actions.each do |action|
|
63
|
-
action.perform(agent, reporter)
|
64
|
-
end
|
5
|
+
main = Lokale::Main.new
|
6
|
+
main.run
|
data/lib/lokale/.lokale
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
|
2
|
+
add_macro "NSLocalizedString" do |m|
|
3
|
+
m.localization_file = "Localizable.strings"
|
4
|
+
|
5
|
+
m.regex = /NSLocalizedString\("(.+?)",\s*comment:\s*"(.*?)"\)/
|
6
|
+
m.key_index = 0
|
7
|
+
m.note_index = 1
|
8
|
+
end
|
9
|
+
|
10
|
+
add_macro "PluralString" do |m|
|
11
|
+
m.regex = /String.localizedPlural\("(.+?)"/
|
12
|
+
m.key_index = 0
|
13
|
+
end
|
14
|
+
|
15
|
+
main_language "en"
|
16
|
+
base_language "Base"
|
data/lib/lokale/agent.rb
ADDED
@@ -0,0 +1,231 @@
|
|
1
|
+
require "lokale/version"
|
2
|
+
require "lokale/colorize"
|
3
|
+
require "lokale/util"
|
4
|
+
require "lokale/model"
|
5
|
+
require "xliffle"
|
6
|
+
require "set"
|
7
|
+
|
8
|
+
|
9
|
+
module Lokale
|
10
|
+
class LFile
|
11
|
+
def repeats
|
12
|
+
return [] if @parsed.nil?
|
13
|
+
uniq_keys = keys.to_set
|
14
|
+
|
15
|
+
keys.delete_if do |k|
|
16
|
+
if uniq_keys.include? k
|
17
|
+
uniq_keys.delete k
|
18
|
+
true
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def keys
|
24
|
+
return nil if parsed.nil?
|
25
|
+
parsed.map(&:key)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class LString
|
30
|
+
def write_format
|
31
|
+
"/* #{note} */\n\"#{key}\" = \"#{str}\";\n"
|
32
|
+
end
|
33
|
+
|
34
|
+
def pretty
|
35
|
+
"\"#{key}\" = \"#{str}\";"
|
36
|
+
end
|
37
|
+
|
38
|
+
attr_accessor :source
|
39
|
+
|
40
|
+
def for_export(lang)
|
41
|
+
str = LString.new(@key, nil, @note, lang)
|
42
|
+
str.source = @str
|
43
|
+
str
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
|
50
|
+
module Lokale
|
51
|
+
class Agent
|
52
|
+
attr_reader :proj_path, :macros, :lfiles, :sfiles_proceeded
|
53
|
+
|
54
|
+
def initialize(proj_path, macros)
|
55
|
+
@proj_path = proj_path
|
56
|
+
@macros = macros
|
57
|
+
|
58
|
+
@writer = Writer.new
|
59
|
+
@exporter = Exporter.new
|
60
|
+
@importer = Importer.new
|
61
|
+
|
62
|
+
get_localization_files
|
63
|
+
find_all_localization_calls
|
64
|
+
end
|
65
|
+
|
66
|
+
###
|
67
|
+
|
68
|
+
def proj_files
|
69
|
+
if block_given?
|
70
|
+
Dir.glob("#{@proj_path}/**/**") { |f| yield f }
|
71
|
+
else
|
72
|
+
Dir.glob("#{@proj_path}/**/**")
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def get_localization_files
|
77
|
+
return @lfiles unless @lfiles.nil?
|
78
|
+
@lfiles = proj_files.map { |file| LFile.try_to_read(file) }.compact
|
79
|
+
end
|
80
|
+
|
81
|
+
def find_all_localization_calls
|
82
|
+
@macros.each { |m| m.clear_calls }
|
83
|
+
|
84
|
+
@sfiles_proceeded = 0
|
85
|
+
proj_files do |file|
|
86
|
+
next unless file.source_file?
|
87
|
+
|
88
|
+
file_content = File.read(file)
|
89
|
+
@macros.each { |macro| macro.read_from file_content }
|
90
|
+
@sfiles_proceeded += 1
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
###
|
95
|
+
|
96
|
+
def copy_base
|
97
|
+
main_lfiles = @lfiles.group_by { |f| f.lang }[Config.get.main_lang].select { |f| f.strings_file? }
|
98
|
+
base_lfiles = @lfiles.group_by { |f| f.lang }[Config.get.base_lang].select { |f| f.strings_file? }
|
99
|
+
|
100
|
+
main_lfiles.each do |en|
|
101
|
+
base = base_lfiles.select { |f| f.full_name == en.full_name }.sample
|
102
|
+
next if base.nil?
|
103
|
+
IO.copy_stream(en.path, base.path)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def append_new_macro_calls
|
108
|
+
@macros.each do |macro|
|
109
|
+
next if macro.localization_file.nil?
|
110
|
+
file = @lfiles.select { |lf| lf.full_name == macro.localization_file && lf.lang == Config.get.main_lang }.sample
|
111
|
+
next if file.nil?
|
112
|
+
|
113
|
+
found_strings = macro.found_strings.keys
|
114
|
+
proj_keys = found_strings.map { |ls| ls.key }.to_set
|
115
|
+
current_keys = file.keys.to_set
|
116
|
+
new_keys = proj_keys - current_keys
|
117
|
+
|
118
|
+
next if new_keys.empty?
|
119
|
+
|
120
|
+
new_lstrings = found_strings.select { |ls| new_keys.include? ls.key }
|
121
|
+
@writer.append_new_strings(new_lstrings, file)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
def export_xliffs
|
126
|
+
files = Config.get.base_lang.nil? ? @lfiles : @lfiles.select { |lf| lf.lang != Config.get.base_lang }
|
127
|
+
main_lang = Config.get.main_lang
|
128
|
+
diffs = Exporter::Diff.find(files, main_lang)
|
129
|
+
@exporter.export(diffs) unless diffs.empty?
|
130
|
+
end
|
131
|
+
|
132
|
+
def try_to_import
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
class Writer
|
137
|
+
def find_append_point(content)
|
138
|
+
ignore_after = content =~ /^\s*?\/\/\s*?\n\s*?\/\/\s*?MARK/
|
139
|
+
string_regexp = /".*?"\s*=\s*".*?"\s*;\s*\n/
|
140
|
+
|
141
|
+
append_at = content.match(string_regexp).end(0) - 1
|
142
|
+
return if append_at.nil?
|
143
|
+
next_try = append_at
|
144
|
+
while next_try < ignore_after
|
145
|
+
append_at = next_try
|
146
|
+
next_try = content.match(string_regexp, next_try).end(0) - 1
|
147
|
+
end
|
148
|
+
|
149
|
+
append_at - 1
|
150
|
+
end
|
151
|
+
|
152
|
+
def append_new_strings(lstrings, file)
|
153
|
+
content = file.content
|
154
|
+
|
155
|
+
puts "Appending #{lstrings.size} new strings to file #{file.lang}/#{file.full_name}".blue
|
156
|
+
lstrings.each { |ls| puts ls.pretty }
|
157
|
+
puts
|
158
|
+
|
159
|
+
append_at = find_append_point(content)
|
160
|
+
data_to_append = "\n" + lstrings.map { |ls| ls.write_format }.join("\n")
|
161
|
+
|
162
|
+
content.insert(append_at, data_to_append)
|
163
|
+
File.write(file.path, content)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
class Exporter
|
169
|
+
class Diff
|
170
|
+
attr_reader :lang, :missing_strings
|
171
|
+
|
172
|
+
def self.find(files, main_lang)
|
173
|
+
groups = files.group_by { |lf| lf.lang }
|
174
|
+
main_files = groups[main_lang]
|
175
|
+
diffs = []
|
176
|
+
groups.each do |lang, files|
|
177
|
+
next if lang == main_lang
|
178
|
+
diffs << Diff.new(main_files, files, lang)
|
179
|
+
end
|
180
|
+
diffs.delete_if { |d| d.empty? }
|
181
|
+
end
|
182
|
+
|
183
|
+
def initialize(main_files, lfiles, lang)
|
184
|
+
@lang = lang
|
185
|
+
@missing_strings = Hash.new { |h, k| h[k] = [] }
|
186
|
+
lfiles.each do |lf|
|
187
|
+
next unless lf.strings_file?
|
188
|
+
counterpart = main_files.select { |m| m.full_name == lf.full_name }.sample
|
189
|
+
next if counterpart.nil?
|
190
|
+
|
191
|
+
missing_keys = counterpart.keys - lf.keys
|
192
|
+
next if missing_keys.empty?
|
193
|
+
|
194
|
+
counterpart.parsed.each do |lstr|
|
195
|
+
next unless missing_keys.include? lstr.key
|
196
|
+
@missing_strings[lf.full_name] << lstr.for_export(lang)
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def empty?
|
202
|
+
@missing_strings.empty? || @missing_strings.all? { |file_name, strings| strings.empty? }
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
def export(diffs)
|
208
|
+
# puts "Exporting stuff"
|
209
|
+
diffs.each do |d|
|
210
|
+
puts "Writing xliff for `#{d.lang}` language. Missing strings count: #{d.missing_strings.values.map { |e| e.size }.reduce(:+)}"
|
211
|
+
|
212
|
+
xliffle = Xliffle.new
|
213
|
+
d.missing_strings.each do |lfile, strings|
|
214
|
+
xfile = xliffle.file(lfile, Config.get.main_lang, d.lang)
|
215
|
+
strings.each do |lstr|
|
216
|
+
xfile.string(lstr.key, lstr.source, nil).note(lstr.note, 0)
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
file_name = "#{d.lang}.xliff"
|
221
|
+
File.write(file_name, xliffle.to_xliff)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
class Importer
|
227
|
+
def look_for_strings(root_path)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
@@ -0,0 +1,68 @@
|
|
1
|
+
|
2
|
+
require "optparse"
|
3
|
+
require "lokale/util"
|
4
|
+
|
5
|
+
class Action
|
6
|
+
attr_accessor :type, :arg
|
7
|
+
|
8
|
+
def initialize(type)
|
9
|
+
@type = type
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.summary; Action.new(:summary) end
|
13
|
+
def self.copy_base; Action.new(:copy_base) end
|
14
|
+
def self.append; Action.new(:append) end
|
15
|
+
def self.export; Action.new(:export) end
|
16
|
+
def self.import; Action.new(:import) end
|
17
|
+
end
|
18
|
+
|
19
|
+
class Config
|
20
|
+
attr_accessor :actions
|
21
|
+
|
22
|
+
def self.init
|
23
|
+
return unless @config.nil?
|
24
|
+
|
25
|
+
actions = []
|
26
|
+
|
27
|
+
OptionParser.new do |opts|
|
28
|
+
opts.banner = "Usage: lokale [-bsh]"
|
29
|
+
|
30
|
+
opts.on("-b", "--copy-base", "Copies 'en' localization files to 'Base'") do |n|
|
31
|
+
actions << Action.copy_base
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-s", "--summary", "Prints project summary") do |n|
|
35
|
+
actions << Action.summary
|
36
|
+
end
|
37
|
+
|
38
|
+
opts.on("-a", "--append", "Appends new strings to english localization file") do |n|
|
39
|
+
actions << Action.append
|
40
|
+
end
|
41
|
+
|
42
|
+
opts.on("-e", "--export", "Creates xliff files with missing localization") do |n|
|
43
|
+
actions << Action.export
|
44
|
+
end
|
45
|
+
|
46
|
+
opts.on("-i", "--import", "Looks for xliffs in project dir and imports whatever possible") do |n|
|
47
|
+
actions << Action.import
|
48
|
+
end
|
49
|
+
|
50
|
+
opts.on("-h", "--help", "Prints this help") do
|
51
|
+
puts opts
|
52
|
+
exit
|
53
|
+
end
|
54
|
+
end.parse!
|
55
|
+
|
56
|
+
actions << Action.summary if actions.empty?
|
57
|
+
|
58
|
+
@config = Config.new
|
59
|
+
@config.actions = actions
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.get
|
63
|
+
init if @config.nil?
|
64
|
+
@config
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
|
data/lib/lokale/find_dir.rb
CHANGED
@@ -2,38 +2,59 @@
|
|
2
2
|
# Based on https://github.com/mojombo/grit/pull/178 by https://github.com/derricks
|
3
3
|
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
#
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
5
|
+
module ProjectFinder
|
6
|
+
|
7
|
+
# Returns true if the given path represents a root directory (/ or C:/)
|
8
|
+
def self.root_directory?(file_path)
|
9
|
+
# Implementation inspired by http://stackoverflow.com/a/4969416:
|
10
|
+
# Does file + ".." resolve to the same directory as file_path?
|
11
|
+
File.directory?(file_path) &&
|
12
|
+
File.expand_path(file_path) == File.expand_path(File.join(file_path, '..'))
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the git root directory given a path inside the repo. Returns nil if
|
16
|
+
# the path is not in a git repo.
|
17
|
+
def self.find_git_repo(start_path = '.')
|
18
|
+
raise NoSuchPathError unless File.exists?(start_path)
|
12
19
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
break
|
29
|
-
else
|
30
|
-
# go up a directory and try again
|
31
|
-
current_path = File.dirname(current_path)
|
20
|
+
current_path = File.expand_path(start_path)
|
21
|
+
|
22
|
+
# for clarity: set to an explicit nil and then just return whatever
|
23
|
+
# the current value of this variable is (nil or otherwise)
|
24
|
+
return_path = nil
|
25
|
+
|
26
|
+
until root_directory?(current_path)
|
27
|
+
if File.exists?(File.join(current_path, '.git'))
|
28
|
+
# done
|
29
|
+
return_path = current_path
|
30
|
+
break
|
31
|
+
else
|
32
|
+
# go up a directory and try again
|
33
|
+
current_path = File.dirname(current_path)
|
34
|
+
end
|
32
35
|
end
|
36
|
+
return_path
|
33
37
|
end
|
34
|
-
return_path
|
35
|
-
end
|
36
38
|
|
37
|
-
|
38
|
-
|
39
|
+
##
|
40
|
+
|
41
|
+
def self.xcode_project_name(path)
|
42
|
+
Dir.glob("#{path}/**/**") { |file| return $1 if file =~ /\/(.+?)\.(?:xcodeproj|xcworkspace)$/ }
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
|
47
|
+
def self.find_proj
|
48
|
+
project_path = find_git_repo
|
49
|
+
if project_path.nil?
|
50
|
+
raise "Could not find any git repository."
|
51
|
+
end
|
52
|
+
|
53
|
+
project_name = xcode_project_name(project_path)
|
54
|
+
if project_name.nil?
|
55
|
+
raise "Found git repository (#{project_path}) does not contain an Xcode project."
|
56
|
+
end
|
57
|
+
|
58
|
+
return project_path, project_name
|
59
|
+
end
|
39
60
|
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
|
2
|
+
require "lokale/config"
|
3
|
+
require "lokale/model"
|
4
|
+
|
5
|
+
DEFAULT_LOKALEFILE = <<FILE
|
6
|
+
|
7
|
+
add_macro "NSLocalizedString" do |m|
|
8
|
+
m.localization_file = "Localizable.strings"
|
9
|
+
|
10
|
+
m.regex = /NSLocalizedString\\("(.+?)",\\s*comment:\\s*"(.*?)"\\)/
|
11
|
+
m.key_index = 0
|
12
|
+
m.note_index = 1
|
13
|
+
end
|
14
|
+
|
15
|
+
add_macro "PluralString" do |m|
|
16
|
+
m.regex = /String.localizedPlural\\("(.+?)"/
|
17
|
+
m.key_index = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
main_language "en"
|
21
|
+
base_language "Base"
|
22
|
+
|
23
|
+
FILE
|
24
|
+
|
25
|
+
|
26
|
+
class Config
|
27
|
+
def read_lokalefile(project_path)
|
28
|
+
lokalefile_path = File.join(project_path, ".lokale")
|
29
|
+
|
30
|
+
if File.file? lokalefile_path
|
31
|
+
read_config_from_file(lokalefile_path)
|
32
|
+
else
|
33
|
+
read_default_config
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_default_config
|
38
|
+
reset_config
|
39
|
+
instance_eval(DEFAULT_LOKALEFILE)
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_config_from_file(file_path)
|
43
|
+
content = File.read(file_path)
|
44
|
+
reset_config
|
45
|
+
instance_eval(content)
|
46
|
+
fill_defaults
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
class Config
|
52
|
+
|
53
|
+
attr_reader :macros
|
54
|
+
attr_reader :main_lang, :base_lang
|
55
|
+
|
56
|
+
def reset_config
|
57
|
+
@macros = nil
|
58
|
+
@main_lang = nil
|
59
|
+
@base_lang = nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def fill_defaults
|
63
|
+
default = Config.new
|
64
|
+
default.read_default_config
|
65
|
+
|
66
|
+
@macros ||= default.macros
|
67
|
+
@main_lang ||= default.main_lang
|
68
|
+
@base_lang ||= default.base_lang
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def add_macro(name)
|
74
|
+
macro = Lokale::Macro.new(name)
|
75
|
+
yield macro
|
76
|
+
@macros ||= []
|
77
|
+
@macros << macro
|
78
|
+
end
|
79
|
+
|
80
|
+
def main_language(l)
|
81
|
+
@main_lang = l
|
82
|
+
end
|
83
|
+
|
84
|
+
def base_language(l)
|
85
|
+
@base_lang = l
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
def test
|
91
|
+
Config.get.read_lokalefile File.dirname(__FILE__)
|
92
|
+
p Config.get.macros
|
93
|
+
p Config.get.main_lang
|
94
|
+
p Config.get.base_lang
|
95
|
+
end
|
96
|
+
|
97
|
+
# test
|
98
|
+
|
data/lib/lokale/model.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
|
2
|
+
class String
|
3
|
+
def localization_file?
|
4
|
+
File.directory?(self) == false &&
|
5
|
+
(self =~ /\/Pods\//) == nil &&
|
6
|
+
(self =~ /\.bundle\//) == nil &&
|
7
|
+
(self =~ /\/(.{1,8})\.lproj\//)
|
8
|
+
end
|
9
|
+
|
10
|
+
def source_file?
|
11
|
+
(File.directory?(self) == false) && (self =~ /\/Pods\//).nil? && ((self =~ /\.(swift|h|m)$/) != nil)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
|
16
|
+
module Lokale
|
17
|
+
class LString
|
18
|
+
attr_accessor :key, :str, :note, :target
|
19
|
+
|
20
|
+
def initialize(key, str, note, target)
|
21
|
+
@key = key; @str = str; @note = note; @target = target
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.strings_from_file(file_path, lang)
|
25
|
+
regex = /(?:\/\* (.+) \*\/.*\n)?"(.+)" *= *"(.+)";/
|
26
|
+
File.read(file_path).scan(regex).map { |m| LString.new(m[1], m[2], m[0], lang) }
|
27
|
+
end
|
28
|
+
|
29
|
+
def inspect
|
30
|
+
"<\#LS:#{@key}; s:#{@str}; n:#{@note}; t:#{@target}>"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
#
|
35
|
+
|
36
|
+
class LFile
|
37
|
+
attr_reader :path, :lang, :name, :type
|
38
|
+
def initialize(file_path)
|
39
|
+
@path = file_path
|
40
|
+
|
41
|
+
File.basename(file_path) =~ /^(.+)\.([^\.]*?)$/
|
42
|
+
@name = $1
|
43
|
+
@type = $2
|
44
|
+
|
45
|
+
file_path =~ /\/(.{1,8})\.lproj\//
|
46
|
+
@lang = $1
|
47
|
+
end
|
48
|
+
|
49
|
+
def self.try_to_read(file_path)
|
50
|
+
return nil unless file_path.localization_file?
|
51
|
+
LFile.new(file_path)
|
52
|
+
end
|
53
|
+
|
54
|
+
def inspect
|
55
|
+
"<LF:#{@lang}/#{full_name}>"
|
56
|
+
end
|
57
|
+
|
58
|
+
def full_name
|
59
|
+
"#{@name}.#{@type}"
|
60
|
+
end
|
61
|
+
|
62
|
+
def strings_file?
|
63
|
+
@type == "strings" || @type == "stringsdict"
|
64
|
+
end
|
65
|
+
|
66
|
+
def content
|
67
|
+
File.read(@path)
|
68
|
+
end
|
69
|
+
|
70
|
+
def parsed
|
71
|
+
return @parsed unless @parsed.nil?
|
72
|
+
@parsed = case type
|
73
|
+
when "strings" then LString.strings_from_file(@path, @lang)
|
74
|
+
when "stringsdict" then []
|
75
|
+
else nil
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
#
|
81
|
+
|
82
|
+
class Macro
|
83
|
+
attr_accessor :regex, :name, :localization_file, :key_index, :note_index
|
84
|
+
attr_reader :found_strings
|
85
|
+
|
86
|
+
def initialize(name)
|
87
|
+
@name = name
|
88
|
+
clear_calls
|
89
|
+
end
|
90
|
+
|
91
|
+
def clear_calls
|
92
|
+
@found_strings = Hash.new { |h, k| h[k] = 0 }
|
93
|
+
end
|
94
|
+
|
95
|
+
def read_from(file)
|
96
|
+
file.scan(@regex) do |m|
|
97
|
+
lang = Config.get.main_lang
|
98
|
+
key = m[key_index] unless key_index.nil?
|
99
|
+
val = m[note_index] unless note_index.nil?
|
100
|
+
lstr = LString.new(key, val, val, lang)
|
101
|
+
@found_strings[lstr] += 1
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def uniq_count
|
106
|
+
@found_strings.size
|
107
|
+
end
|
108
|
+
|
109
|
+
def total_count
|
110
|
+
@found_strings.values.reduce(:+) || 0
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
module Lokale
|
120
|
+
|
121
|
+
# Hashable
|
122
|
+
class LString
|
123
|
+
def fields
|
124
|
+
[@key, @str, @note, @target]
|
125
|
+
end
|
126
|
+
|
127
|
+
def ==(other)
|
128
|
+
self.class === other && other.fields == fields
|
129
|
+
end
|
130
|
+
|
131
|
+
alias eql? ==
|
132
|
+
|
133
|
+
def hash
|
134
|
+
fields.hash
|
135
|
+
end
|
136
|
+
end
|
137
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module Lokale
|
2
|
+
class Reporter
|
3
|
+
def initialize(agent)
|
4
|
+
@agent = agent
|
5
|
+
end
|
6
|
+
|
7
|
+
def print_summary
|
8
|
+
print_macro_calls_summary
|
9
|
+
print_macro_table
|
10
|
+
print_files_table
|
11
|
+
print_repeats_report
|
12
|
+
print_diferences_report
|
13
|
+
end
|
14
|
+
|
15
|
+
def print_macro_calls_summary
|
16
|
+
total_macro_calls = @agent.macros.map(&:total_count).reduce(:+)
|
17
|
+
uniq_macro_calls = @agent.macros.map(&:uniq_count).reduce(:+)
|
18
|
+
puts "Found #{total_macro_calls} localization macro calls in #{@agent.sfiles_proceeded} files."
|
19
|
+
puts "Uniq macro calls: #{uniq_macro_calls}"
|
20
|
+
puts
|
21
|
+
end
|
22
|
+
|
23
|
+
def print_files_table
|
24
|
+
languages = @agent.lfiles.map { |e| e.lang }.to_set.to_a
|
25
|
+
files = @agent.lfiles.map { |e| e.full_name }.to_set.to_a
|
26
|
+
|
27
|
+
puts "Found #{@agent.lfiles.size} localized files for #{languages.size} languages."
|
28
|
+
|
29
|
+
description_header = "[*]".rpadded(36)
|
30
|
+
languages.each { |l| description_header << l.rpadded(8) }
|
31
|
+
puts description_header
|
32
|
+
|
33
|
+
files.each do |f|
|
34
|
+
description_string = f.rpadded(36)
|
35
|
+
languages.each do |l|
|
36
|
+
lfile = @agent.lfiles.select { |lf| lf.full_name == f && lf.lang == l }
|
37
|
+
description_string << (lfile.empty? ? "-" : lfile[0].parsed.nil? ? "*" : "#{lfile[0].parsed.size}").rpadded(8)
|
38
|
+
end
|
39
|
+
puts description_string
|
40
|
+
end
|
41
|
+
puts
|
42
|
+
end
|
43
|
+
|
44
|
+
def print_macro_table
|
45
|
+
@agent.macros.each do |macro|
|
46
|
+
puts "#{macro.name}:".rpadded(24) + "total: #{macro.total_count}".rpadded(16) + "uniq: #{macro.uniq_count}"
|
47
|
+
end
|
48
|
+
puts
|
49
|
+
end
|
50
|
+
|
51
|
+
def print_repeats_report
|
52
|
+
repeats_repot = ""
|
53
|
+
@agent.lfiles.each do |lf|
|
54
|
+
repeats = lf.repeats
|
55
|
+
next if repeats.count.zero?
|
56
|
+
repeats_repot << "#{lf.lang}/#{lf.full_name} repeats:\n"
|
57
|
+
repeats_repot << repeats.join("\n")
|
58
|
+
repeats_repot << "\n"
|
59
|
+
end
|
60
|
+
|
61
|
+
if repeats_repot.empty?
|
62
|
+
puts "Repeats not found.".green
|
63
|
+
puts
|
64
|
+
else
|
65
|
+
puts "Found repeats in strings files.".red
|
66
|
+
puts repeats_repot
|
67
|
+
puts
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def print_diferences_report
|
72
|
+
diferences_repot = ""
|
73
|
+
|
74
|
+
@agent.lfiles.group_by { |f| f.full_name }.each do |file_name, files|
|
75
|
+
base_lang = files.any? { |f| f.lang == "Base" } ? "Base" : "en"
|
76
|
+
files = files.select { |f| f.lang != base_lang }
|
77
|
+
all_keys = files.map(&:keys).compact.map(&:to_set)
|
78
|
+
next if all_keys.empty?
|
79
|
+
united_keys = all_keys.reduce(:|)
|
80
|
+
all_keys.map! { |ks| united_keys - ks }
|
81
|
+
next if all_keys.map(&:length).reduce(:+).zero?
|
82
|
+
|
83
|
+
diferences_repot << "Missing keys in file \"#{file_name}\":\n"
|
84
|
+
all_keys.zip(files) do |missing_keys, lfile|
|
85
|
+
next if missing_keys.size.zero?
|
86
|
+
diferences_repot << "*".red + " #{lfile.lang} - #{missing_keys.size} key(s):\n"
|
87
|
+
missing_keys.each { |k| diferences_repot << "#{k}\n" }
|
88
|
+
end
|
89
|
+
diferences_repot << "\n"
|
90
|
+
end
|
91
|
+
|
92
|
+
if diferences_repot.empty?
|
93
|
+
puts "Localization files are full.".green
|
94
|
+
puts
|
95
|
+
else
|
96
|
+
puts "Localization files are not full.".red
|
97
|
+
puts diferences_repot
|
98
|
+
puts
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/lokale/util.rb
ADDED
data/lib/lokale/version.rb
CHANGED
data/lib/lokale.rb
CHANGED
@@ -1,305 +1,84 @@
|
|
1
|
-
require "lokale/version"
|
2
|
-
require "lokale/colorize"
|
3
|
-
require "set"
|
4
1
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
2
|
+
require 'lokale/find_dir'
|
3
|
+
require 'lokale/colorize'
|
4
|
+
require 'lokale/config'
|
5
|
+
require 'lokale/reporter'
|
6
|
+
require 'lokale/lokalefile'
|
7
|
+
require 'lokale/agent'
|
9
8
|
|
10
|
-
|
11
|
-
|
9
|
+
class Action
|
10
|
+
def print(str)
|
11
|
+
puts str.blue
|
12
12
|
end
|
13
13
|
|
14
|
-
def
|
15
|
-
|
16
|
-
(self =~ /\/Pods\//) == nil &&
|
17
|
-
(self =~ /\.bundle\//) == nil &&
|
18
|
-
(self =~ /\/(.{1,8})\.lproj\//)
|
14
|
+
def perform(agent, reporter)
|
15
|
+
send(("perform_" + @type.to_s).to_sym, agent, reporter)
|
19
16
|
end
|
20
17
|
|
21
|
-
def
|
22
|
-
|
18
|
+
def perform_summary(agent, reporter)
|
19
|
+
print "Printing summary...".blue
|
20
|
+
reporter.print_summary
|
23
21
|
end
|
24
|
-
end
|
25
|
-
|
26
|
-
|
27
|
-
module Lokale
|
28
|
-
class LString
|
29
|
-
attr_accessor :key, :str, :note, :target
|
30
|
-
|
31
|
-
def initialize(key, str, note, target)
|
32
|
-
@key = key; @str = str; @note = note; @target = target
|
33
|
-
end
|
34
22
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
end
|
23
|
+
def perform_copy_base(agent, reporter)
|
24
|
+
print "Copying `en` strings files to `Base`...".blue
|
25
|
+
agent.copy_base
|
39
26
|
end
|
40
27
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
attr_reader :path, :lang, :name, :type
|
45
|
-
def initialize(file_path)
|
46
|
-
@path = file_path
|
47
|
-
|
48
|
-
File.basename(file_path) =~ /^(.+)\.([^\.]*?)$/
|
49
|
-
@name = $1
|
50
|
-
@type = $2
|
51
|
-
|
52
|
-
file_path =~ /\/(.{1,8})\.lproj\//
|
53
|
-
@lang = $1
|
54
|
-
end
|
55
|
-
|
56
|
-
def self.try_to_read(file_path)
|
57
|
-
return nil unless file_path.localization_file?
|
58
|
-
LFile.new(file_path)
|
59
|
-
end
|
60
|
-
|
61
|
-
def inspect
|
62
|
-
"<#{@lang}/#{full_name}>"
|
63
|
-
end
|
64
|
-
|
65
|
-
def full_name
|
66
|
-
"#{@name}.#{@type}"
|
67
|
-
end
|
68
|
-
|
69
|
-
def parsed
|
70
|
-
return @parsed unless @parsed.nil?
|
71
|
-
@parsed = case type
|
72
|
-
when "strings" then LString.strings_from_file(@path, @lang)
|
73
|
-
when "stringsdict" then []
|
74
|
-
else nil
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
def repeats
|
79
|
-
return [] if @parsed.nil?
|
80
|
-
keys = @parsed.map(&:key)
|
81
|
-
uniq_keys = keys.to_set
|
82
|
-
|
83
|
-
keys.delete_if do |k|
|
84
|
-
if uniq_keys.include? k
|
85
|
-
uniq_keys.delete k
|
86
|
-
true
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
def keys
|
92
|
-
return nil if parsed.nil?
|
93
|
-
parsed.map(&:key)
|
94
|
-
end
|
95
|
-
|
96
|
-
|
97
|
-
def strings_file?
|
98
|
-
@type == "strings" || @type == "stringsdict"
|
99
|
-
end
|
28
|
+
def perform_append(agent, reporter)
|
29
|
+
print "Appending new macro calls to localization files...".blue
|
30
|
+
agent.append_new_macro_calls
|
100
31
|
end
|
101
32
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
attr_reader :regex, :found_strings, :name, :file_name
|
106
|
-
|
107
|
-
def initialize(name, regex, file_name)
|
108
|
-
@name = name
|
109
|
-
@regex = regex
|
110
|
-
@file_name = file_name
|
111
|
-
clear_calls
|
112
|
-
end
|
113
|
-
|
114
|
-
def clear_calls
|
115
|
-
@found_strings = Hash.new { |h, k| h[k] = 0 }
|
116
|
-
end
|
117
|
-
|
118
|
-
def read_from(file)
|
119
|
-
file.scan(@regex) { |m| @found_strings[m] += 1 }
|
120
|
-
end
|
121
|
-
|
122
|
-
def uniq_count
|
123
|
-
@found_strings.size
|
124
|
-
end
|
125
|
-
|
126
|
-
def total_count
|
127
|
-
@found_strings.values.reduce(:+) || 0
|
128
|
-
end
|
33
|
+
def perform_export(agent, reporter)
|
34
|
+
print "Preparing xliff files with new localized strings...".blue
|
35
|
+
agent.export_xliffs
|
129
36
|
end
|
130
37
|
|
38
|
+
def perform_import(agent, reporter)
|
39
|
+
print "Attempting to import new strings...".blue
|
40
|
+
agent.try_to_import
|
41
|
+
end
|
42
|
+
end
|
131
43
|
|
132
|
-
#
|
133
|
-
#
|
134
|
-
#
|
135
|
-
#
|
136
|
-
|
137
|
-
class Agent
|
138
|
-
attr_reader :proj_path, :macros, :lfiles, :sfiles_proceeded
|
139
|
-
|
140
|
-
def initialize(proj_path, macros)
|
141
|
-
@proj_path = proj_path
|
142
|
-
@macros = macros
|
143
|
-
|
144
|
-
get_localization_files
|
145
|
-
find_all_localization_calls
|
146
|
-
end
|
147
|
-
|
148
|
-
def proj_files
|
149
|
-
if block_given?
|
150
|
-
Dir.glob("#{@proj_path}/**/**") { |f| yield f }
|
151
|
-
else
|
152
|
-
Dir.glob("#{@proj_path}/**/**")
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def get_localization_files
|
157
|
-
return @lfiles unless @lfiles.nil?
|
158
|
-
@lfiles = proj_files.map { |file| LFile.try_to_read(file) }.compact
|
159
|
-
end
|
160
|
-
|
161
|
-
def find_all_localization_calls
|
162
|
-
@macros.each { |m| m.clear_calls }
|
163
44
|
|
164
|
-
|
165
|
-
|
166
|
-
next unless file.source_file?
|
45
|
+
module Lokale
|
46
|
+
class Main
|
167
47
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
48
|
+
def run
|
49
|
+
find_dir
|
50
|
+
read_config
|
51
|
+
init_workers
|
52
|
+
run_actions
|
172
53
|
end
|
173
54
|
|
174
|
-
|
175
|
-
en_files = @lfiles.group_by { |f| f.lang }["en"].select { |f| f.strings_file? }
|
176
|
-
base_files = @lfiles.group_by { |f| f.lang }["Base"].select { |f| f.strings_file? }
|
55
|
+
#
|
177
56
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
57
|
+
def find_dir
|
58
|
+
begin
|
59
|
+
@project_path, @project_name = ProjectFinder::find_proj
|
60
|
+
rescue Exception => e
|
61
|
+
puts e
|
62
|
+
exit
|
182
63
|
end
|
183
|
-
end
|
184
|
-
|
185
|
-
def append_new_macro_calls
|
186
|
-
|
187
|
-
end
|
188
|
-
end
|
189
|
-
|
190
|
-
#
|
191
|
-
|
192
|
-
class Reporter
|
193
|
-
def initialize(agent)
|
194
|
-
@agent = agent
|
195
|
-
end
|
196
|
-
|
197
|
-
def print_summary
|
198
|
-
print_macro_calls_summary
|
199
|
-
print_macro_table
|
200
|
-
print_files_table
|
201
|
-
print_repeats_report
|
202
|
-
print_diferences_report
|
203
|
-
end
|
204
64
|
|
205
|
-
|
206
|
-
total_macro_calls = @agent.macros.map(&:total_count).reduce(:+)
|
207
|
-
uniq_macro_calls = @agent.macros.map(&:uniq_count).reduce(:+)
|
208
|
-
puts "Found #{total_macro_calls} localization macro calls in #{@agent.sfiles_proceeded} files."
|
209
|
-
puts "Uniq macro calls: #{uniq_macro_calls}"
|
210
|
-
puts
|
65
|
+
puts "Target Xcode project: '#{@project_name}'".green
|
211
66
|
end
|
212
67
|
|
213
|
-
def
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
puts "Found #{@agent.lfiles.size} localized files for #{languages.size} languages."
|
218
|
-
|
219
|
-
description_header = "[*]".rpadded(36)
|
220
|
-
languages.each { |l| description_header << l.rpadded(8) }
|
221
|
-
puts description_header
|
222
|
-
|
223
|
-
files.each do |f|
|
224
|
-
description_string = f.rpadded(36)
|
225
|
-
languages.each do |l|
|
226
|
-
lfile = @agent.lfiles.select { |lf| lf.full_name == f && lf.lang == l }
|
227
|
-
description_string << (lfile.empty? ? "-" : lfile[0].parsed.nil? ? "*" : "#{lfile[0].parsed.size}").rpadded(8)
|
228
|
-
end
|
229
|
-
puts description_string
|
230
|
-
end
|
231
|
-
puts
|
68
|
+
def read_config
|
69
|
+
Config.init
|
70
|
+
Config.get.read_lokalefile(@project_path)
|
232
71
|
end
|
233
72
|
|
234
|
-
def
|
235
|
-
@agent.macros
|
236
|
-
|
237
|
-
end
|
238
|
-
puts
|
73
|
+
def init_workers
|
74
|
+
@agent = Lokale::Agent.new(@project_path, Config.get.macros)
|
75
|
+
@reporter = Lokale::Reporter.new(@agent)
|
239
76
|
end
|
240
|
-
|
241
|
-
def
|
242
|
-
|
243
|
-
@agent.lfiles.each do |lf|
|
244
|
-
repeats = lf.repeats
|
245
|
-
next if repeats.count.zero?
|
246
|
-
repeats_repot << "#{lf.lang}/#{lf.full_name} repeats:\n"
|
247
|
-
repeats_repot << repeats.join("\n")
|
248
|
-
repeats_repot << "\n"
|
249
|
-
end
|
250
|
-
|
251
|
-
if repeats_repot.empty?
|
252
|
-
puts "Repeats not found.".green
|
253
|
-
puts
|
254
|
-
else
|
255
|
-
puts "Found repeats in strings files.".red
|
256
|
-
puts repeats_repot
|
257
|
-
puts
|
258
|
-
end
|
77
|
+
|
78
|
+
def run_actions
|
79
|
+
Config.get.actions.each { |action| action.perform(@agent, @reporter) }
|
259
80
|
end
|
260
|
-
|
261
|
-
def print_diferences_report
|
262
|
-
diferences_repot = ""
|
263
|
-
|
264
|
-
@agent.lfiles.group_by { |f| f.full_name }.each do |file_name, files|
|
265
|
-
base_lang = files.any? { |f| f.lang == "Base" } ? "Base" : "en"
|
266
|
-
files = files.select { |f| f.lang != base_lang }
|
267
|
-
all_keys = files.map(&:keys).compact.map(&:to_set)
|
268
|
-
next if all_keys.empty?
|
269
|
-
united_keys = all_keys.reduce(:|)
|
270
|
-
all_keys.map! { |ks| united_keys - ks }
|
271
|
-
next if all_keys.map(&:length).reduce(:+).zero?
|
272
|
-
|
273
|
-
diferences_repot << "Missing keys in file \"#{file_name}\":\n"
|
274
|
-
all_keys.zip(files) do |missing_keys, lfile|
|
275
|
-
next if missing_keys.size.zero?
|
276
|
-
diferences_repot << "*".red + " #{lfile.lang} - #{missing_keys.size} key(s):\n"
|
277
|
-
missing_keys.each { |k| diferences_repot << "#{k}\n" }
|
278
|
-
end
|
279
|
-
diferences_repot << "\n"
|
280
|
-
end
|
281
|
-
|
282
|
-
if diferences_repot.empty?
|
283
|
-
puts "Localization files are full.".green
|
284
|
-
puts
|
285
|
-
else
|
286
|
-
puts "Localization files are not full.".red
|
287
|
-
puts diferences_repot
|
288
|
-
puts
|
289
|
-
end
|
290
|
-
end
|
291
81
|
end
|
292
82
|
end
|
293
83
|
|
294
84
|
|
295
|
-
|
296
|
-
# macros = [
|
297
|
-
# Lokale::Macro.new("NSLocalizedString", /NSLocalizedString\("(.+?)",\s*comment:\s*"(.*?)"\)/),
|
298
|
-
# Lokale::Macro.new("PluralString", /String.localizedPlural\("(.+?)"/),
|
299
|
-
# #LocalizationMacro.new("ObjC String", /NSLocalizedString\("(.*)",\s*(.*)\)/),
|
300
|
-
# #LocalizationMacro.new("ObjC Table String", /NSLocalizedStringFromTableInBundle\((.*?),/)
|
301
|
-
# ]
|
302
|
-
|
303
|
-
# agent = Lokale::Agent.new("/Users/crysberry/Documents/hand2hand", macros)
|
304
|
-
# reporter = Lokale::Reporter.new(agent)
|
305
|
-
# reporter.print_summary
|
data/lokale.gemspec
CHANGED
data/test.sh
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rake install; cd ~/Documents/hand2hand-ios; lokale; cd ~/Documents/lokale
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lokale
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Onizhuk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
12
|
-
dependencies:
|
11
|
+
date: 2017-11-18 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: xliffle
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.2.2
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.2.2
|
13
27
|
description: Write a longer description or delete this line.
|
14
28
|
email:
|
15
29
|
- anton.onizhuk@gmail.com
|
@@ -23,15 +37,23 @@ files:
|
|
23
37
|
- LICENSE.txt
|
24
38
|
- README.md
|
25
39
|
- Rakefile
|
40
|
+
- a.sh
|
26
41
|
- bin/console
|
27
42
|
- bin/lokale
|
28
43
|
- bin/setup
|
29
44
|
- lib/lokale.rb
|
45
|
+
- lib/lokale/.lokale
|
46
|
+
- lib/lokale/agent.rb
|
30
47
|
- lib/lokale/colorize.rb
|
48
|
+
- lib/lokale/config.rb
|
31
49
|
- lib/lokale/find_dir.rb
|
32
|
-
- lib/lokale/
|
50
|
+
- lib/lokale/lokalefile.rb
|
51
|
+
- lib/lokale/model.rb
|
52
|
+
- lib/lokale/reporter.rb
|
53
|
+
- lib/lokale/util.rb
|
33
54
|
- lib/lokale/version.rb
|
34
55
|
- lokale.gemspec
|
56
|
+
- test.sh
|
35
57
|
homepage:
|
36
58
|
licenses:
|
37
59
|
- MIT
|
data/lib/lokale/options.rb
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
|
2
|
-
require "optparse"
|
3
|
-
|
4
|
-
class Action
|
5
|
-
attr_reader :type, :arg, :precedence
|
6
|
-
def initialize(type, arg, precedence)
|
7
|
-
@type = type; @arg = arg; @precedence = precedence
|
8
|
-
end
|
9
|
-
|
10
|
-
def self.summary
|
11
|
-
Action.new(:summary, nil, 10)
|
12
|
-
end
|
13
|
-
def self.copy_base
|
14
|
-
Action.new(:copy_base, nil, 50)
|
15
|
-
end
|
16
|
-
def self.append
|
17
|
-
Action.new(:append, nil, 60)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
class Settings
|
22
|
-
attr_reader :actions
|
23
|
-
|
24
|
-
def self.init
|
25
|
-
actions = []
|
26
|
-
|
27
|
-
OptionParser.new do |opts|
|
28
|
-
opts.banner = "Usage: lokale [-bsh]"
|
29
|
-
|
30
|
-
opts.on("-b", "--copy-base", "Copies 'en' localization files to 'Base'") do |n|
|
31
|
-
actions << Action.copy_base
|
32
|
-
end
|
33
|
-
|
34
|
-
opts.on("-s", "--summary", "Prints project summary") do |n|
|
35
|
-
actions << Action.summary
|
36
|
-
end
|
37
|
-
|
38
|
-
opts.on("-a", "--append", "Appends new strings to english localization file") do |n|
|
39
|
-
actions << Action.append
|
40
|
-
end
|
41
|
-
|
42
|
-
opts.on("-h", "--help", "Prints this help") do
|
43
|
-
puts opts
|
44
|
-
exit
|
45
|
-
end
|
46
|
-
end.parse!
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
if actions.empty?
|
51
|
-
actions << Action.summary
|
52
|
-
else
|
53
|
-
actions.sort_by! { |e| -e.precedence }
|
54
|
-
end
|
55
|
-
|
56
|
-
@shared_settings = Settings.new(actions)
|
57
|
-
end
|
58
|
-
|
59
|
-
def self.get
|
60
|
-
init if @shared_settings.nil?
|
61
|
-
@shared_settings
|
62
|
-
end
|
63
|
-
|
64
|
-
def initialize(actions)
|
65
|
-
@actions = actions
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
|
70
|
-
|