tml 4.3.1
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 +7 -0
- data/LICENSE +22 -0
- data/README.md +243 -0
- data/Rakefile +9 -0
- data/lib/tml.rb +56 -0
- data/lib/tml/api/client.rb +206 -0
- data/lib/tml/api/post_office.rb +71 -0
- data/lib/tml/application.rb +254 -0
- data/lib/tml/base.rb +116 -0
- data/lib/tml/cache.rb +143 -0
- data/lib/tml/cache_adapters/file.rb +89 -0
- data/lib/tml/cache_adapters/memcache.rb +104 -0
- data/lib/tml/cache_adapters/memory.rb +85 -0
- data/lib/tml/cache_adapters/redis.rb +108 -0
- data/lib/tml/config.rb +410 -0
- data/lib/tml/decorators/base.rb +52 -0
- data/lib/tml/decorators/default.rb +43 -0
- data/lib/tml/decorators/html.rb +102 -0
- data/lib/tml/exception.rb +35 -0
- data/lib/tml/ext/array.rb +86 -0
- data/lib/tml/ext/date.rb +99 -0
- data/lib/tml/ext/fixnum.rb +47 -0
- data/lib/tml/ext/hash.rb +99 -0
- data/lib/tml/ext/string.rb +56 -0
- data/lib/tml/ext/time.rb +89 -0
- data/lib/tml/generators/cache/base.rb +117 -0
- data/lib/tml/generators/cache/file.rb +159 -0
- data/lib/tml/language.rb +175 -0
- data/lib/tml/language_case.rb +105 -0
- data/lib/tml/language_case_rule.rb +76 -0
- data/lib/tml/language_context.rb +117 -0
- data/lib/tml/language_context_rule.rb +56 -0
- data/lib/tml/languages/en.json +1363 -0
- data/lib/tml/logger.rb +109 -0
- data/lib/tml/rules_engine/evaluator.rb +162 -0
- data/lib/tml/rules_engine/parser.rb +65 -0
- data/lib/tml/session.rb +199 -0
- data/lib/tml/source.rb +106 -0
- data/lib/tml/tokenizers/data.rb +96 -0
- data/lib/tml/tokenizers/decoration.rb +204 -0
- data/lib/tml/tokenizers/dom.rb +346 -0
- data/lib/tml/tokens/data.rb +403 -0
- data/lib/tml/tokens/method.rb +61 -0
- data/lib/tml/tokens/transform.rb +223 -0
- data/lib/tml/translation.rb +67 -0
- data/lib/tml/translation_key.rb +178 -0
- data/lib/tml/translator.rb +47 -0
- data/lib/tml/utils.rb +130 -0
- data/lib/tml/version.rb +34 -0
- metadata +121 -0
data/lib/tml/ext/hash.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
|
3
|
+
#
|
4
|
+
# _______ _ _ _ ______ _
|
5
|
+
# |__ __| | | | | (_) | ____| | |
|
6
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
7
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
8
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
9
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
10
|
+
# __/ |
|
11
|
+
# |___/
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
13
|
+
# a copy of this software and associated documentation files (the
|
14
|
+
# "Software"), to deal in the Software without restriction, including
|
15
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
16
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
17
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
18
|
+
# the following conditions:
|
19
|
+
#
|
20
|
+
# The above copyright notice and this permission notice shall be
|
21
|
+
# included in all copies or substantial portions of the Software.
|
22
|
+
#
|
23
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
24
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
25
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
26
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
27
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
28
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
29
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
30
|
+
#++
|
31
|
+
|
32
|
+
class Hash
|
33
|
+
#
|
34
|
+
# = Hash Recursive Merge
|
35
|
+
#
|
36
|
+
# Merges a Ruby Hash recursively, Also known as deep merge.
|
37
|
+
# Recursive version of Hash#merge and Hash#merge!.
|
38
|
+
#
|
39
|
+
# Category:: Ruby
|
40
|
+
# Package:: Hash
|
41
|
+
# Author:: Simone Carletti <weppos@weppos.net>
|
42
|
+
# Copyright:: 2007-2008 The Authors
|
43
|
+
# License:: MIT License
|
44
|
+
# Link:: http://www.simonecarletti.com/
|
45
|
+
# Source:: http://gist.github.com/gists/6391/
|
46
|
+
|
47
|
+
#
|
48
|
+
# Recursive version of Hash#merge!
|
49
|
+
#
|
50
|
+
# Adds the contents of +other_hash+ to +hsh+,
|
51
|
+
# merging entries in +hsh+ with duplicate keys with those from +other_hash+.
|
52
|
+
#
|
53
|
+
# Compared with Hash#merge!, this method supports nested hashes.
|
54
|
+
# When both +hsh+ and +other_hash+ contains an entry with the same key,
|
55
|
+
# it merges and returns the values from both arrays.
|
56
|
+
#
|
57
|
+
# h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
|
58
|
+
# h2 = {"b" => 254, "c" => 300, "c" => {"c1" => 16, "c3" => 94}}
|
59
|
+
# h1.rmerge!(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
|
60
|
+
#
|
61
|
+
# Simply using Hash#merge! would return
|
62
|
+
#
|
63
|
+
# h1.merge!(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
|
64
|
+
#
|
65
|
+
def rmerge!(other_hash)
|
66
|
+
merge!(other_hash) do |key, oldval, newval|
|
67
|
+
oldval.class == self.class ? oldval.rmerge!(newval) : newval
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
#
|
72
|
+
# Recursive version of Hash#merge
|
73
|
+
#
|
74
|
+
# Compared with Hash#merge!, this method supports nested hashes.
|
75
|
+
# When both +hsh+ and +other_hash+ contains an entry with the same key,
|
76
|
+
# it merges and returns the values from both arrays.
|
77
|
+
#
|
78
|
+
# Compared with Hash#merge, this method provides a different approch
|
79
|
+
# for merging nasted hashes.
|
80
|
+
# If the value of a given key is an Hash and both +other_hash+ abd +hsh
|
81
|
+
# includes the same key, the value is merged instead replaced with
|
82
|
+
# +other_hash+ value.
|
83
|
+
#
|
84
|
+
# h1 = {"a" => 100, "b" => 200, "c" => {"c1" => 12, "c2" => 14}}
|
85
|
+
# h2 = {"b" => 254, "c" => 300, "c" => {"c1" => 16, "c3" => 94}}
|
86
|
+
# h1.rmerge(h2) #=> {"a" => 100, "b" => 254, "c" => {"c1" => 16, "c2" => 14, "c3" => 94}}
|
87
|
+
#
|
88
|
+
# Simply using Hash#merge would return
|
89
|
+
#
|
90
|
+
# h1.merge(h2) #=> {"a" => 100, "b" = >254, "c" => {"c1" => 16, "c3" => 94}}
|
91
|
+
#
|
92
|
+
def rmerge(other_hash)
|
93
|
+
r = {}
|
94
|
+
merge(other_hash) do |key, oldval, newval|
|
95
|
+
r[key] = oldval.class == self.class ? oldval.rmerge(newval) : newval
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
|
3
|
+
#
|
4
|
+
# _______ _ _ _ ______ _
|
5
|
+
# |__ __| | | | | (_) | ____| | |
|
6
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
7
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
8
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
9
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
10
|
+
# __/ |
|
11
|
+
# |___/
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
13
|
+
# a copy of this software and associated documentation files (the
|
14
|
+
# "Software"), to deal in the Software without restriction, including
|
15
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
16
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
17
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
18
|
+
# the following conditions:
|
19
|
+
#
|
20
|
+
# The above copyright notice and this permission notice shall be
|
21
|
+
# included in all copies or substantial portions of the Software.
|
22
|
+
#
|
23
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
24
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
25
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
26
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
27
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
28
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
29
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
30
|
+
#++
|
31
|
+
|
32
|
+
class String
|
33
|
+
|
34
|
+
def translate(desc = '', tokens = {}, options = {})
|
35
|
+
Tml.session.target_language.translate(
|
36
|
+
Tml::Utils.normalize_tr_params(self, desc, tokens, options)
|
37
|
+
)
|
38
|
+
end
|
39
|
+
|
40
|
+
def trl(desc = '', tokens = {}, options = {})
|
41
|
+
Tml.session.target_language.translate(
|
42
|
+
Tml::Utils.normalize_tr_params(self, desc, tokens, options.merge(:skip_decorations => true))
|
43
|
+
)
|
44
|
+
end
|
45
|
+
|
46
|
+
def tml_translated
|
47
|
+
return self if frozen?
|
48
|
+
@tml_translated = true
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
def tml_translated?
|
53
|
+
@tml_translated
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
data/lib/tml/ext/time.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
|
3
|
+
#
|
4
|
+
# _______ _ _ _ ______ _
|
5
|
+
# |__ __| | | | | (_) | ____| | |
|
6
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
7
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
8
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
9
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
10
|
+
# __/ |
|
11
|
+
# |___/
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
13
|
+
# a copy of this software and associated documentation files (the
|
14
|
+
# "Software"), to deal in the Software without restriction, including
|
15
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
16
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
17
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
18
|
+
# the following conditions:
|
19
|
+
#
|
20
|
+
# The above copyright notice and this permission notice shall be
|
21
|
+
# included in all copies or substantial portions of the Software.
|
22
|
+
#
|
23
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
24
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
25
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
26
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
27
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
28
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
29
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
30
|
+
#++
|
31
|
+
|
32
|
+
class Time
|
33
|
+
|
34
|
+
def translate(format = :default, options = {})
|
35
|
+
language = Tml.session.target_language
|
36
|
+
|
37
|
+
label = (format.is_a?(String) ? format.clone : Tml.config.default_date_formats[format].clone)
|
38
|
+
symbols = label.scan(/(%\w)/).flatten.uniq
|
39
|
+
|
40
|
+
selected_tokens = []
|
41
|
+
using_tokens = label.index('{')
|
42
|
+
|
43
|
+
if using_tokens
|
44
|
+
selected_tokens = Tml::Tokens::Data.parse(label).collect{ |token| token.name(:parens => true) }
|
45
|
+
else
|
46
|
+
symbols.each do |symbol|
|
47
|
+
token = Tml.config.strftime_symbol_to_token(symbol)
|
48
|
+
next unless token
|
49
|
+
selected_tokens << token
|
50
|
+
label.gsub!(symbol, token)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
tokens = {}
|
55
|
+
selected_tokens.each do |token|
|
56
|
+
case token
|
57
|
+
when '{days}' then tokens[:days] = options[:with_leading_zero] ? day.with_leading_zero : day.to_s
|
58
|
+
when '{year_days}' then tokens[:year_days] = options[:with_leading_zero] ? yday.with_leading_zero : yday.to_s
|
59
|
+
when '{months}' then tokens[:months] = options[:with_leading_zero] ? month.with_leading_zero : month.to_s
|
60
|
+
when '{week_num}' then tokens[:week_num] = wday
|
61
|
+
when '{week_days}' then tokens[:week_days] = strftime('%w')
|
62
|
+
when '{short_years}' then tokens[:short_years] = strftime('%y')
|
63
|
+
when '{years}' then tokens[:years] = year
|
64
|
+
when '{short_week_day_name}' then tokens[:short_week_day_name] = language.tr(Tml.config.default_abbr_day_name(wday), 'Short name for a day of a week', {}, options)
|
65
|
+
when '{week_day_name}' then tokens[:week_day_name] = language.tr(Tml.config.default_day_name(wday), 'Day of a week', {}, options)
|
66
|
+
when '{short_month_name}' then tokens[:short_month_name] = language.tr(Tml.config.default_abbr_month_name(month - 1), 'Short month name', {}, options)
|
67
|
+
when '{month_name}' then tokens[:month_name] = language.tr(Tml.config.default_month_name(month - 1), 'Month name', {}, options)
|
68
|
+
when '{am_pm}' then tokens[:am_pm] = language.tr(strftime('%p'), 'Meridian indicator', {}, options)
|
69
|
+
when '{full_hours}' then tokens[:full_hours] = hour
|
70
|
+
when '{short_hours}' then tokens[:short_hours] = strftime('%I')
|
71
|
+
when '{trimed_hour}' then tokens[:trimed_hour] = strftime('%l')
|
72
|
+
when '{minutes}' then tokens[:minutes] = strftime('%M')
|
73
|
+
when '{seconds}' then tokens[:seconds] = strftime('%S')
|
74
|
+
when '{since_epoch}' then tokens[:since_epoch] = strftime('%s')
|
75
|
+
when '{day_of_month}' then tokens[:day_of_month] = strftime('%e')
|
76
|
+
else
|
77
|
+
''
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
language.tr(label, nil, tokens, options)
|
82
|
+
end
|
83
|
+
alias :tr :translate
|
84
|
+
|
85
|
+
def trl(format = :default, options = {})
|
86
|
+
tr(format, options.merge!(:skip_decorations => true))
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
|
3
|
+
#
|
4
|
+
# _______ _ _ _ ______ _
|
5
|
+
# |__ __| | | | | (_) | ____| | |
|
6
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
7
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
8
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
9
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
10
|
+
# __/ |
|
11
|
+
# |___/
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
13
|
+
# a copy of this software and associated documentation files (the
|
14
|
+
# "Software"), to deal in the Software without restriction, including
|
15
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
16
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
17
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
18
|
+
# the following conditions:
|
19
|
+
#
|
20
|
+
# The above copyright notice and this permission notice shall be
|
21
|
+
# included in all copies or substantial portions of the Software.
|
22
|
+
#
|
23
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
24
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
25
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
26
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
27
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
28
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
29
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
30
|
+
#++
|
31
|
+
|
32
|
+
class Tml::Generators::Cache::Base
|
33
|
+
|
34
|
+
attr_accessor :started_at, :finished_at
|
35
|
+
|
36
|
+
def log(msg)
|
37
|
+
msg = "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}: #{msg}"
|
38
|
+
puts msg
|
39
|
+
Tml.logger.debug(msg)
|
40
|
+
end
|
41
|
+
|
42
|
+
def cache_path
|
43
|
+
raise Tml::Exception.new('Must be implemented by the subclass')
|
44
|
+
end
|
45
|
+
|
46
|
+
def cache_version
|
47
|
+
@started_at.strftime('%Y%m%d%H%M%S')
|
48
|
+
end
|
49
|
+
|
50
|
+
def cache(key, data)
|
51
|
+
raise Tml::Exception.new('Must be implemented by the subclass')
|
52
|
+
end
|
53
|
+
|
54
|
+
def execute
|
55
|
+
raise Tml::Exception.new('Must be implemented by the subclass')
|
56
|
+
end
|
57
|
+
|
58
|
+
def run
|
59
|
+
prepare
|
60
|
+
execute
|
61
|
+
finalize
|
62
|
+
end
|
63
|
+
|
64
|
+
def prepare
|
65
|
+
@started_at = Time.now
|
66
|
+
Tml.session.init
|
67
|
+
cache_path
|
68
|
+
end
|
69
|
+
|
70
|
+
def api_client
|
71
|
+
Tml.session.application.api_client
|
72
|
+
end
|
73
|
+
|
74
|
+
def application
|
75
|
+
@application ||= api_client.get('applications/current', {:definition => true})
|
76
|
+
end
|
77
|
+
|
78
|
+
def languages
|
79
|
+
application['languages']
|
80
|
+
end
|
81
|
+
|
82
|
+
def finalize
|
83
|
+
@finished_at = Time.now
|
84
|
+
log("Cache has been stored in #{cache_path}")
|
85
|
+
log("Cache generation took #{@finished_at - @started_at} mls.")
|
86
|
+
log('Done.')
|
87
|
+
end
|
88
|
+
|
89
|
+
def cache_application
|
90
|
+
log('Downloading application...')
|
91
|
+
cache(Tml::Application.cache_key, application)
|
92
|
+
log('Application has been cached.')
|
93
|
+
end
|
94
|
+
|
95
|
+
def cache_languages
|
96
|
+
log('Downloading languages...')
|
97
|
+
unless application['languages']
|
98
|
+
log('No languages are available...')
|
99
|
+
return
|
100
|
+
end
|
101
|
+
languages.each do |lang|
|
102
|
+
language = api_client.get("languages/#{lang['locale']}", :definition => true)
|
103
|
+
cache(Tml::Language.cache_key(language['locale']), language)
|
104
|
+
end
|
105
|
+
log("#{application['languages'].count} languages have been cached.")
|
106
|
+
end
|
107
|
+
|
108
|
+
def symlink_path
|
109
|
+
"#{Tml.config.cache[:path]}/current"
|
110
|
+
end
|
111
|
+
|
112
|
+
def generate_symlink
|
113
|
+
FileUtils.rm(symlink_path) if File.exist?(symlink_path)
|
114
|
+
FileUtils.ln_s(cache_version, symlink_path)
|
115
|
+
log('Symlink has been updated.')
|
116
|
+
end
|
117
|
+
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
|
3
|
+
#
|
4
|
+
# _______ _ _ _ ______ _
|
5
|
+
# |__ __| | | | | (_) | ____| | |
|
6
|
+
# | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
|
7
|
+
# | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
|
8
|
+
# | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
|
9
|
+
# |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
|
10
|
+
# __/ |
|
11
|
+
# |___/
|
12
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
13
|
+
# a copy of this software and associated documentation files (the
|
14
|
+
# "Software"), to deal in the Software without restriction, including
|
15
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
16
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
17
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
18
|
+
# the following conditions:
|
19
|
+
#
|
20
|
+
# The above copyright notice and this permission notice shall be
|
21
|
+
# included in all copies or substantial portions of the Software.
|
22
|
+
#
|
23
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
24
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
25
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
26
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
27
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
28
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
29
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
30
|
+
#++
|
31
|
+
|
32
|
+
class Tml::Generators::Cache::File < Tml::Generators::Cache::Base
|
33
|
+
|
34
|
+
def cache_path
|
35
|
+
@cache_path ||= begin
|
36
|
+
path = "#{Tml.config.cache[:path]}/#{cache_version}"
|
37
|
+
log("Cache will be stored in #{path}")
|
38
|
+
FileUtils.mkdir_p(path)
|
39
|
+
FileUtils.chmod(0777, path)
|
40
|
+
path
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def file_path(key)
|
45
|
+
path = key.split('/')
|
46
|
+
if path.count > 1
|
47
|
+
filename = path.pop
|
48
|
+
path = File.join(cache_path, path)
|
49
|
+
FileUtils.mkdir_p(path)
|
50
|
+
File.join(path, "#{filename}.json")
|
51
|
+
else
|
52
|
+
File.join(cache_path, "#{path.first}.json")
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
def cache(key, data)
|
57
|
+
File.open(file_path(key), 'w') { |file| file.write(JSON.pretty_generate(data)) }
|
58
|
+
end
|
59
|
+
|
60
|
+
def execute
|
61
|
+
cache_application
|
62
|
+
cache_languages
|
63
|
+
cache_translations
|
64
|
+
generate_symlink
|
65
|
+
end
|
66
|
+
|
67
|
+
def cache_translations
|
68
|
+
log('Downloading translations...')
|
69
|
+
|
70
|
+
languages.each do |language|
|
71
|
+
log("Downloading #{language['english_name']} language...")
|
72
|
+
|
73
|
+
if Tml.config.cache[:segmented]
|
74
|
+
api_client.paginate('applications/current/sources') do |source|
|
75
|
+
next unless source['source']
|
76
|
+
|
77
|
+
cache_path = Tml::Source.cache_key(language['locale'], source['source'])
|
78
|
+
log("Downloading #{source['source']} in #{language['locale']} to #{cache_path}...")
|
79
|
+
|
80
|
+
data = api_client.get("sources/#{source['key']}/translations", {:locale => language['locale'], :original => true, :per_page => 1000})
|
81
|
+
cache(cache_path, data)
|
82
|
+
end
|
83
|
+
else
|
84
|
+
cache_path = Tml::Application.translations_cache_key(language['locale'])
|
85
|
+
log("Downloading translations in #{language['locale']} to #{cache_path}...")
|
86
|
+
data = {}
|
87
|
+
api_client.paginate('applications/current/translations', {:locale => language['locale'], :original => true, :per_page => 1000}) do |translations|
|
88
|
+
data.merge!(translations)
|
89
|
+
end
|
90
|
+
cache(cache_path, data)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def rollback
|
96
|
+
folders = Dir["#{Tml.config.cache[:path]}/*"]
|
97
|
+
folders.delete_if{|e| e.index('current')}.sort!
|
98
|
+
|
99
|
+
if File.exist?(symlink_path)
|
100
|
+
current_dest = File.readlink("#{Tml.config.cache[:path]}/current")
|
101
|
+
current_dest = "#{Tml.config.cache[:path]}/#{current_dest}"
|
102
|
+
else
|
103
|
+
current_dest = 'undefined'
|
104
|
+
end
|
105
|
+
|
106
|
+
index = folders.index(current_dest)
|
107
|
+
|
108
|
+
if index == 0
|
109
|
+
log('There are no earlier cache versions')
|
110
|
+
return
|
111
|
+
end
|
112
|
+
|
113
|
+
if index.nil?
|
114
|
+
new_version_path = folders[folders.size-1]
|
115
|
+
else
|
116
|
+
new_version_path = folders[index-1]
|
117
|
+
end
|
118
|
+
|
119
|
+
new_version_path = new_version_path.split('/').last
|
120
|
+
|
121
|
+
FileUtils.rm(symlink_path) if File.exist?(symlink_path)
|
122
|
+
FileUtils.ln_s(new_version_path, symlink_path)
|
123
|
+
|
124
|
+
log("Cache has been rolled back to version #{new_version_path}.")
|
125
|
+
end
|
126
|
+
|
127
|
+
def rollup
|
128
|
+
folders = Dir["#{Tml.config.cache[:path]}/*"]
|
129
|
+
folders.delete_if{|e| e.index('current')}.sort!
|
130
|
+
|
131
|
+
if File.exist?(symlink_path)
|
132
|
+
current_dest = File.readlink("#{Tml.config.cache[:path]}/current")
|
133
|
+
current_dest = "#{Tml.config.cache[:path]}/#{current_dest}"
|
134
|
+
else
|
135
|
+
current_dest = 'undefined'
|
136
|
+
end
|
137
|
+
|
138
|
+
index = folders.index(current_dest)
|
139
|
+
|
140
|
+
if index == (folders.size - 1)
|
141
|
+
log('You are on the latest version of the cache already. No further versions are available')
|
142
|
+
return
|
143
|
+
end
|
144
|
+
|
145
|
+
if index.nil?
|
146
|
+
new_version_path = folders[0]
|
147
|
+
else
|
148
|
+
new_version_path = folders[index+1]
|
149
|
+
end
|
150
|
+
|
151
|
+
new_version_path = new_version_path.split('/').last
|
152
|
+
|
153
|
+
FileUtils.rm(symlink_path) if File.exist?(symlink_path)
|
154
|
+
FileUtils.ln_s(new_version_path, symlink_path)
|
155
|
+
|
156
|
+
log("Cache has been upgraded to version #{new_version_path}.")
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|