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
|
-
|
340
|
+
aggregate_v3_translation_activity(compute_v3_translation_activity(user_id, opts[:since], opts[:to]), opts)
|
341
341
|
end
|
342
342
|
|
343
|
-
def self.
|
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.
|
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 =
|
506
|
-
|
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
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
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
|
-
|
517
|
-
previous_translation_user_id = 0
|
518
|
-
was_stale = false
|
513
|
+
payment_details = {}
|
519
514
|
end
|
520
|
-
|
521
|
-
|
522
|
-
|
523
|
-
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
|
529
|
-
|
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
|
data/lib/air18n/version.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|
-
|
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.
|
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.
|
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.
|
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-
|
16
|
+
date: 2012-11-28 00:00:00.000000000 Z
|
17
17
|
dependencies:
|
18
18
|
- !ruby/object:Gem::Dependency
|
19
19
|
name: i18n
|