air18n 0.1.40 → 0.1.41

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.
@@ -337,10 +337,10 @@ module Air18n
337
337
  end
338
338
 
339
339
  def self.translator_activity_data_v3 user_id=0, opts={}
340
- activity_from_translation_pairs(get_translation_pairs(user_id, opts[:since], opts[:to]), opts)
340
+ aggregate_v3_translation_activity(compute_v3_translation_activity(user_id, opts[:since], opts[:to]), opts)
341
341
  end
342
342
 
343
- def self.activity_from_translation_pairs(translation_pairs, opts={})
343
+ def self.aggregate_v3_translation_activity(translation_pairs, opts={})
344
344
  per_user_locale_month_year =
345
345
  Hash.new {|h, year| h[year] =
346
346
  Hash.new {|h, month| h[month] =
@@ -356,16 +356,15 @@ module Air18n
356
356
  } } } } } }
357
357
 
358
358
  translation_pairs.each do |pair|
359
- words_translated, words_verified = self.word_counts_from_translation_pair(pair)
360
359
  sums = per_user_locale_month_year[
361
360
  pair[:datetime].year][
362
361
  pair[:datetime].month][
363
362
  pair[:user_id]][
364
363
  pair[:locale]][
365
364
  pair[:datetime].day]
366
- sums[:words_translated] += words_translated
367
- sums[:words_verified] += words_verified
368
- if words_verified > 0
365
+ sums[:words_translated] += pair[:words_translated]
366
+ sums[:words_verified] += pair[:words_verified]
367
+ if pair[:words_verified] > 0
369
368
  sums[:keys_verified] << pair[:phrase_key]
370
369
  sums[:phrases_verified] += 1
371
370
  else
@@ -397,9 +396,6 @@ module Air18n
397
396
  :verified_keys => sums[:keys_verified],
398
397
  }
399
398
  }
400
- LoggingHelper.info("keys translated: #{sums[:keys_translated]}")
401
- LoggingHelper.info("keys verified: #{sums[:keys_verified]}")
402
- LoggingHelper.info("ret now: #{ret.inspect}")
403
399
  end
404
400
  else
405
401
  monthly_sums = {
@@ -429,9 +425,6 @@ module Air18n
429
425
  :verified_keys => monthly_sums[:keys_verified],
430
426
  }
431
427
  }
432
- LoggingHelper.info("keys translated: #{monthly_sums[:keys_translated]}")
433
- LoggingHelper.info("keys verified: #{monthly_sums[:keys_verified]}")
434
- LoggingHelper.info("ret now: #{ret.inspect}")
435
428
  end
436
429
  end
437
430
  end
@@ -485,7 +478,7 @@ module Air18n
485
478
  (translation_pair[:source_word_count] * proportion_verified).floor]
486
479
  end
487
480
 
488
- def self.get_translation_pairs(user_id, from_date, to_date)
481
+ def self.compute_v3_translation_activity(user_id, from_date, to_date)
489
482
  ret = []
490
483
  Phrase.select(:id).find_in_batches do |batch|
491
484
  pt_scope = PhraseTranslation.where(:phrase_id => batch)
@@ -502,32 +495,68 @@ module Air18n
502
495
  phrase_to_phrase_translations.each do |(locale, phrase_id), phrase_translations|
503
496
  phrase_translations.sort_by! { |pt| pt.created_at }
504
497
 
505
- previous_translation = PhraseTranslation.where("created_at < ?", phrase_translations.first.created_at - 1.second).
506
- where(:locale => locale).
507
- where(:phrase_id => phrase_id).
508
- order("created_at DESC").
509
- first
498
+ previous_translation = :uncomputed
499
+
510
500
  phrase_translations.each do |pt|
511
- if previous_translation
512
- previous_translation_text = previous_translation.value
513
- previous_translation_user_id = previous_translation.user_id
514
- was_stale = previous_translation.source_hash != pt.source_hash
501
+ translation_pair = {
502
+ :translation => pt.value,
503
+ :locale => pt.locale,
504
+ :user_id => pt.user_id,
505
+ :datetime => pt.created_at,
506
+ :source_word_count => pt.source_word_count,
507
+ :phrase_key => pt.key,
508
+ }
509
+
510
+ if pt.payment_details.present?
511
+ payment_details = JSON.parse(pt.payment_details)
515
512
  else
516
- previous_translation_text = ''
517
- previous_translation_user_id = 0
518
- was_stale = false
513
+ payment_details = {}
519
514
  end
520
- translation_text = pt.value
521
- ret << { :translation => translation_text,
522
- :previous_translation => previous_translation_text,
523
- :was_stale => was_stale,
524
- :locale => pt.locale,
525
- :user_id => pt.user_id,
526
- :previous_user_id => previous_translation_user_id,
527
- :datetime => pt.created_at,
528
- :source_word_count => pt.source_word_count,
529
- :phrase_key => pt.key,
530
- }
515
+
516
+ if !payment_details.include?('v3')
517
+ # If we haven't computed v3 payment details already, compute them
518
+ # and then save details to the PhraseTranslation itself.
519
+
520
+ if previous_translation == :uncomputed
521
+ previous_translation = PhraseTranslation.
522
+ where("created_at < ?", phrase_translations.first.created_at - 1.second).
523
+ where(:locale => locale).
524
+ where(:phrase_id => phrase_id).
525
+ order("created_at DESC").
526
+ first
527
+ end
528
+
529
+ if previous_translation
530
+ previous_translation_text = previous_translation.value
531
+ previous_translation_user_id = previous_translation.user_id
532
+ was_stale = previous_translation.source_hash != pt.source_hash
533
+ else
534
+ previous_translation_text = ''
535
+ previous_translation_user_id = 0
536
+ was_stale = false
537
+ end
538
+
539
+ words_translated, words_verified = self.word_counts_from_translation_pair(
540
+ translation_pair.merge(
541
+ :previous_translation => previous_translation_text,
542
+ :was_stale => was_stale,
543
+ :previous_user_id => previous_translation_user_id,
544
+ ))
545
+
546
+ payment_details['v3'] = {
547
+ 't' => words_translated,
548
+ 'v' => words_verified
549
+ }
550
+
551
+ pt.payment_details = payment_details.to_json
552
+ LoggingHelper.info "saving payment details: "
553
+ pt.save
554
+ end
555
+
556
+ translation_pair[:words_translated] = payment_details['v3']['t']
557
+ translation_pair[:words_verified] = payment_details['v3']['v']
558
+
559
+ ret << translation_pair
531
560
 
532
561
  previous_translation = pt
533
562
  end
@@ -1,3 +1,3 @@
1
1
  module Air18n
2
- VERSION = "0.1.40"
2
+ VERSION = "0.1.41"
3
3
  end
@@ -40,6 +40,7 @@ class Air18nMigration < ActiveRecord::Migration
40
40
  t.boolean "is_latest", :default => false
41
41
  t.integer "source_word_count", :default => 0
42
42
  t.string "source_hash"
43
+ t.text "payment_details"
43
44
  end
44
45
 
45
46
  add_index "phrase_translations", ["locale", "is_latest", "is_stale", "is_verification"], :name => "index_phrase_translations_on_locale_and_flags"
@@ -374,54 +374,133 @@ describe Air18n::PhraseTranslation do
374
374
  ##### Phrase 1
375
375
 
376
376
  # User 1 translates Phrase 1 for the first time [edit of untranslated phrase]
377
- translation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'urgle burgle', :phrase => @phrase1, :user_id => @user1, :created_at => Date.new(2012, 11, 1))
377
+ @translation_wih_precomputed_edits = FactoryGirl.create(
378
+ :phrase_translation,
379
+ :locale => :de,
380
+ :value => 'urgle burgle',
381
+ :phrase => @phrase1,
382
+ :user_id => @user1,
383
+ :created_at => Date.new(2012, 11, 1),
384
+ :payment_details => '{"v3":{"t":8,"v":0}}')
378
385
 
379
386
  # User 1 tweaks his own translation of Phrase 1. [edit of own unverified translation]
380
- translation_tweak = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'urgle burgle boo', :phrase => @phrase1, :user_id => @user1, :created_at => Date.new(2012, 11, 2))
387
+ FactoryGirl.create(
388
+ :phrase_translation,
389
+ :locale => :de,
390
+ :value => 'urgle burgle boo',
391
+ :phrase => @phrase1,
392
+ :user_id => @user1,
393
+ :created_at => Date.new(2012, 11, 2))
381
394
 
382
395
  # User 2 verifies translation of Phrase 1. [pure verification]
383
- verification_by_other_user = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'urgle burgle boo', :phrase => @phrase1, :user_id => @user2, :is_verification => true, :created_at => Date.new(2012, 11, 3))
396
+ FactoryGirl.create(
397
+ :phrase_translation,
398
+ :locale => :de,
399
+ :value => 'urgle burgle boo',
400
+ :phrase => @phrase1,
401
+ :user_id => @user2,
402
+ :is_verification => true,
403
+ :created_at => Date.new(2012, 11, 3))
384
404
 
385
405
  # Phrase 1 becomes stale.
386
406
  @phrase1.value = "one two three four five six seven eight nine ten eleven twelve thirteen"
387
407
  @phrase1.save!
388
408
 
389
409
  # User 1 reedits translation of Phrase 1. [edit of other's stale translation]
390
- retranslation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'oogie boogie boo', :phrase => @phrase1, :user_id => @user1, :created_at => Date.new(2012, 11, 4))
410
+ @phrase_without_payment_details = FactoryGirl.create(
411
+ :phrase_translation,
412
+ :locale => :de,
413
+ :value => 'oogie boogie boo',
414
+ :phrase => @phrase1,
415
+ :user_id => @user1,
416
+ :created_at => Date.new(2012, 11, 4))
391
417
 
392
418
  # User 2 pure-verifies of Phrase 1.
393
- other_user_translation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'oogie boogie boo', :is_verification => true, :phrase => @phrase1, :user_id => @user2, :created_at => Date.new(2012, 11, 5))
419
+ FactoryGirl.create(
420
+ :phrase_translation,
421
+ :locale => :de,
422
+ :value => 'oogie boogie boo',
423
+ :is_verification => true,
424
+ :phrase => @phrase1,
425
+ :user_id => @user2,
426
+ :created_at => Date.new(2012, 11, 5))
394
427
 
395
428
  # User 1 edits verified translation of Phrase 1. [edit of other's verified translation]
396
- verification = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'oogie booooogie boo hat ogl', :phrase => @phrase1, :user_id => @user1, :is_verification => true, :created_at => Date.new(2012, 11, 6))
429
+ FactoryGirl.create(:phrase_translation,
430
+ :locale => :de,
431
+ :value => 'oogie booooogie boo hat ogl',
432
+ :phrase => @phrase1,
433
+ :user_id => @user1,
434
+ :is_verification => true,
435
+ :created_at => Date.new(2012, 11, 6))
397
436
 
398
437
  ##### Phrase 2
399
438
 
400
439
  # User 1 translates Phrase 2 for the first time, but earlier in the year.
401
- translation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'The only verdict is vengence', :phrase => @phrase2, :user_id => @user1, :created_at => Date.new(2012, 9, 1))
440
+ FactoryGirl.create(
441
+ :phrase_translation,
442
+ :locale => :de,
443
+ :value => 'The only verdict is vengence',
444
+ :phrase => @phrase2,
445
+ :user_id => @user1,
446
+ :created_at => Date.new(2012, 9, 1))
402
447
 
403
448
  # User 1 tweaks their own translation later.
404
- translation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'The only verdict is VENGENCE', :phrase => @phrase2, :user_id => @user1, :created_at => Date.new(2012, 11, 1))
449
+ FactoryGirl.create(
450
+ :phrase_translation,
451
+ :locale => :de,
452
+ :value => 'The only verdict is VENGENCE',
453
+ :phrase => @phrase2,
454
+ :user_id => @user1,
455
+ :created_at => Date.new(2012, 11, 1))
405
456
 
406
457
  # User 2 tweaks translation of Phrase 2.
407
- translation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'a vendetta, held as a votive', :is_verification => true, :phrase => @phrase2, :user_id => @user2, :created_at => Date.new(2012, 11, 2))
458
+ FactoryGirl.create(
459
+ :phrase_translation,
460
+ :locale => :de,
461
+ :value => 'a vendetta, held as a votive',
462
+ :is_verification => true,
463
+ :phrase => @phrase2,
464
+ :user_id => @user2,
465
+ :created_at => Date.new(2012, 11, 2))
408
466
 
409
467
  # User 2 tweaks their own translation of Phrase 2. [edit of own verified translation]
410
- translation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'a vendetta, held as a votive, not in vain', :is_verification => true, :phrase => @phrase2, :user_id => @user2, :created_at => Date.new(2012, 11, 3))
468
+ FactoryGirl.create(
469
+ :phrase_translation,
470
+ :locale => :de,
471
+ :value => 'a vendetta, held as a votive, not in vain',
472
+ :is_verification => true,
473
+ :phrase => @phrase2,
474
+ :user_id => @user2,
475
+ :created_at => Date.new(2012, 11, 3))
411
476
 
412
477
  # Phrase 2 becomes stale.
413
478
  @phrase2.value = "one two three four five six seven eight nine"
414
479
  @phrase2.save!
415
480
 
416
481
  # User 2 verifies existing translation of Phrase 2. [pure verification of own stale translation]
417
- translation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'a vendetta, held as a votive, not in vain', :is_verification => true, :phrase => @phrase2, :user_id => @user2, :created_at => Date.new(2012, 11, 4))
482
+ FactoryGirl.create(
483
+ :phrase_translation,
484
+ :locale => :de,
485
+ :value => 'a vendetta, held as a votive, not in vain',
486
+ :is_verification => true,
487
+ :phrase => @phrase2,
488
+ :user_id => @user2,
489
+ :created_at => Date.new(2012, 11, 4))
418
490
 
419
491
  # Phrase 2 becomes stale again.
420
492
  @phrase2.value = "one two three"
421
493
  @phrase2.save!
422
494
 
423
495
  # User 2 tweaks translation of Phrase 2. [pure verification of own stale translation]
424
- translation = FactoryGirl.create(:phrase_translation, :locale => :de, :value => 'a vendetta, held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous', :is_verification => true, :phrase => @phrase2, :user_id => @user2, :created_at => Date.new(2012, 11, 5))
496
+ FactoryGirl.create(
497
+ :phrase_translation,
498
+ :locale => :de,
499
+ :value => 'a vendetta, held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous',
500
+ :is_verification => true,
501
+ :phrase => @phrase2,
502
+ :user_id => @user2,
503
+ :created_at => Date.new(2012, 11, 5))
425
504
  end
426
505
 
427
506
  @golden_pairs =
@@ -433,6 +512,8 @@ describe Air18n::PhraseTranslation do
433
512
  :previous_user_id=>0,
434
513
  :datetime=>Date.new(2012, 11, 01),
435
514
  :source_word_count=>8,
515
+ :words_translated=>8, # "" -> "urgle burgle", user 5
516
+ :words_verified=>0,
436
517
  :phrase_key=>'v3 regime payments key 1'},
437
518
  {:translation=>"urgle burgle boo",
438
519
  :previous_translation=>"urgle burgle",
@@ -442,6 +523,8 @@ describe Air18n::PhraseTranslation do
442
523
  :previous_user_id=>5,
443
524
  :datetime=>Date.new(2012, 11, 02),
444
525
  :source_word_count=>8,
526
+ :words_translated=>0, # same translator making an edit, user 5
527
+ :words_verified=>0,
445
528
  :phrase_key=>'v3 regime payments key 1'},
446
529
  {:translation=>"urgle burgle boo",
447
530
  :previous_translation=>"urgle burgle boo",
@@ -451,6 +534,8 @@ describe Air18n::PhraseTranslation do
451
534
  :previous_user_id=>5,
452
535
  :datetime=>Date.new(2012, 11, 03),
453
536
  :source_word_count=>8,
537
+ :words_translated=>0, # different translator verifying, user 6
538
+ :words_verified=>8,
454
539
  :phrase_key=>'v3 regime payments key 1'},
455
540
  {:translation=>"oogie boogie boo",
456
541
  :previous_translation=>"urgle burgle boo",
@@ -460,6 +545,8 @@ describe Air18n::PhraseTranslation do
460
545
  :previous_user_id=>6,
461
546
  :datetime=>Date.new(2012, 11, 04),
462
547
  :source_word_count=>13,
548
+ :words_translated=>9, # edit of stale phrase; 2/3 words changed, 2/3*13=8.66; ceils to 9, user 5
549
+ :words_verified=>4,
463
550
  :phrase_key=>'v3 regime payments key 1'},
464
551
  {:translation=>"oogie boogie boo",
465
552
  :previous_translation=>"oogie boogie boo",
@@ -469,6 +556,8 @@ describe Air18n::PhraseTranslation do
469
556
  :previous_user_id=>5,
470
557
  :datetime=>Date.new(2012, 11, 05),
471
558
  :source_word_count=>13,
559
+ :words_translated=>0, # verification, user 6
560
+ :words_verified=>13,
472
561
  :phrase_key=>'v3 regime payments key 1'},
473
562
  {:translation=>"oogie booooogie boo hat ogl",
474
563
  :previous_translation=>"oogie boogie boo",
@@ -478,6 +567,8 @@ describe Air18n::PhraseTranslation do
478
567
  :previous_user_id=>6,
479
568
  :datetime=>Date.new(2012, 11, 06),
480
569
  :source_word_count=>13,
570
+ :words_translated=>13, # 3 new words; 3/3 words changed, 3/3*13=13, user 5
571
+ :words_verified=>0,
481
572
  :phrase_key=>'v3 regime payments key 1'},
482
573
  {:translation=>"The only verdict is VENGENCE",
483
574
  :previous_translation=>"The only verdict is vengence",
@@ -487,6 +578,8 @@ describe Air18n::PhraseTranslation do
487
578
  :previous_user_id=>5,
488
579
  :datetime=>Date.new(2012, 11, 01),
489
580
  :source_word_count=>6,
581
+ :words_translated=>0, # Tweak of a translation that was done in past by same person, user 5
582
+ :words_verified=>0,
490
583
  :phrase_key=>'v3 regime payments key 2'},
491
584
  {:translation=>"a vendetta, held as a votive",
492
585
  :previous_translation=>"The only verdict is VENGENCE",
@@ -496,6 +589,8 @@ describe Air18n::PhraseTranslation do
496
589
  :previous_user_id=>5,
497
590
  :datetime=>Date.new(2012, 11, 02),
498
591
  :source_word_count=>6,
592
+ :words_translated=>6, # Rewrite of translation by other person, user 6
593
+ :words_verified=>0,
499
594
  :phrase_key=>'v3 regime payments key 2'},
500
595
  {:translation=>"a vendetta, held as a votive, not in vain",
501
596
  :previous_translation=>"a vendetta, held as a votive",
@@ -505,6 +600,8 @@ describe Air18n::PhraseTranslation do
505
600
  :previous_user_id=>6,
506
601
  :datetime=>Date.new(2012, 11, 03),
507
602
  :source_word_count=>6,
603
+ :words_translated=>0, # Tweak by same person, user 6
604
+ :words_verified=>0,
508
605
  :phrase_key=>'v3 regime payments key 2'},
509
606
  {:translation=>"a vendetta, held as a votive, not in vain",
510
607
  :previous_translation=>"a vendetta, held as a votive, not in vain",
@@ -514,6 +611,8 @@ describe Air18n::PhraseTranslation do
514
611
  :previous_user_id=>6,
515
612
  :datetime=>Date.new(2012, 11, 04),
516
613
  :source_word_count=>9,
614
+ :words_translated=>0, # Pure verification of stale, user 6
615
+ :words_verified=>9,
517
616
  :phrase_key=>'v3 regime payments key 2'},
518
617
  {:translation=>
519
618
  "a vendetta, held as a votive, not in vain, for the value and veracity of such shall one day vindicate the vigilant and the virtuous",
@@ -524,6 +623,8 @@ describe Air18n::PhraseTranslation do
524
623
  :previous_user_id=>6,
525
624
  :datetime=>Date.new(2012, 11, 05),
526
625
  :source_word_count=>3,
626
+ :words_translated=>3, # Edit of stale, user 6
627
+ :words_verified=>0,
527
628
  :phrase_key=>'v3 regime payments key 2'}]
528
629
 
529
630
  @golden_word_counts =
@@ -572,10 +673,16 @@ describe Air18n::PhraseTranslation do
572
673
  end
573
674
 
574
675
  it 'should be able to enumerate pairs of translations' do
575
- pairs = Air18n::PhraseTranslation.get_translation_pairs(0, Date.new(2012, 11, 1), Date.new(2012, 12, 1))
676
+ pairs = Air18n::PhraseTranslation.compute_v3_translation_activity(0, Date.new(2012, 11, 1), Date.new(2012, 12, 1))
576
677
  pairs = pairs.select { |pair| pair[:locale] == 'de' }
577
678
 
578
- pairs.should == @golden_pairs
679
+ (0...@golden_pairs.size).each do |i|
680
+ # Check that @golden_pairs[i] includes all keys/values in pairs[i].
681
+ pairs[i].should == @golden_pairs[i].slice(*pairs[i].keys)
682
+ end
683
+
684
+ # Check that it stores computed payment details in the database.
685
+ @phrase_without_payment_details.reload.payment_details.should == '{"v3":{"t":9,"v":4}}'
579
686
  end
580
687
 
581
688
  it 'should be able to count words proportional to amount of translation edited' do
@@ -682,13 +789,13 @@ describe Air18n::PhraseTranslation do
682
789
  end
683
790
 
684
791
  it 'should compute correct monthly activities' do
685
- data = Air18n::PhraseTranslation.activity_from_translation_pairs(@golden_pairs, :daily => false)
792
+ data = Air18n::PhraseTranslation.aggregate_v3_translation_activity(@golden_pairs, :daily => false)
686
793
 
687
794
  data.should == @golden_monthly_activity
688
795
  end
689
796
 
690
797
  it 'should compute correct daily activities' do
691
- data = Air18n::PhraseTranslation.activity_from_translation_pairs(@golden_pairs, :daily => true)
798
+ data = Air18n::PhraseTranslation.aggregate_v3_translation_activity(@golden_pairs, :daily => true)
692
799
 
693
800
  data.first.should ==
694
801
  {:year=>2012,
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.1.40
4
+ version: 0.1.41
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: 2012-11-27 00:00:00.000000000 Z
16
+ date: 2012-11-28 00:00:00.000000000 Z
17
17
  dependencies:
18
18
  - !ruby/object:Gem::Dependency
19
19
  name: i18n