air18n 0.4.5 → 0.4.6
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/air18n/metrics.rb +78 -10
- data/lib/air18n/phrase.rb +4 -0
- data/lib/air18n/version.rb +1 -1
- data/spec/lib/air18n/metrics_spec.rb +28 -10
- metadata +2 -2
data/lib/air18n/metrics.rb
CHANGED
@@ -2,10 +2,59 @@ module Air18n
|
|
2
2
|
module Metrics
|
3
3
|
TARGET_PRIORITY_PHRASE_TRANSLATION_PERCENT = 98
|
4
4
|
|
5
|
+
def self.time_to_first_translation
|
6
|
+
# First we get all phrases created in the last 28 days and one of their
|
7
|
+
# translations (leaving out verifications).
|
8
|
+
#
|
9
|
+
# Then we look at the difference between the phrase's created_at and the
|
10
|
+
# phrase translation's created_at and return the average per language
|
11
|
+
|
12
|
+
search_scope = Air18n::Phrase.still_used
|
13
|
+
search_scope = search_scope.select(
|
14
|
+
'`phrases`.`id`, `phrases`.`key`, `phrases`.`created_at`, ' +
|
15
|
+
'`phrase_translations`.`locale` AS latest_translation_locale, ' +
|
16
|
+
'`phrase_translations`.`user_id` AS latest_translation_user_id, ' +
|
17
|
+
'`phrase_translations`.`created_at` AS latest_translation_created_at'
|
18
|
+
)
|
19
|
+
search_scope = search_scope.where('`phrases`.`created_at` >= ?', 28.days.ago)
|
20
|
+
search_scope = search_scope.pull_in_all_historic_phrase_translations
|
21
|
+
search_scope = search_scope.where('`phrase_translations`.`is_verification` = ?', false)
|
22
|
+
search_scope = search_scope.group('`phrases`.`id`, `phrase_translations`.`phrase_id`, `latest_translation_locale`')
|
23
|
+
|
24
|
+
phrases_and_translations = search_scope.all
|
25
|
+
|
26
|
+
progress = {}
|
27
|
+
|
28
|
+
locale_to_translations = phrases_and_translations.group_by do |phrase_and_translation|
|
29
|
+
phrase_and_translation.latest_translation_locale
|
30
|
+
end
|
31
|
+
locale_to_translations.each do |locale, phrases_and_translations_for_locale|
|
32
|
+
if locale.present?
|
33
|
+
locale = locale.to_sym
|
34
|
+
progress[locale] ||= {}
|
35
|
+
elapsed_times = []
|
36
|
+
phrases_and_translations_for_locale.each do |phrase_and_translation|
|
37
|
+
phrase_created_at = phrase_and_translation.created_at
|
38
|
+
translated_at = phrase_and_translation.latest_translation_created_at
|
39
|
+
if translated_at.is_a?(String)
|
40
|
+
translated_at = Time.parse(translated_at)
|
41
|
+
end
|
42
|
+
seconds_passed = (translated_at - phrase_created_at).to_i
|
43
|
+
|
44
|
+
elapsed_times << seconds_passed
|
45
|
+
end
|
46
|
+
|
47
|
+
progress[locale][:average_seconds_to_first_translation] = (elapsed_times.inject(:+).to_f / elapsed_times.size).round
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
progress
|
52
|
+
end
|
53
|
+
|
5
54
|
def self.translation_progress(page_ids)
|
6
55
|
search_scope = Air18n::Phrase.still_used
|
7
56
|
search_scope = search_scope.select(
|
8
|
-
'`phrases`.`id`, `phrases`.`key`, ' +
|
57
|
+
'`phrases`.`id`, `phrases`.`key`, `phrases`.`created_at`, ' +
|
9
58
|
'`phrase_translations`.`locale` AS latest_translation_locale, ' +
|
10
59
|
'`phrase_translations`.`user_id` AS latest_translation_user_id, ' +
|
11
60
|
'`phrase_translations`.`created_at` AS latest_translation_created_at, ' +
|
@@ -39,13 +88,19 @@ module Air18n
|
|
39
88
|
priority_keys = phrases_and_translations.map { |phrase_and_translation| phrase_and_translation.key }.uniq
|
40
89
|
number_of_priority_phrases = priority_keys.size
|
41
90
|
number_of_priority_words = priority_keys.map { |k| word_counts[k] }.sum
|
42
|
-
locale_to_translations = phrases_and_translations.group_by
|
91
|
+
locale_to_translations = phrases_and_translations.group_by do |phrase_and_translation|
|
92
|
+
phrase_and_translation.latest_translation_locale
|
93
|
+
end
|
43
94
|
locale_to_translations.each do |locale, phrases_and_translations_for_locale|
|
44
95
|
if locale.present?
|
45
96
|
locale = locale.to_sym
|
46
97
|
progress[locale] ||= {}
|
47
|
-
phrases_with_translations_for_locale = phrases_and_translations_for_locale.find_all
|
48
|
-
|
98
|
+
phrases_with_translations_for_locale = phrases_and_translations_for_locale.find_all do |phrase_and_translation|
|
99
|
+
phrase_and_translation.latest_translation_user_id
|
100
|
+
end
|
101
|
+
phrases_with_verifications_for_locale = phrases_with_translations_for_locale.find_all do |phrase_and_translation|
|
102
|
+
true_value?(phrase_and_translation.latest_translation_is_verification)
|
103
|
+
end
|
49
104
|
|
50
105
|
words_with_translations_for_locale = phrases_with_translations_for_locale.map { |p| word_counts[p.key] }.sum
|
51
106
|
words_with_verifications_for_locale = phrases_with_verifications_for_locale.map { |p| word_counts[p.key] }.sum
|
@@ -83,12 +138,19 @@ module Air18n
|
|
83
138
|
progress[locale][:phrases_remaining_to_verify] = progress[locale][:phrases] - progress[locale][:phrases_verified]
|
84
139
|
progress[locale][:words_remaining_to_verify] = progress[locale][:words] - progress[locale][:words_verified]
|
85
140
|
|
86
|
-
progress[locale][:translators] =
|
87
|
-
|
88
|
-
|
141
|
+
progress[locale][:translators] =
|
142
|
+
phrases_with_translations_for_locale.inject(Set.new) do |carry, value|
|
143
|
+
if since?(value.latest_translation_created_at, 28.days.ago)
|
144
|
+
carry.add(value.latest_translation_user_id)
|
145
|
+
end
|
146
|
+
carry
|
147
|
+
end
|
148
|
+
progress[locale][:number_of_nonautomatic_translators] =
|
149
|
+
if progress[locale][:translators].include?(0)
|
150
|
+
progress[locale][:translators].size - 1
|
151
|
+
else
|
152
|
+
progress[locale][:translators].size
|
89
153
|
end
|
90
|
-
carry
|
91
|
-
end
|
92
154
|
end
|
93
155
|
end
|
94
156
|
|
@@ -156,7 +218,6 @@ module Air18n
|
|
156
218
|
:words_translated_last_week => words_translated_last_week,
|
157
219
|
:words_verified_last_month => words_verified_last_month,
|
158
220
|
:words_verified_last_week => words_verified_last_week,
|
159
|
-
:words_verified_last_week => words_verified_last_week,
|
160
221
|
:daily_average => daily_average,
|
161
222
|
:number_of_later_modified_phrases_last_month => number_of_later_modified_phrases_last_month,
|
162
223
|
:later_modified_percent => later_modified_percent
|
@@ -173,6 +234,13 @@ module Air18n
|
|
173
234
|
info[:translator_progress][user_id] = translator_progress(locale, user_id)
|
174
235
|
end
|
175
236
|
end
|
237
|
+
|
238
|
+
t = time_to_first_translation()
|
239
|
+
t.each do |locale, info|
|
240
|
+
p[locale].merge!(info)
|
241
|
+
end
|
242
|
+
|
243
|
+
p
|
176
244
|
end
|
177
245
|
|
178
246
|
# Returns scope for searching for most recent PhraseTranslations of a
|
data/lib/air18n/phrase.rb
CHANGED
@@ -125,6 +125,10 @@ module Air18n
|
|
125
125
|
"LEFT OUTER JOIN phrase_translations ON phrase_translations.phrase_id = phrases.id AND phrase_translations.is_latest = #{connection.quoted_true} AND phrase_translations.is_stale = #{connection.quoted_false}"
|
126
126
|
) }
|
127
127
|
|
128
|
+
scope :pull_in_all_historic_phrase_translations, lambda { joins(
|
129
|
+
"LEFT OUTER JOIN phrase_translations ON phrase_translations.phrase_id = phrases.id"
|
130
|
+
) }
|
131
|
+
|
128
132
|
# The still_used scope is wrapped in a lambda expression to
|
129
133
|
# I18n.still_used_phrase_ids is reevaluated each time.
|
130
134
|
# This makes dynamic updating possible and testing easier.
|
data/lib/air18n/version.rb
CHANGED
@@ -17,13 +17,17 @@ describe Air18n::Metrics do
|
|
17
17
|
|
18
18
|
@translator1_ko_id = 15
|
19
19
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
20
|
+
without_timestamping_of Air18n::Phrase do
|
21
|
+
@phrase1 = FactoryGirl.create(:phrase,
|
22
|
+
:value => 'one two three four five six seven eight nine',
|
23
|
+
:created_at => 3.days.ago)
|
24
|
+
@phrase2 = FactoryGirl.create(:phrase, :created_at => 1.year.ago)
|
25
|
+
@phrase3 = FactoryGirl.create(:phrase, :created_at => 1.year.ago)
|
26
|
+
@phrase4 = FactoryGirl.create(:phrase, :created_at => 1.year.ago)
|
27
|
+
@phrase5 = FactoryGirl.create(:phrase, :created_at => 1.year.ago)
|
28
|
+
@phrase6 = FactoryGirl.create(:phrase, :created_at => 1.year.ago)
|
29
|
+
@phrase7 = FactoryGirl.create(:phrase, :created_at => 1.year.ago)
|
30
|
+
end
|
27
31
|
|
28
32
|
# info#press is a manually-prioritized page.
|
29
33
|
@phrase3_screenshot1 = FactoryGirl.create(
|
@@ -197,7 +201,9 @@ describe Air18n::Metrics do
|
|
197
201
|
:words_remaining_to_verify => 12,
|
198
202
|
|
199
203
|
# translator2_fr doesn't appear because he hasn't last touched any phrase.
|
200
|
-
:translators => Set.new([@translator1_fr_id, @translator4_fr_id])
|
204
|
+
:translators => Set.new([@translator1_fr_id, @translator4_fr_id]),
|
205
|
+
:number_of_nonautomatic_translators => 2,
|
206
|
+
})
|
201
207
|
|
202
208
|
ppp[:it].should include({
|
203
209
|
:phrases => 5,
|
@@ -210,7 +216,8 @@ describe Air18n::Metrics do
|
|
210
216
|
:words_translated_percent => 43,
|
211
217
|
:phrases_progress => :bad,
|
212
218
|
:phrases_remaining_to_translate => 4,
|
213
|
-
:words_remaining_to_translate => 12
|
219
|
+
:words_remaining_to_translate => 12,
|
220
|
+
})
|
214
221
|
ppp[:ko].should include({
|
215
222
|
:phrases => 5,
|
216
223
|
:words => 21,
|
@@ -223,7 +230,8 @@ describe Air18n::Metrics do
|
|
223
230
|
:phrases_progress => :bad,
|
224
231
|
:phrases_remaining_to_translate => 4,
|
225
232
|
:words_remaining_to_translate => 18,
|
226
|
-
:translators => Set.new([@translator1_ko_id])
|
233
|
+
:translators => Set.new([@translator1_ko_id]),
|
234
|
+
})
|
227
235
|
end
|
228
236
|
end
|
229
237
|
|
@@ -259,11 +267,21 @@ describe Air18n::Metrics do
|
|
259
267
|
end
|
260
268
|
end
|
261
269
|
|
270
|
+
context "#time_to_first_translation" do
|
271
|
+
it "should measure time to first translation" do
|
272
|
+
s = Air18n::Metrics.time_to_first_translation
|
273
|
+
s.size.should == 2
|
274
|
+
s[:it][:average_seconds_to_first_translation].should == 280800
|
275
|
+
s[:fr][:average_seconds_to_first_translation].should == 277200
|
276
|
+
end
|
277
|
+
end
|
278
|
+
|
262
279
|
context "#metrics_suite" do
|
263
280
|
it "should work" do
|
264
281
|
s = Air18n::Metrics.metrics_suite
|
265
282
|
s[:fr][:words_translated].should == 18
|
266
283
|
s[:fr][:translator_progress].size.should == 2
|
284
|
+
s[:fr][:average_seconds_to_first_translation].should > 0
|
267
285
|
end
|
268
286
|
end
|
269
287
|
|
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.
|
4
|
+
version: 0.4.6
|
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-03-
|
16
|
+
date: 2013-03-28 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: i18n
|