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.
@@ -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 { |phrase_and_translation| phrase_and_translation.latest_translation_locale }
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 { |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) }
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] = 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)
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
@@ -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.
@@ -1,3 +1,3 @@
1
1
  module Air18n
2
- VERSION = "0.4.5"
2
+ VERSION = "0.4.6"
3
3
  end
@@ -17,13 +17,17 @@ describe Air18n::Metrics do
17
17
 
18
18
  @translator1_ko_id = 15
19
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)
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.5
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-27 00:00:00.000000000 Z
16
+ date: 2013-03-28 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: i18n