air18n 0.1.57 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/air18n.rb +1 -0
- data/lib/air18n/class_methods.rb +2 -1
- data/lib/air18n/metrics.rb +211 -0
- data/lib/air18n/prim_and_proper.rb +8 -0
- data/lib/air18n/version.rb +1 -1
- data/spec/lib/air18n/backend_spec.rb +5 -5
- data/spec/lib/air18n/metrics_spec.rb +276 -0
- data/spec/lib/air18n/prim_and_proper_spec.rb +13 -0
- metadata +6 -3
data/lib/air18n.rb
CHANGED
data/lib/air18n/class_methods.rb
CHANGED
@@ -216,7 +216,8 @@ module Air18n
|
|
216
216
|
|
217
217
|
# Use locale fallbacks that always include default locale as the last
|
218
218
|
# fallback.
|
219
|
-
@fallbacks
|
219
|
+
@fallbacks ||= I18n::Locale::Fallbacks.new
|
220
|
+
@fallbacks.defaults = [default_locale]
|
220
221
|
|
221
222
|
# Make the single instance of Air18n::Backend.
|
222
223
|
@air18n_backend = Air18n::Backend.new
|
@@ -0,0 +1,211 @@
|
|
1
|
+
module Air18n
|
2
|
+
module Metrics
|
3
|
+
TARGET_PRIORITY_PHRASE_TRANSLATION_PERCENT = 98
|
4
|
+
|
5
|
+
def self.translation_progress(page_ids)
|
6
|
+
search_scope = Air18n::Phrase.still_used
|
7
|
+
search_scope = search_scope.select(
|
8
|
+
'`phrases`.`id`, `phrases`.`key`, ' +
|
9
|
+
'`phrase_translations`.`locale` AS latest_translation_locale, ' +
|
10
|
+
'`phrase_translations`.`user_id` AS latest_translation_user_id, ' +
|
11
|
+
'`phrase_translations`.`created_at` AS latest_translation_created_at, ' +
|
12
|
+
'`phrase_translations`.`is_stale` AS latest_translation_is_stale, ' +
|
13
|
+
'`phrase_translations`.`is_verification` AS latest_translation_is_verification'
|
14
|
+
)
|
15
|
+
search_scope = search_scope.pull_in_all_up_to_date_phrase_translations
|
16
|
+
search_scope = search_scope.group('`phrases`.`id`, `phrase_translations`.`phrase_id`, `latest_translation_locale`')
|
17
|
+
|
18
|
+
if page_ids.present?
|
19
|
+
search_scope = search_scope.joins(:phrase_screenshots)
|
20
|
+
conditions = page_ids.map do |page_id|
|
21
|
+
controller_action = Air18n::PhraseScreenshot.deserialize_page_id(page_id)
|
22
|
+
"(phrase_screenshots.controller = '#{controller_action.controller}' AND phrase_screenshots.action = '#{controller_action.action}')"
|
23
|
+
end
|
24
|
+
search_scope = search_scope.where(conditions.join(' OR '))
|
25
|
+
end
|
26
|
+
|
27
|
+
progress = {}
|
28
|
+
|
29
|
+
phrases_and_translations = search_scope.all
|
30
|
+
|
31
|
+
# This block is useful for debugging.
|
32
|
+
if false
|
33
|
+
LoggingHelper.info "Phrases and translations:"
|
34
|
+
phrases_and_translations.each do |thing|
|
35
|
+
LoggingHelper.info "key #{thing.key} locale #{thing.latest_translation_locale} user #{thing.latest_translation_user_id} at #{thing.latest_translation_created_at} stale? #{thing.latest_translation_is_stale} verified? #{thing.latest_translation_is_verification}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
priority_keys = phrases_and_translations.map { |phrase_and_translation| phrase_and_translation.key }.uniq
|
40
|
+
number_of_priority_phrases = priority_keys.size
|
41
|
+
number_of_priority_words = priority_keys.map { |k| word_counts[k] }.sum
|
42
|
+
locale_to_translations = phrases_and_translations.group_by { |phrase_and_translation| phrase_and_translation.latest_translation_locale }
|
43
|
+
locale_to_translations.each do |locale, phrases_and_translations_for_locale|
|
44
|
+
if locale.present?
|
45
|
+
locale = locale.to_sym
|
46
|
+
progress[locale] ||= {}
|
47
|
+
phrases_with_translations_for_locale = phrases_and_translations_for_locale.find_all { |phrase_and_translation| phrase_and_translation.latest_translation_user_id }
|
48
|
+
phrases_with_verifications_for_locale = phrases_with_translations_for_locale.find_all { |phrase_and_translation| true_value?(phrase_and_translation.latest_translation_is_verification) }
|
49
|
+
|
50
|
+
words_with_translations_for_locale = phrases_with_translations_for_locale.map { |p| word_counts[p.key] }.sum
|
51
|
+
words_with_verifications_for_locale = phrases_with_verifications_for_locale.map { |p| word_counts[p.key] }.sum
|
52
|
+
progress[locale][:phrases] = number_of_priority_phrases
|
53
|
+
progress[locale][:words] = number_of_priority_words
|
54
|
+
|
55
|
+
progress[locale][:phrases_translated] = phrases_with_translations_for_locale.size
|
56
|
+
progress[locale][:words_translated] = words_with_translations_for_locale
|
57
|
+
|
58
|
+
progress[locale][:phrases_verified] = phrases_with_verifications_for_locale.size
|
59
|
+
progress[locale][:words_verified] = words_with_verifications_for_locale
|
60
|
+
|
61
|
+
phrases_translated_in_last_day = phrases_with_translations_for_locale.find_all { |phrase_and_translation| since?(phrase_and_translation.latest_translation_created_at, 1.day.ago) }
|
62
|
+
phrases_translated_in_last_week = phrases_with_translations_for_locale.find_all { |phrase_and_translation| since?(phrase_and_translation.latest_translation_created_at, 1.week.ago) }
|
63
|
+
progress[locale][:phrases_translated_in_last_day] = phrases_translated_in_last_day.size
|
64
|
+
progress[locale][:words_translated_in_last_day] = phrases_translated_in_last_day.map { |p| word_counts[p.key] }.sum
|
65
|
+
progress[locale][:phrases_translated_in_last_week] = phrases_translated_in_last_week.size
|
66
|
+
progress[locale][:words_translated_in_last_week] = phrases_translated_in_last_week.map { |p| word_counts[p.key] }.sum
|
67
|
+
|
68
|
+
progress[locale][:phrases_translated_percent] = (100 * progress[locale][:phrases_translated].to_f / progress[locale][:phrases]).round
|
69
|
+
progress[locale][:words_translated_percent] = (100 * progress[locale][:words_translated].to_f / progress[locale][:words]).round
|
70
|
+
progress[locale][:phrases_verified_percent] = (100 * progress[locale][:phrases_verified].to_f / progress[locale][:phrases]).round
|
71
|
+
progress[locale][:words_verified_percent] = (100 * progress[locale][:words_verified].to_f / progress[locale][:words]).round
|
72
|
+
if progress[locale][:phrases_translated_percent] >= TARGET_PRIORITY_PHRASE_TRANSLATION_PERCENT
|
73
|
+
progress[locale][:phrases_progress] = :good
|
74
|
+
elsif progress[locale][:phrases_translated_in_last_day] < 50
|
75
|
+
progress[locale][:phrases_progress] = :bad
|
76
|
+
else
|
77
|
+
progress[locale][:phrases_progress] = :okay
|
78
|
+
end
|
79
|
+
|
80
|
+
progress[locale][:phrases_remaining_to_translate] = progress[locale][:phrases] - progress[locale][:phrases_translated]
|
81
|
+
progress[locale][:words_remaining_to_translate] = progress[locale][:words] - progress[locale][:words_translated]
|
82
|
+
|
83
|
+
progress[locale][:phrases_remaining_to_verify] = progress[locale][:phrases] - progress[locale][:phrases_verified]
|
84
|
+
progress[locale][:words_remaining_to_verify] = progress[locale][:words] - progress[locale][:words_verified]
|
85
|
+
|
86
|
+
progress[locale][:translators] = phrases_with_translations_for_locale.inject(Set.new) do |carry, value|
|
87
|
+
if since?(value.latest_translation_created_at, 28.days.ago)
|
88
|
+
carry.add(value.latest_translation_user_id)
|
89
|
+
end
|
90
|
+
carry
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
progress
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.translator_progress(locale, user_id)
|
99
|
+
scope = PhraseTranslation.where(:locale => locale).where(:user_id => user_id)
|
100
|
+
scope = scope.where('created_at >= ?', 28.days.ago)
|
101
|
+
scope = scope.group(:phrase_id, :source_hash)
|
102
|
+
scope.select("`id`, `key`, `source_word_count`")
|
103
|
+
|
104
|
+
words_translated_last_month = 0
|
105
|
+
words_translated_last_week = 0
|
106
|
+
words_verified_last_month = 0
|
107
|
+
words_verified_last_week = 0
|
108
|
+
phrases_translated_last_month = 0
|
109
|
+
number_of_later_modified_phrases_last_month = 0
|
110
|
+
phrases_translated = {}
|
111
|
+
scope.find_each do |pt|
|
112
|
+
if pt.created_at >= 1.week.ago
|
113
|
+
if pt.is_verification?
|
114
|
+
words_verified_last_week += pt.source_word_count
|
115
|
+
else
|
116
|
+
words_translated_last_week += pt.source_word_count
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
if pt.is_verification?
|
121
|
+
words_verified_last_month += pt.source_word_count
|
122
|
+
else
|
123
|
+
words_translated_last_month += pt.source_word_count
|
124
|
+
end
|
125
|
+
|
126
|
+
if !pt.is_verification?
|
127
|
+
later_modifications = PhraseTranslation.
|
128
|
+
where(:phrase_id => pt.phrase_id, :source_hash => pt.source_hash).
|
129
|
+
where('created_at > ?', pt.created_at).
|
130
|
+
where('user_id != ?', pt.user_id).
|
131
|
+
where('payment_details NOT LIKE ?', '{"v3":{"t":0,%').
|
132
|
+
count
|
133
|
+
if later_modifications > 0
|
134
|
+
number_of_later_modified_phrases_last_month += 1
|
135
|
+
end
|
136
|
+
phrases_translated_last_month += 1
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
daily_average = (words_translated_last_month + words_verified_last_month) / 28
|
141
|
+
later_modified_percent = if phrases_translated_last_month == 0
|
142
|
+
0
|
143
|
+
else
|
144
|
+
(100.0 * number_of_later_modified_phrases_last_month.to_f / phrases_translated_last_month).round
|
145
|
+
end
|
146
|
+
classification = words_translated_last_month > words_verified_last_month ? :translator : :verifier
|
147
|
+
|
148
|
+
{
|
149
|
+
:user_id => user_id,
|
150
|
+
:classification => classification,
|
151
|
+
:phrases_translated_last_month => phrases_translated_last_month,
|
152
|
+
:words_translated_last_month => words_translated_last_month,
|
153
|
+
:words_translated_last_week => words_translated_last_week,
|
154
|
+
:words_verified_last_month => words_verified_last_month,
|
155
|
+
:words_verified_last_week => words_verified_last_week,
|
156
|
+
:words_verified_last_week => words_verified_last_week,
|
157
|
+
:daily_average => daily_average,
|
158
|
+
:number_of_later_modified_phrases_last_month => number_of_later_modified_phrases_last_month,
|
159
|
+
:later_modified_percent => later_modified_percent
|
160
|
+
}
|
161
|
+
end
|
162
|
+
|
163
|
+
# Computes translation progress for all pages, then translator progress for
|
164
|
+
# all translators in each locale.
|
165
|
+
def self.metrics_suite
|
166
|
+
p = translation_progress(nil)
|
167
|
+
p.each do |locale, info|
|
168
|
+
info[:translator_progress] = {}
|
169
|
+
info[:translators].each do |user_id|
|
170
|
+
info[:translator_progress][user_id] = translator_progress(locale, user_id)
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Returns scope for searching for most recent PhraseTranslations of a
|
176
|
+
# translator.
|
177
|
+
def self.recent_work(locale, user_id)
|
178
|
+
scope = Air18n::PhraseTranslation
|
179
|
+
scope = scope.order('`phrase_translations`.`created_at` DESC')
|
180
|
+
scope.includes(:phrase_revision)
|
181
|
+
if user_id.present?
|
182
|
+
scope = scope.where(:user_id => user_id)
|
183
|
+
end
|
184
|
+
if locale.present?
|
185
|
+
scope = scope.where(:locale => locale)
|
186
|
+
end
|
187
|
+
scope
|
188
|
+
end
|
189
|
+
|
190
|
+
private
|
191
|
+
|
192
|
+
def self.word_counts
|
193
|
+
# Set up a map of phrase key -> word count.
|
194
|
+
@word_counts ||=
|
195
|
+
{}.tap do |ret|
|
196
|
+
Air18n::Phrase.still_used.find_each do |p|
|
197
|
+
ret[p.key] = PhraseTranslation.segment(p.value).size
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def self.since?(created_at, time_ago)
|
203
|
+
time_obj = created_at.is_a?(String) ? Time.parse(created_at) : created_at
|
204
|
+
time_obj >= time_ago
|
205
|
+
end
|
206
|
+
|
207
|
+
def self.true_value?(tf_value)
|
208
|
+
tf_value == 1 || tf_value == "t" || tf_value == "1"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
@@ -12,6 +12,7 @@ module Air18n
|
|
12
12
|
:"en-CA" => AmericanToCanadian.new,
|
13
13
|
:"en-GB" => AmericanToBritish.new,
|
14
14
|
:"en-NZ" => AmericanToKiwi.new,
|
15
|
+
:"en-SG" => AmericanToSinglish.new,
|
15
16
|
},
|
16
17
|
:de => { :"de-CH" => GermanToSwissGerman.new }
|
17
18
|
}
|
@@ -127,6 +128,13 @@ module Air18n
|
|
127
128
|
end
|
128
129
|
end
|
129
130
|
|
131
|
+
# Singlish is just normal Colonial English for now.
|
132
|
+
class AmericanToSinglish < AmericanToColonial
|
133
|
+
def initialize
|
134
|
+
super
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
130
138
|
# Only changes
|
131
139
|
# "[flav]or" to "[flav]our"
|
132
140
|
# "[travel]ed" to "[travel]led"
|
data/lib/air18n/version.rb
CHANGED
@@ -158,12 +158,12 @@ describe Air18n::Backend do
|
|
158
158
|
context 'Language fallbacks' do
|
159
159
|
it 'should fall back to default locale' do
|
160
160
|
old_default_locale = I18n.default_locale
|
161
|
-
I18n.reset(:
|
161
|
+
I18n.reset(:zq)
|
162
162
|
@backend = Air18n::Backend.new
|
163
|
-
@backend.lookup(:
|
164
|
-
@backend.lookup(:
|
165
|
-
@backend.lookup(:
|
166
|
-
@backend.lookup(:
|
163
|
+
@backend.lookup(:zq, 'fallbacks, key 1', @scope, :default => 'merci').should == 'merci'
|
164
|
+
@backend.lookup(:zv, 'fallbacks, key 1', @scope, :default => 'merci').should == 'merci'
|
165
|
+
@backend.lookup(:zv, 'fallbacks, key 1', @scope).should == 'merci'
|
166
|
+
@backend.lookup(:zy, 'fallbacks, key 1', @scope).should == 'merci'
|
167
167
|
|
168
168
|
# Restore the old default locale.
|
169
169
|
I18n.reset(old_default_locale)
|
@@ -0,0 +1,276 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Air18n::Metrics do
|
4
|
+
before :all do
|
5
|
+
@translator1_fr_id = 7
|
6
|
+
@translator2_fr_id = 9
|
7
|
+
|
8
|
+
# Translator 3 for French hasn't translated for 2 months. Shouldn't be
|
9
|
+
# included in recent translators list.
|
10
|
+
@translator3_fr_id = 11
|
11
|
+
|
12
|
+
# Translator 4 fixes translator 1 and 2's work.
|
13
|
+
@translator4_fr_id = 17
|
14
|
+
|
15
|
+
@translator1_it_id = 13
|
16
|
+
@translator2_it_id = 19
|
17
|
+
|
18
|
+
@translator1_ko_id = 15
|
19
|
+
|
20
|
+
@phrase1 = FactoryGirl.create(:phrase, :value => 'one two three four five six seven eight nine')
|
21
|
+
@phrase2 = FactoryGirl.create(:phrase)
|
22
|
+
@phrase3 = FactoryGirl.create(:phrase)
|
23
|
+
@phrase4 = FactoryGirl.create(:phrase)
|
24
|
+
@phrase5 = FactoryGirl.create(:phrase)
|
25
|
+
@phrase6 = FactoryGirl.create(:phrase)
|
26
|
+
@phrase7 = FactoryGirl.create(:phrase)
|
27
|
+
|
28
|
+
# info#press is a manually-prioritized page.
|
29
|
+
@phrase3_screenshot1 = FactoryGirl.create(
|
30
|
+
:phrase_screenshot,
|
31
|
+
:controller => 'info',
|
32
|
+
:action => 'press',
|
33
|
+
:phrase => @phrase3)
|
34
|
+
|
35
|
+
# info#unimportant is unimportant.
|
36
|
+
@phrase2_screenshot1 = FactoryGirl.create(
|
37
|
+
:phrase_screenshot,
|
38
|
+
:controller => 'info',
|
39
|
+
:action => 'unimportant',
|
40
|
+
:phrase => @phrase2)
|
41
|
+
|
42
|
+
# info#obsolete_page is a obsolete page with only obsolete phrases.
|
43
|
+
@phrase4_screenshot1 = FactoryGirl.create(
|
44
|
+
:phrase_screenshot,
|
45
|
+
:controller => 'info',
|
46
|
+
:action => 'obsolete_page',
|
47
|
+
:phrase => @phrase4)
|
48
|
+
|
49
|
+
# home#index is high-pageviews high priority.
|
50
|
+
@phrase1_screenshot1 = FactoryGirl.create(
|
51
|
+
:phrase_screenshot,
|
52
|
+
:controller => 'home',
|
53
|
+
:action => 'index',
|
54
|
+
:phrase => @phrase1)
|
55
|
+
@phrase3_screenshot2 = FactoryGirl.create(
|
56
|
+
:phrase_screenshot,
|
57
|
+
:controller => 'home',
|
58
|
+
:action => 'index',
|
59
|
+
:phrase => @phrase3)
|
60
|
+
@phrase5_screenshot1 = FactoryGirl.create(
|
61
|
+
:phrase_screenshot,
|
62
|
+
:controller => 'home',
|
63
|
+
:action => 'index',
|
64
|
+
:phrase => @phrase5)
|
65
|
+
@phrase6_screenshot1 = FactoryGirl.create(
|
66
|
+
:phrase_screenshot,
|
67
|
+
:controller => 'home',
|
68
|
+
:action => 'index',
|
69
|
+
:phrase => @phrase6)
|
70
|
+
@phrase7_screenshot1 = FactoryGirl.create(
|
71
|
+
:phrase_screenshot,
|
72
|
+
:controller => 'home',
|
73
|
+
:action => 'index',
|
74
|
+
:phrase => @phrase7)
|
75
|
+
|
76
|
+
without_timestamping_of Air18n::PhraseTranslation do
|
77
|
+
@translation0_of_phrase1_fr_today = FactoryGirl.create(
|
78
|
+
:phrase_translation,
|
79
|
+
:locale => 'fr',
|
80
|
+
:phrase => @phrase1,
|
81
|
+
:user_id => @translator1_fr_id,
|
82
|
+
:created_at => 3.hours.ago)
|
83
|
+
@translation1_of_phrase1_fr_today = FactoryGirl.create(
|
84
|
+
:phrase_translation,
|
85
|
+
:locale => 'fr',
|
86
|
+
:phrase => @phrase1,
|
87
|
+
:user_id => @translator1_fr_id,
|
88
|
+
:created_at => 2.hours.ago)
|
89
|
+
@verification1_of_phrase1_fr_today = FactoryGirl.create(
|
90
|
+
:phrase_translation,
|
91
|
+
:locale => 'fr',
|
92
|
+
:phrase => @phrase1,
|
93
|
+
:user_id => @translator2_fr_id,
|
94
|
+
:is_verification => true,
|
95
|
+
:created_at => 1.hour.ago)
|
96
|
+
@translation2_of_phrase1_fr_today = FactoryGirl.create(
|
97
|
+
:phrase_translation,
|
98
|
+
:locale => 'fr',
|
99
|
+
:phrase => @phrase1,
|
100
|
+
:user_id => @translator4_fr_id,
|
101
|
+
:value => "something brand new!",
|
102
|
+
:payment_details => '{"v3":{"t":9,"v":0}}',
|
103
|
+
:is_verification => true,
|
104
|
+
:created_at => 1.hours.ago)
|
105
|
+
@translation1_of_phrase2_fr_today = FactoryGirl.create(
|
106
|
+
:phrase_translation,
|
107
|
+
:locale => 'fr',
|
108
|
+
:phrase => @phrase2,
|
109
|
+
:user_id => @translator1_fr_id,
|
110
|
+
:created_at => 59.minutes.ago)
|
111
|
+
@translation1_of_phrase6_fr_way_old = FactoryGirl.create(
|
112
|
+
:phrase_translation,
|
113
|
+
:locale => 'fr',
|
114
|
+
:phrase => @phrase6,
|
115
|
+
:user_id => @translator3_fr_id,
|
116
|
+
:created_at => 2.months.ago)
|
117
|
+
@translation2_of_phrase3_fr_old = FactoryGirl.create(
|
118
|
+
:phrase_translation,
|
119
|
+
:locale => 'fr',
|
120
|
+
:phrase => @phrase3,
|
121
|
+
:user_id => @translator1_fr_id,
|
122
|
+
:created_at => 3.days.ago)
|
123
|
+
@translation2_of_phrase4_fr_old = FactoryGirl.create(
|
124
|
+
:phrase_translation,
|
125
|
+
:locale => 'fr',
|
126
|
+
:phrase => @phrase4,
|
127
|
+
:user_id => @translator1_fr_id,
|
128
|
+
:created_at => 3.days.ago)
|
129
|
+
|
130
|
+
# With Italian, we test the odd case where multiple translations have
|
131
|
+
# the "is_latest" flag set.
|
132
|
+
#
|
133
|
+
# (I'm not sure why this ever happens, but in prod database, it does.)
|
134
|
+
@translation1_of_phrase1_it_today = FactoryGirl.create(
|
135
|
+
:phrase_translation,
|
136
|
+
:locale => 'it',
|
137
|
+
:phrase => @phrase1,
|
138
|
+
:user_id => @translator1_it_id,
|
139
|
+
:created_at => 2.hours.ago)
|
140
|
+
@translation2_of_phrase1_it_today = FactoryGirl.create(
|
141
|
+
:phrase_translation,
|
142
|
+
:locale => 'it',
|
143
|
+
:phrase => @phrase1,
|
144
|
+
:user_id => @translator2_it_id,
|
145
|
+
:created_at => 1.hour.ago)
|
146
|
+
@translation1_of_phrase1_it_today.update_column(:is_latest, true)
|
147
|
+
@translation2_of_phrase1_it_today.update_column(:is_latest, true)
|
148
|
+
|
149
|
+
@translation1_of_phrase3_ko_old = FactoryGirl.create(
|
150
|
+
:phrase_translation,
|
151
|
+
:locale => 'ko',
|
152
|
+
:phrase => @phrase3,
|
153
|
+
:user_id => @translator1_ko_id,
|
154
|
+
:created_at => 3.days.ago)
|
155
|
+
|
156
|
+
@translation1_of_phrase5_fr_today = FactoryGirl.create(
|
157
|
+
:phrase_translation,
|
158
|
+
:locale => 'fr',
|
159
|
+
:phrase => @phrase5,
|
160
|
+
:is_stale => true,
|
161
|
+
:user_id => @translator1_fr_id,
|
162
|
+
:created_at => 58.minutes.ago)
|
163
|
+
|
164
|
+
# Phrase 7 is not translated at all.
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
before :each do
|
169
|
+
@still_used_phrases = [@phrase1.id, @phrase2.id, @phrase3.id, @phrase5.id, @phrase6.id, @phrase7.id]
|
170
|
+
I18n.stub(:still_used_phrase_ids => @still_used_phrases)
|
171
|
+
end
|
172
|
+
|
173
|
+
context "#translation_progress" do
|
174
|
+
it "should measure priority phrase progress" do
|
175
|
+
ppp = Air18n::Metrics.translation_progress(['home#index', 'home#other_action', 'info#press'])
|
176
|
+
ppp.size.should == 3
|
177
|
+
|
178
|
+
ppp[:fr].should include({
|
179
|
+
:phrases => 5,
|
180
|
+
:words => 21,
|
181
|
+
:phrases_translated => 3,
|
182
|
+
:words_translated => 15,
|
183
|
+
:phrases_verified => 1,
|
184
|
+
:words_verified => 9,
|
185
|
+
:phrases_translated_in_last_day => 1,
|
186
|
+
:words_translated_in_last_day => 9,
|
187
|
+
:phrases_translated_in_last_week => 2,
|
188
|
+
:words_translated_in_last_week => 12,
|
189
|
+
:phrases_translated_percent => 60,
|
190
|
+
:words_translated_percent => 71,
|
191
|
+
:phrases_verified_percent => 20,
|
192
|
+
:words_verified_percent => 43,
|
193
|
+
:phrases_progress => :bad,
|
194
|
+
:phrases_remaining_to_translate => 2,
|
195
|
+
:words_remaining_to_translate => 6,
|
196
|
+
:phrases_remaining_to_verify => 4,
|
197
|
+
:words_remaining_to_verify => 12,
|
198
|
+
|
199
|
+
# translator2_fr doesn't appear because he hasn't last touched any phrase.
|
200
|
+
:translators => Set.new([@translator1_fr_id, @translator4_fr_id]) })
|
201
|
+
|
202
|
+
ppp[:it].should include({
|
203
|
+
:phrases => 5,
|
204
|
+
:words => 21,
|
205
|
+
:phrases_translated => 1,
|
206
|
+
:words_translated => 9,
|
207
|
+
:phrases_translated_in_last_day => 1,
|
208
|
+
:phrases_translated_in_last_week => 1,
|
209
|
+
:phrases_translated_percent => 20,
|
210
|
+
:words_translated_percent => 43,
|
211
|
+
:phrases_progress => :bad,
|
212
|
+
:phrases_remaining_to_translate => 4,
|
213
|
+
:words_remaining_to_translate => 12 })
|
214
|
+
ppp[:ko].should include({
|
215
|
+
:phrases => 5,
|
216
|
+
:words => 21,
|
217
|
+
:phrases_translated => 1,
|
218
|
+
:words_translated => 3,
|
219
|
+
:phrases_translated_in_last_day => 0,
|
220
|
+
:phrases_translated_in_last_week => 1,
|
221
|
+
:phrases_translated_percent => 20,
|
222
|
+
:words_translated_percent => 14,
|
223
|
+
:phrases_progress => :bad,
|
224
|
+
:phrases_remaining_to_translate => 4,
|
225
|
+
:words_remaining_to_translate => 18,
|
226
|
+
:translators => Set.new([@translator1_ko_id]) })
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
context "#translator_progress" do
|
231
|
+
it "should measure priority phrase progress" do
|
232
|
+
p1 = Air18n::Metrics.translator_progress(:fr, @translator1_fr_id)
|
233
|
+
p1.should include({
|
234
|
+
:user_id => @translator1_fr_id,
|
235
|
+
:classification => :translator,
|
236
|
+
:words_translated_last_month => 21,
|
237
|
+
:words_translated_last_week => 21,
|
238
|
+
:words_verified_last_month => 0,
|
239
|
+
:words_verified_last_week => 0,
|
240
|
+
:daily_average => 0,
|
241
|
+
:phrases_translated_last_month => 5,
|
242
|
+
:number_of_later_modified_phrases_last_month => 1,
|
243
|
+
:later_modified_percent => 20,
|
244
|
+
})
|
245
|
+
|
246
|
+
p2 = Air18n::Metrics.translator_progress(:fr, @translator2_fr_id)
|
247
|
+
p2.should include({
|
248
|
+
:user_id => @translator2_fr_id,
|
249
|
+
:classification => :verifier,
|
250
|
+
:words_translated_last_month => 0,
|
251
|
+
:words_translated_last_week => 0,
|
252
|
+
:words_verified_last_month => 9,
|
253
|
+
:words_verified_last_week => 9,
|
254
|
+
:daily_average => 0,
|
255
|
+
:phrases_translated_last_month => 0,
|
256
|
+
:number_of_later_modified_phrases_last_month => 0,
|
257
|
+
:later_modified_percent => 0,
|
258
|
+
})
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
context "#metrics_suite" do
|
263
|
+
it "should work" do
|
264
|
+
s = Air18n::Metrics.metrics_suite
|
265
|
+
s[:fr][:words_translated].should == 18
|
266
|
+
s[:fr][:translator_progress].size.should == 2
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
context "#recent_work" do
|
271
|
+
it "should scope somebody's recent work" do
|
272
|
+
work = Air18n::Metrics.recent_work(:fr, @translator1_fr_id).limit(2).all
|
273
|
+
work.should == [@translation1_of_phrase5_fr_today, @translation1_of_phrase2_fr_today]
|
274
|
+
end
|
275
|
+
end
|
276
|
+
end
|
@@ -58,6 +58,19 @@ describe Air18n::PrimAndProper do
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
+
describe Air18n::AmericanToSinglish do
|
62
|
+
it "have a complete travel-related vocab list with Kia ora" do
|
63
|
+
@airpnp.guess(
|
64
|
+
"traveled realize flavor center learned practices airplane inquire specialties " +
|
65
|
+
"inquiry artifact program livable among spelled judgment defense fulfill spilled " +
|
66
|
+
"vacation apartment elevator couch coupon cell Hi bathroom neighborhood's",
|
67
|
+
:en, :"en-SG").should ==
|
68
|
+
"travelled realise flavour centre learnt practises aeroplane enquire specialities " +
|
69
|
+
"enquiry artefact programme liveable amongst spelt judgement defence fulfil spilt " +
|
70
|
+
"holiday apartment lift sofa voucher mobile Hi bathroom neighbourhood's"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
61
74
|
describe Air18n::AmericanToCanadian do
|
62
75
|
it "have a complete travel-related vocab list without ize/ise variants" do
|
63
76
|
@airpnp.guess(
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: air18n
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ authors:
|
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
|
-
date: 2013-
|
16
|
+
date: 2013-02-21 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: i18n
|
@@ -168,6 +168,7 @@ files:
|
|
168
168
|
- lib/air18n/default_text_change_observer.rb
|
169
169
|
- lib/air18n/less_silly_chain.rb
|
170
170
|
- lib/air18n/logging_helper.rb
|
171
|
+
- lib/air18n/metrics.rb
|
171
172
|
- lib/air18n/mock_priority.rb
|
172
173
|
- lib/air18n/phrase.rb
|
173
174
|
- lib/air18n/phrase_revision.rb
|
@@ -192,6 +193,7 @@ files:
|
|
192
193
|
- spec/lib/air18n/air18n_spec.rb
|
193
194
|
- spec/lib/air18n/backend_spec.rb
|
194
195
|
- spec/lib/air18n/chunk_cache_spec.rb
|
196
|
+
- spec/lib/air18n/metrics_spec.rb
|
195
197
|
- spec/lib/air18n/phrase_spec.rb
|
196
198
|
- spec/lib/air18n/phrase_translation_spec.rb
|
197
199
|
- spec/lib/air18n/prim_and_proper_spec.rb
|
@@ -219,7 +221,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
219
221
|
version: '0'
|
220
222
|
requirements: []
|
221
223
|
rubyforge_project:
|
222
|
-
rubygems_version: 1.8.
|
224
|
+
rubygems_version: 1.8.24
|
223
225
|
signing_key:
|
224
226
|
specification_version: 3
|
225
227
|
summary: Dynamic I18n backend
|
@@ -229,6 +231,7 @@ test_files:
|
|
229
231
|
- spec/lib/air18n/air18n_spec.rb
|
230
232
|
- spec/lib/air18n/backend_spec.rb
|
231
233
|
- spec/lib/air18n/chunk_cache_spec.rb
|
234
|
+
- spec/lib/air18n/metrics_spec.rb
|
232
235
|
- spec/lib/air18n/phrase_spec.rb
|
233
236
|
- spec/lib/air18n/phrase_translation_spec.rb
|
234
237
|
- spec/lib/air18n/prim_and_proper_spec.rb
|