air18n 0.4.5 → 0.4.6
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.
- 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
|