babelyoda 1.6.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/CHANGELOG +1 -0
- data/Gemfile +6 -0
- data/LICENSE +1 -1
- data/README.rdoc +2 -2
- data/Rakefile +1 -0
- data/babelyoda.gemspec +28 -0
- data/lib/babelyoda/file.rb +20 -0
- data/lib/babelyoda/genstrings.rb +27 -0
- data/lib/babelyoda/git.rb +99 -0
- data/lib/babelyoda/git_versions.rb +39 -0
- data/lib/babelyoda/ibtool.rb +51 -0
- data/lib/babelyoda/keyset.rb +58 -0
- data/lib/babelyoda/localization_key.rb +56 -0
- data/lib/babelyoda/localization_value.rb +26 -0
- data/lib/babelyoda/logger.rb +16 -0
- data/lib/babelyoda/rake.rb +10 -0
- data/lib/babelyoda/specification.rb +40 -0
- data/lib/babelyoda/specification_loader.rb +35 -0
- data/lib/babelyoda/strings.rb +64 -8
- data/lib/babelyoda/strings_lexer.rb +12 -0
- data/lib/babelyoda/strings_parser.rb +72 -0
- data/lib/babelyoda/tanker.rb +190 -0
- data/lib/babelyoda/version.rb +3 -0
- data/lib/babelyoda/xib.rb +94 -0
- data/lib/babelyoda.rb +207 -0
- data/templates/Babelfile.erb +15 -0
- metadata +162 -70
- data/VERSION +0 -1
- data/bin/babelyoda +0 -399
- data/data/empty.strings +0 -1
- data/lib/babelyoda/options.rb +0 -42
@@ -0,0 +1,72 @@
|
|
1
|
+
require_relative 'localization_key'
|
2
|
+
require_relative 'localization_value'
|
3
|
+
|
4
|
+
module Babelyoda
|
5
|
+
class StringsParser
|
6
|
+
Bit = Struct.new(:token, :value)
|
7
|
+
|
8
|
+
def initialize(lexer, language)
|
9
|
+
@lexer, @language = lexer, language
|
10
|
+
end
|
11
|
+
|
12
|
+
def parse(str, &block)
|
13
|
+
@block = block
|
14
|
+
bitstream = []
|
15
|
+
@lexer.lex(str) do | token, value |
|
16
|
+
bitstream << Bit.new(token, value)
|
17
|
+
end
|
18
|
+
while bitstream.size > 0
|
19
|
+
record = produce(bitstream)
|
20
|
+
@block.call(record) if record
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def produce(bs)
|
25
|
+
match_bs(bs, :multiline_comment, :string, :equal_sign, :string, :semicolon) do |bits|
|
26
|
+
localization_key = LocalizationKey.new(cleanup_string(bits[1]), cleanup_comment(bits[0]))
|
27
|
+
localization_value = LocalizationValue.new(@language, cleanup_string(bits[3]))
|
28
|
+
localization_key << localization_value
|
29
|
+
return localization_key
|
30
|
+
end
|
31
|
+
match_bs(bs, :singleline_comment, :string, :equal_sign, :string, :semicolon) do |bits|
|
32
|
+
localization_key = LocalizationKey.new(cleanup_string(bits[1]), cleanup_comment(bits[0]))
|
33
|
+
localization_value = LocalizationValue.new(@language, cleanup_string(bits[3]))
|
34
|
+
localization_key << localization_value
|
35
|
+
return localization_key
|
36
|
+
end
|
37
|
+
match_bs(bs, :string, :equal_sign, :string, :semicolon) do |bits|
|
38
|
+
localization_key = LocalizationKey.new(cleanup_string(bits[0]), nil)
|
39
|
+
localization_value = LocalizationValue.new(@language, cleanup_string(bits[2]))
|
40
|
+
localization_key << localization_value
|
41
|
+
return localization_key
|
42
|
+
end
|
43
|
+
match_bs(bs, :singleline_comment) do |bits|
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
match_bs(bs, :multiline_comment) do |bits|
|
47
|
+
return nil
|
48
|
+
end
|
49
|
+
raise "Syntax error: #{bs.shift(5).inspect}"
|
50
|
+
end
|
51
|
+
|
52
|
+
def match_bs(bs, *tokens)
|
53
|
+
return unless bs.size >= tokens.size
|
54
|
+
tokens.each_with_index do |token, idx|
|
55
|
+
return unless bs[idx][:token] == token
|
56
|
+
end
|
57
|
+
yield bs.shift(tokens.size).map { |bit| bit[:value] }
|
58
|
+
end
|
59
|
+
|
60
|
+
def cleanup_comment(str)
|
61
|
+
if str.match(/^\/\/\s*/)
|
62
|
+
str.sub(/^\/\/\s*/, '')
|
63
|
+
else
|
64
|
+
str.sub(/^\/\*\s*/, '').sub(/\s*\*\/$/, '')
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def cleanup_string(str)
|
69
|
+
str.sub(/^\"/, '').sub(/\"$/, '')
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
require 'builder'
|
2
|
+
require 'net/http'
|
3
|
+
require 'nokogiri'
|
4
|
+
require 'stringio'
|
5
|
+
|
6
|
+
require 'babelyoda/specification_loader'
|
7
|
+
|
8
|
+
module Babelyoda
|
9
|
+
class Keyset
|
10
|
+
def to_xml(xml, language = nil)
|
11
|
+
xml.keyset(:id => name) do
|
12
|
+
keys.each_value do |key|
|
13
|
+
xml.key(:id => key.id, :is_plural => 'False') do
|
14
|
+
xml.context(key.context)
|
15
|
+
key.values.each_value do |value|
|
16
|
+
next if language && (value.language.to_s != language.to_s)
|
17
|
+
xml.value(value.text, :language => value.language, :status => value.status)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.parse_xml(node)
|
25
|
+
result = self.new(node[:id])
|
26
|
+
node.css('key').each do |key_node|
|
27
|
+
result.merge_key!(Babelyoda::LocalizationKey.parse_xml(key_node))
|
28
|
+
end
|
29
|
+
result
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class LocalizationKey
|
34
|
+
def self.parse_xml(node)
|
35
|
+
context = node.css('context').first
|
36
|
+
context &&= context.text
|
37
|
+
result = self.new(node[:id], context)
|
38
|
+
node.css('value').each do |value_node|
|
39
|
+
result << Babelyoda::LocalizationValue.parse_xml(value_node)
|
40
|
+
end
|
41
|
+
result
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class LocalizationValue
|
46
|
+
def self.parse_xml(node)
|
47
|
+
self.new(node[:language], node.text, node[:status])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Tanker
|
52
|
+
include Babelyoda::SpecificationLoader
|
53
|
+
|
54
|
+
class FileNameInvalidError < RuntimeError ; end
|
55
|
+
|
56
|
+
attr_accessor :endpoint
|
57
|
+
attr_accessor :token
|
58
|
+
attr_accessor :project_id
|
59
|
+
|
60
|
+
def replace(keyset, language = nil)
|
61
|
+
doc = project_xml do |xml|
|
62
|
+
keyset.to_xml(xml, language)
|
63
|
+
end
|
64
|
+
payload = {
|
65
|
+
:file => StringIO.new(doc),
|
66
|
+
'project-id' => project_id,
|
67
|
+
'keyset-id' => keyset.name,
|
68
|
+
:format => 'xml'
|
69
|
+
}
|
70
|
+
payload.merge!({:language => language}) if language
|
71
|
+
post('/keysets/replace/', payload)
|
72
|
+
end
|
73
|
+
|
74
|
+
def list
|
75
|
+
get('/keysets/', { 'project-id' => project_id }).css('keyset').map { |keyset| keyset['id'] }
|
76
|
+
end
|
77
|
+
|
78
|
+
def create(keyset_name)
|
79
|
+
post('/keysets/create/', { 'project-id' => project_id, 'keyset-id' => keyset_name })
|
80
|
+
end
|
81
|
+
|
82
|
+
def export(keyset_name = nil, languages = nil, status = nil, safe = false)
|
83
|
+
payload = { 'project-id' => project_id }
|
84
|
+
payload.merge!({ 'keyset-id' => keyset_name }) if keyset_name
|
85
|
+
if languages
|
86
|
+
value = languages
|
87
|
+
value = languages.join(',') if languages.respond_to?(:join)
|
88
|
+
payload.merge!({ 'language' => value })
|
89
|
+
end
|
90
|
+
payload.merge!({ 'status' => status.to_s }) if status
|
91
|
+
payload.merge!({ 'safe' => safe }) if safe
|
92
|
+
get('/projects/export/xml/', payload)
|
93
|
+
end
|
94
|
+
|
95
|
+
def load_keyset(keyset_name, languages = nil, status = nil, safe = false)
|
96
|
+
doc = export(keyset_name, languages, status, safe)
|
97
|
+
doc.css("keyset[@id='#{keyset_name}']").each do |keyset_node|
|
98
|
+
keyset = Babelyoda::Keyset.parse_xml(keyset_node)
|
99
|
+
return keyset if keyset.name == keyset_name
|
100
|
+
end
|
101
|
+
Babelyoda::Keyset.new(keyset_name)
|
102
|
+
end
|
103
|
+
|
104
|
+
private
|
105
|
+
|
106
|
+
MULTIPART_BOUNDARY = '114YANDEXTANKERCLIENTBNDR';
|
107
|
+
|
108
|
+
def multipart_content_type
|
109
|
+
"multipart/form-data; boundary=#{MULTIPART_BOUNDARY}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def method(name)
|
113
|
+
"#{endpoint}#{name}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def project_xml(&block)
|
117
|
+
xml = Builder::XmlMarkup.new
|
118
|
+
xml.instruct!(:xml, :encoding => "UTF-8")
|
119
|
+
xml.tanker do
|
120
|
+
xml.project(:id => project_id) do
|
121
|
+
yield xml
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def multipart_data(payload = {}, boundary = MULTIPART_BOUNDARY)
|
127
|
+
payload.keys.map { |k|
|
128
|
+
"--#{boundary}\r\n" + multipart_field(k, payload[k])
|
129
|
+
}.join('') + "--#{boundary}--\r\n"
|
130
|
+
end
|
131
|
+
|
132
|
+
def multipart_field(k, v)
|
133
|
+
if v.respond_to?(:read)
|
134
|
+
"Content-Disposition: form-data; name=\"#{k}\"; filename=\"#{k}.xml\"\r\n" +
|
135
|
+
"Content-Type: application/octet-stream\r\n" +
|
136
|
+
"Content-Transfer-Encoding: binary\r\n\r\n" +
|
137
|
+
"#{v.read}\r\n"
|
138
|
+
else
|
139
|
+
"Content-Disposition: form-data; name=\"#{k}\"\r\n\r\n" +
|
140
|
+
"#{v}\r\n"
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def post(method_name, payload)
|
145
|
+
uri = URI(method(method_name))
|
146
|
+
req = Net::HTTP::Post.new(uri.path)
|
147
|
+
req['AUTHORIZATION'] = token
|
148
|
+
req.content_type = multipart_content_type
|
149
|
+
req.body = multipart_data(payload)
|
150
|
+
|
151
|
+
# puts "POST URI: #{uri}"
|
152
|
+
# puts "POST BODY: #{req.body}"
|
153
|
+
|
154
|
+
res = Net::HTTP.start(uri.host, uri.port) do |http|
|
155
|
+
http.request(req)
|
156
|
+
end
|
157
|
+
|
158
|
+
case res
|
159
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
160
|
+
Nokogiri::XML.parse(res.body)
|
161
|
+
else
|
162
|
+
doc = Nokogiri::XML.parse(res.body)
|
163
|
+
error = doc.css('result error')[0].content
|
164
|
+
raise RuntimeError.new(error)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
def get(method_name, payload = nil)
|
169
|
+
uri = URI(method(method_name))
|
170
|
+
uri.query = URI.encode_www_form(payload) if payload
|
171
|
+
req = Net::HTTP::Get.new(uri.request_uri)
|
172
|
+
req['AUTHORIZATION'] = token
|
173
|
+
|
174
|
+
# puts "GET URI: #{uri}"
|
175
|
+
|
176
|
+
res = Net::HTTP.start(uri.host, uri.port) do |http|
|
177
|
+
http.request(req)
|
178
|
+
end
|
179
|
+
|
180
|
+
case res
|
181
|
+
when Net::HTTPSuccess, Net::HTTPRedirection
|
182
|
+
Nokogiri::XML.parse(res.body)
|
183
|
+
else
|
184
|
+
doc = Nokogiri::XML.parse(res.body)
|
185
|
+
error = doc.css('result error')[0].content
|
186
|
+
raise Error.new(error)
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
end
|
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require_relative 'file'
|
4
|
+
require_relative 'ibtool'
|
5
|
+
|
6
|
+
module Babelyoda
|
7
|
+
class Xib
|
8
|
+
attr_reader :filename
|
9
|
+
attr_reader :language
|
10
|
+
|
11
|
+
def initialize(filename, language)
|
12
|
+
@filename, @language = filename, language
|
13
|
+
end
|
14
|
+
|
15
|
+
def extractable?(development_language)
|
16
|
+
lproj_part = File.lproj_part(@filename)
|
17
|
+
(!lproj_part.nil?) && lproj_part == "#{development_language}.lproj"
|
18
|
+
end
|
19
|
+
|
20
|
+
def dirname
|
21
|
+
File.dirname(@filename)
|
22
|
+
end
|
23
|
+
|
24
|
+
def basename
|
25
|
+
File.basename(File.split(@filename)[1], '.xib')
|
26
|
+
end
|
27
|
+
|
28
|
+
def resourced?
|
29
|
+
!File.lproj_part(@filename).nil?
|
30
|
+
end
|
31
|
+
|
32
|
+
def resource!
|
33
|
+
raise "The XIB is already in a resource folder: #{@filename}" unless File.lproj_part(@filename).nil?
|
34
|
+
mv(File.localized(@filename, @language))
|
35
|
+
end
|
36
|
+
|
37
|
+
def mv(new_filename)
|
38
|
+
FileUtils.mkdir_p(File.dirname(new_filename))
|
39
|
+
FileUtils.mv(@filename, new_filename)
|
40
|
+
@filename = new_filename
|
41
|
+
end
|
42
|
+
|
43
|
+
def strings?
|
44
|
+
!strings.empty?
|
45
|
+
end
|
46
|
+
|
47
|
+
def strings
|
48
|
+
Babelyoda::Ibtool.extract_strings(@filename, @language)
|
49
|
+
end
|
50
|
+
|
51
|
+
def localize(language, scm)
|
52
|
+
puts "Localizing #{filename} => #{File.localized(filename, language)}..."
|
53
|
+
assert_localization_target(language)
|
54
|
+
strings_fn = strings_filename(language)
|
55
|
+
$logger.error "No strings file found: #{strings_fn}" unless File.exist?(strings_fn)
|
56
|
+
Babelyoda::Ibtool.localize(filename, File.localized(filename, language), strings_fn)
|
57
|
+
end
|
58
|
+
|
59
|
+
def localize_incremental(language, scm)
|
60
|
+
assert_localization_target(language)
|
61
|
+
unless has_incremental_resources?(language, scm)
|
62
|
+
localize(language, scm)
|
63
|
+
else
|
64
|
+
puts "Incrementally localizing #{filename} => #{File.localized(filename, language)}..."
|
65
|
+
strings_fn = strings_filename(language)
|
66
|
+
$logger.error "No strings file found: #{strings_fn}" unless File.exist?(strings_fn)
|
67
|
+
|
68
|
+
scm.fetch_versions!(filename, File.localized(filename, language)) do |filenames|
|
69
|
+
Babelyoda::Ibtool.localize_incrementally(filename, File.localized(filename, language), strings_fn, filenames[0], filenames[1])
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def strings_filename(language = nil)
|
75
|
+
language ? File.localized(File.join(dirname, "#{basename}.strings"), language) : File.join(dirname, "#{basename}.strings")
|
76
|
+
end
|
77
|
+
|
78
|
+
def import_strings(scm)
|
79
|
+
Babelyoda::Ibtool.import_strings(filename, strings_filename)
|
80
|
+
end
|
81
|
+
|
82
|
+
private
|
83
|
+
|
84
|
+
def has_incremental_resources?(language, scm)
|
85
|
+
scm.version_exist?(filename) && scm.version_exist?(File.localized(filename, language))
|
86
|
+
end
|
87
|
+
|
88
|
+
def assert_localization_target(language)
|
89
|
+
raise "Can't localize a XIB file that has not been put into an .lproj folder: #{filename}" unless resourced?
|
90
|
+
raise "Can't localize #{@language} to #{language} for: #{filename}" if @language == language
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
data/lib/babelyoda.rb
ADDED
@@ -0,0 +1,207 @@
|
|
1
|
+
BABELYODA_PATH = File.expand_path(File.join(File.dirname(__FILE__), '..'))
|
2
|
+
|
3
|
+
require 'awesome_print'
|
4
|
+
|
5
|
+
require_relative 'babelyoda/genstrings'
|
6
|
+
require_relative 'babelyoda/git'
|
7
|
+
require_relative 'babelyoda/ibtool'
|
8
|
+
require_relative 'babelyoda/keyset'
|
9
|
+
require_relative 'babelyoda/localization_key'
|
10
|
+
require_relative 'babelyoda/localization_value'
|
11
|
+
require_relative 'babelyoda/rake'
|
12
|
+
require_relative 'babelyoda/specification'
|
13
|
+
require_relative 'babelyoda/tanker'
|
14
|
+
require_relative 'babelyoda/xib'
|
15
|
+
|
16
|
+
desc "Do a full localization cycle: push new strings, get translations and merge them"
|
17
|
+
task :babelyoda => ['babelyoda:push', 'babelyoda:pull'] do
|
18
|
+
end
|
19
|
+
|
20
|
+
namespace :babelyoda do
|
21
|
+
|
22
|
+
file 'Babelfile' do
|
23
|
+
Babelyoda::Specification.generate_default_babelfile
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "Create a basic bootstrap Babelfile"
|
27
|
+
task :init => 'Babelfile' do
|
28
|
+
end
|
29
|
+
|
30
|
+
Babelyoda::Rake.spec do |spec|
|
31
|
+
|
32
|
+
desc "Extract strings from sources"
|
33
|
+
task :extract_strings do
|
34
|
+
puts "Extracting strings from sources..."
|
35
|
+
dev_lang = spec.development_language
|
36
|
+
|
37
|
+
spec.scm.transaction("Extract strings from sources") do
|
38
|
+
Babelyoda::Genstrings.run(spec.source_files, dev_lang) do |keyset|
|
39
|
+
old_strings_filename = strings_filename(keyset.name, dev_lang)
|
40
|
+
old_strings = Babelyoda::Strings.new(old_strings_filename, dev_lang).read
|
41
|
+
old_strings.merge!(keyset)
|
42
|
+
old_strings.save!
|
43
|
+
puts " #{old_strings_filename}: #{old_strings.keys.size} keys"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "Extract strings from XIBs"
|
49
|
+
task :extract_xib_strings do
|
50
|
+
puts "Extracting .strings from XIBs..."
|
51
|
+
spec.scm.transaction("Extract strings from XIBs") do
|
52
|
+
spec.xib_files.each do |xib_filename|
|
53
|
+
xib = Babelyoda::Xib.new(xib_filename, spec.development_language)
|
54
|
+
next unless xib.extractable?(spec.development_language)
|
55
|
+
keyset = xib.strings
|
56
|
+
puts " #{xib_filename} => #{xib.strings_filename}"
|
57
|
+
Babelyoda::Strings.save_keyset(keyset, xib.strings_filename, spec.development_language)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
desc "Extracts localizable strings into the corresponding .strings files"
|
63
|
+
task :extract => [:extract_strings, :extract_xib_strings] do
|
64
|
+
end
|
65
|
+
|
66
|
+
desc "Create remote keysets for local keysets"
|
67
|
+
task :create_keysets => :extract do
|
68
|
+
# Create remote keysets for each local keyset if they don't exist.
|
69
|
+
puts "Creating remote keysets for local keysets..."
|
70
|
+
remote_keyset_names = spec.engine.list
|
71
|
+
spec.strings_files.each do |filename|
|
72
|
+
keyset_name = Babelyoda::Keyset.keyset_name(filename)
|
73
|
+
if remote_keyset_names.include?(keyset_name)
|
74
|
+
puts " Tanker: An existing keyset found: #{keyset_name}"
|
75
|
+
next
|
76
|
+
end
|
77
|
+
spec.engine.create(keyset_name)
|
78
|
+
puts " Tanker: Created NEW keyset: #{keyset_name}"
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
desc "Drops remote keys not found in local keysets"
|
83
|
+
task :drop_orphan_keys => :create_keysets do
|
84
|
+
puts "Dropping orphan keys..."
|
85
|
+
spec.strings_files.each do |filename|
|
86
|
+
strings = Babelyoda::Strings.new(filename, spec.development_language).read!
|
87
|
+
puts " Processing keyset: #{strings.name}"
|
88
|
+
remote_keyset = spec.engine.load_keyset(strings.name)
|
89
|
+
keys_to_drop = []
|
90
|
+
remote_keyset.keys.each_value do |key|
|
91
|
+
unless strings.keys.has_key?(key.id)
|
92
|
+
keys_to_drop << key.id
|
93
|
+
puts " Found orphan key: #{key.id}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
keys_to_drop.each do |key|
|
97
|
+
remote_keyset.keys.delete(key)
|
98
|
+
end
|
99
|
+
spec.engine.replace(remote_keyset)
|
100
|
+
puts " Dropped keys: #{keys_to_drop.size}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
desc "Pushes resources to the translators"
|
105
|
+
task :push => :drop_orphan_keys do
|
106
|
+
puts "Pushing local keys to the remote..."
|
107
|
+
spec.strings_files.each do |filename|
|
108
|
+
strings = Babelyoda::Strings.new(filename, spec.development_language).read!
|
109
|
+
puts " Processing keyset: #{strings.name}"
|
110
|
+
remote_keyset = spec.engine.load_keyset(strings.name, nil, :unapproved)
|
111
|
+
result = remote_keyset.merge!(strings, preserve: true)
|
112
|
+
remote_keyset.ensure_languages!(spec.all_languages)
|
113
|
+
spec.engine.replace(remote_keyset)
|
114
|
+
puts " New keys: #{result[:new]} Updated keys: #{result[:updated]}"
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
desc "Fetches remote strings and merges them down into local .string files"
|
119
|
+
task :fetch_strings do
|
120
|
+
puts "Fetching remote translations..."
|
121
|
+
spec.scm.transaction("Merge in remote translations") do
|
122
|
+
spec.strings_files.each do |filename|
|
123
|
+
keyset_name = Babelyoda::Keyset.keyset_name(filename)
|
124
|
+
remote_keyset = spec.engine.load_keyset(keyset_name, nil, :unapproved, true)
|
125
|
+
remote_keyset.drop_empty!
|
126
|
+
spec.all_languages.each do |language|
|
127
|
+
keyset_filename = strings_filename(keyset_name, language)
|
128
|
+
Babelyoda::Strings.save_keyset(remote_keyset, keyset_filename, language)
|
129
|
+
puts " #{keyset_filename}"
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
desc "Incrementally localizes XIB files"
|
136
|
+
task :localize_xibs do
|
137
|
+
puts "Translating XIB files..."
|
138
|
+
|
139
|
+
spec.scm.transaction("Localize XIB files") do
|
140
|
+
spec.xib_files.each do |filename|
|
141
|
+
xib = Babelyoda::Xib.new(filename, spec.development_language)
|
142
|
+
|
143
|
+
xib.import_strings(spec.scm)
|
144
|
+
spec.localization_languages.each do |language|
|
145
|
+
xib.localize_incremental(language, spec.scm)
|
146
|
+
end
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
spec.scm.transaction("Update XIB SHA1 version refs") do
|
151
|
+
spec.xib_files.each do |filename|
|
152
|
+
spec.scm.store_version!(filename)
|
153
|
+
spec.localization_languages.each do |language|
|
154
|
+
spec.scm.store_version!(File.localized(filename, language))
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
desc "Pull remote translations"
|
161
|
+
task :pull => [:fetch_strings, :localize_xibs] do
|
162
|
+
end
|
163
|
+
|
164
|
+
namespace :remote do
|
165
|
+
|
166
|
+
desc "List remote keysets"
|
167
|
+
task :list do
|
168
|
+
ap spec.engine.list
|
169
|
+
end
|
170
|
+
|
171
|
+
desc "Drop remote keysets in KEYSETS"
|
172
|
+
task :drop_keysets do
|
173
|
+
if ENV['KEYSETS']
|
174
|
+
keysets = ENV['KEYSETS'].split(',')
|
175
|
+
if keysets.include?('*')
|
176
|
+
keysets = spec.engine.list
|
177
|
+
puts "Dropping ALL keysets: #{keysets}"
|
178
|
+
else
|
179
|
+
puts "Dropping keysets: #{keysets}"
|
180
|
+
end
|
181
|
+
keysets.each do |keyset_name|
|
182
|
+
puts " Dropping: #{keyset_name}"
|
183
|
+
keyset = Babelyoda::Keyset.new(keyset_name)
|
184
|
+
key = Babelyoda::LocalizationKey.new("Dummy", "Dummy")
|
185
|
+
value = Babelyoda::LocalizationValue.new(:en, "Dummy")
|
186
|
+
key << value
|
187
|
+
keyset.merge_key!(key)
|
188
|
+
spec.engine.replace(keyset)
|
189
|
+
end
|
190
|
+
puts "All done!"
|
191
|
+
else
|
192
|
+
puts "Please provide keyset names to drop in the KEYSET environment variable. Separate by commas. Use * for ALL."
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
def strings_filename(keyset_name, lang)
|
202
|
+
if keyset_name.match(/\//)
|
203
|
+
File.join(File.dirname(keyset_name), "#{lang}.lproj", "#{File.basename(keyset_name)}.strings")
|
204
|
+
else
|
205
|
+
File.join("#{lang}.lproj", "#{keyset_name}.strings")
|
206
|
+
end
|
207
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
Babelyoda::Specification.new do |s|
|
2
|
+
s.name = 'YOUR PROJECT NAME HERE'
|
3
|
+
s.development_language = :en
|
4
|
+
s.localization_languages = [:ru, :uk, :tr]
|
5
|
+
s.engine = Babelyoda::Tanker.new do |t|
|
6
|
+
t.token = 'FIX: TANKER TOKEN HERE'
|
7
|
+
t.project_id = 'FIX: TANKER PROJECT ID HERE'
|
8
|
+
t.endpoint = 'FIX: TANKER END POINT HERE'
|
9
|
+
end
|
10
|
+
s.scm = Babelyoda::Git.new
|
11
|
+
s.source_files = FileList['Classes/**/*.{m,mm,h}']
|
12
|
+
s.resources_folder = 'Resources'
|
13
|
+
s.xib_files = FileList['{Classes,Resources}/**/en.lproj/*.{xib}']
|
14
|
+
s.strings_files = FileList['{Classes,Resources}/**/en.lproj/*.{strings}']
|
15
|
+
end
|