Bug 1024757 - Translation FHR should report missed opportunities due to the detected language not being part of the list of supported languages. r=mdeboer a=lmandel
authorFelipe Gomes <felipc@gmail.com>
Thu, 19 Jun 2014 13:42:29 -0300
changeset 208262 606653d5d01d7a0c10b98f8dc4822091c08db247
parent 208261 82fcdadb5b04a653019242d262e7d0a4604150ef
child 208263 506057526ce6afe30d98a307df3bc0680bcd6b96
push id494
push userraliiev@mozilla.com
push dateMon, 25 Aug 2014 18:42:16 +0000
treeherdermozilla-release@a3cc3e46b571 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmdeboer, lmandel
bugs1024757
milestone32.0a2
Bug 1024757 - Translation FHR should report missed opportunities due to the detected language not being part of the list of supported languages. r=mdeboer a=lmandel
browser/components/translation/Translation.jsm
browser/components/translation/test/unit/test_healthreport.js
services/healthreport/docs/dataformat.rst
--- a/browser/components/translation/Translation.jsm
+++ b/browser/components/translation/Translation.jsm
@@ -43,19 +43,26 @@ this.Translation = {
                                       .getSelectedLocale("global")
                                       .split("-")[0];
     }
     return this._defaultTargetLanguage;
   },
 
   documentStateReceived: function(aBrowser, aData) {
     if (aData.state == this.STATE_OFFER) {
-      if (this.supportedSourceLanguages.indexOf(aData.detectedLanguage) == -1 ||
-          aData.detectedLanguage == this.defaultTargetLanguage)
+      if (aData.detectedLanguage == this.defaultTargetLanguage) {
+        // Detected language is the same as the user's locale.
         return;
+      }
+
+      if (this.supportedSourceLanguages.indexOf(aData.detectedLanguage) == -1) {
+        // Detected language is not part of the supported languages.
+        TranslationHealthReport.recordMissedTranslationOpportunity(aData.detectedLanguage);
+        return;
+      }
 
       TranslationHealthReport.recordTranslationOpportunity(aData.detectedLanguage);
     }
 
     if (!Services.prefs.getBoolPref(TRANSLATION_PREF_SHOWUI))
       return;
 
     if (!aBrowser.translationUI)
@@ -237,16 +244,27 @@ let TranslationHealthReport = {
    * Record a translation opportunity in the health report.
    * @param language
    *        The language of the page.
    */
   recordTranslationOpportunity: function (language) {
     this._withProvider(provider => provider.recordTranslationOpportunity(language));
    },
 
+  /**
+   * Record a missed translation opportunity in the health report.
+   * A missed opportunity is when the language detected is not part
+   * of the supported languages.
+   * @param language
+   *        The language of the page.
+   */
+  recordMissedTranslationOpportunity: function (language) {
+    this._withProvider(provider => provider.recordMissedTranslationOpportunity(language));
+  },
+
    /**
    * Record a translation in the health report.
    * @param langFrom
    *        The language of the page.
    * @param langTo
    *        The language translated to
    * @param numCharacters
    *        The number of characters that were translated
@@ -316,19 +334,21 @@ function TranslationMeasurement1() {
 TranslationMeasurement1.prototype = Object.freeze({
   __proto__: Metrics.Measurement.prototype,
 
   name: "translation",
   version: 1,
 
   fields: {
     translationOpportunityCount: DAILY_COUNTER_FIELD,
+    missedTranslationOpportunityCount: DAILY_COUNTER_FIELD,
     pageTranslatedCount: DAILY_COUNTER_FIELD,
     charactersTranslatedCount: DAILY_COUNTER_FIELD,
     translationOpportunityCountsByLanguage: DAILY_LAST_TEXT_FIELD,
+    missedTranslationOpportunityCountsByLanguage: DAILY_LAST_TEXT_FIELD,
     pageTranslatedCountsByLanguage: DAILY_LAST_TEXT_FIELD,
     detectedLanguageChangedBefore: DAILY_COUNTER_FIELD,
     detectedLanguageChangedAfter: DAILY_COUNTER_FIELD,
     detectLanguageEnabled: DAILY_LAST_NUMERIC_FIELD,
     showTranslationUI: DAILY_LAST_NUMERIC_FIELD,
   },
 
   shouldIncludeField: function (field) {
@@ -363,16 +383,17 @@ TranslationMeasurement1.prototype = Obje
     };
 
     return function (data) {
       let result = serializer(data);
 
       // Special case the serialization of these fields so that
       // they are sent as objects, not stringified objects.
       _parseInPlace(result, "translationOpportunityCountsByLanguage");
+      _parseInPlace(result, "missedTranslationOpportunityCountsByLanguage");
       _parseInPlace(result, "pageTranslatedCountsByLanguage");
 
       return result;
     }
   }
 });
 
 this.TranslationProvider = function () {
@@ -402,16 +423,35 @@ TranslationProvider.prototype = Object.f
       langCounts = JSON.stringify(langCounts);
 
       yield m.setDailyLastText("translationOpportunityCountsByLanguage",
                                langCounts, date);
 
     }.bind(this));
   },
 
+  recordMissedTranslationOpportunity: function (language, date=new Date()) {
+    let m = this.getMeasurement(TranslationMeasurement1.prototype.name,
+                                TranslationMeasurement1.prototype.version);
+
+    return this._enqueueTelemetryStorageTask(function* recordTask() {
+      yield m.incrementDailyCounter("missedTranslationOpportunityCount", date);
+
+      let langCounts = yield m._getDailyLastTextFieldAsJSON(
+        "missedTranslationOpportunityCountsByLanguage", date);
+
+      langCounts[language] = (langCounts[language] || 0) + 1;
+      langCounts = JSON.stringify(langCounts);
+
+      yield m.setDailyLastText("missedTranslationOpportunityCountsByLanguage",
+                               langCounts, date);
+
+    }.bind(this));
+  },
+
   recordTranslation: function (langFrom, langTo, numCharacters, date=new Date()) {
     let m = this.getMeasurement(TranslationMeasurement1.prototype.name,
                                 TranslationMeasurement1.prototype.version);
 
     return this._enqueueTelemetryStorageTask(function* recordTask() {
       yield m.incrementDailyCounter("pageTranslatedCount", date);
       yield m.incrementDailyCounter("charactersTranslatedCount", date,
                                     numCharacters);
--- a/browser/components/translation/test/unit/test_healthreport.js
+++ b/browser/components/translation/test/unit/test_healthreport.js
@@ -64,31 +64,57 @@ add_task(function* test_translation_oppo
   let day = values.days.getDay(now);
   Assert.ok(day.has("translationOpportunityCount"));
   Assert.equal(day.get("translationOpportunityCount"), 1);
 
   Assert.ok(day.has("translationOpportunityCountsByLanguage"));
   let countsByLanguage = JSON.parse(day.get("translationOpportunityCountsByLanguage"));
   Assert.equal(countsByLanguage["fr"], 1);
 
+  // Record a missed opportunity.
+  yield provider.recordMissedTranslationOpportunity("it", now);
+
+  values = yield m.getValues();
+  day = values.days.getDay(now);
+  Assert.equal(values.days.size, 1);
+  Assert.ok(values.days.hasDay(now));
+  Assert.ok(day.has("missedTranslationOpportunityCount"));
+  Assert.equal(day.get("missedTranslationOpportunityCount"), 1);
+
+  Assert.ok(day.has("missedTranslationOpportunityCountsByLanguage"));
+  let missedCountsByLanguage = JSON.parse(day.get("missedTranslationOpportunityCountsByLanguage"));
+  Assert.equal(missedCountsByLanguage["it"], 1);
+
   // Record more opportunities.
   yield provider.recordTranslationOpportunity("fr", now);
   yield provider.recordTranslationOpportunity("fr", now);
   yield provider.recordTranslationOpportunity("es", now);
 
+  yield provider.recordMissedTranslationOpportunity("it", now);
+  yield provider.recordMissedTranslationOpportunity("cs", now);
+  yield provider.recordMissedTranslationOpportunity("fi", now);
+
   values = yield m.getValues();
-  let day = values.days.getDay(now);
+  day = values.days.getDay(now);
   Assert.ok(day.has("translationOpportunityCount"));
   Assert.equal(day.get("translationOpportunityCount"), 4);
+  Assert.ok(day.has("missedTranslationOpportunityCount"));
+  Assert.equal(day.get("missedTranslationOpportunityCount"), 4);
 
   Assert.ok(day.has("translationOpportunityCountsByLanguage"));
   countsByLanguage = JSON.parse(day.get("translationOpportunityCountsByLanguage"));
   Assert.equal(countsByLanguage["fr"], 3);
   Assert.equal(countsByLanguage["es"], 1);
 
+  Assert.ok(day.has("missedTranslationOpportunityCountsByLanguage"));
+  missedCountsByLanguage = JSON.parse(day.get("missedTranslationOpportunityCountsByLanguage"));
+  Assert.equal(missedCountsByLanguage["it"], 2);
+  Assert.equal(missedCountsByLanguage["cs"], 1);
+  Assert.equal(missedCountsByLanguage["fi"], 1);
+
   yield provider.shutdown();
   yield storage.close();
 });
 
 // Test recording a translation.
 add_task(function* test_record_translation() {
   let storage = yield Metrics.Storage("translation");
   let provider = new TranslationProvider();
--- a/services/healthreport/docs/dataformat.rst
+++ b/services/healthreport/docs/dataformat.rst
@@ -1537,16 +1537,20 @@ FHR if telemetry is enabled.
 
 Version 1
 ^^^^^^^^^
 
 Daily counts are reported in the following properties:
 
 translationOpportunityCount
     Integer count of the number of opportunities there were to translate a page.
+missedTranslationOpportunityCount
+    Integer count of the number of missed opportunities there were to translate a page.
+    A missed opportunity is when the page language is not supported by the translation
+    provider.
 pageTranslatedCount
     Integer count of the number of pages translated.
 charactersTranslatedCount
     Integer count of the number of characters translated.
 detectedLanguageChangedBefore
     Integer count of the number of times the user manually adjusted the detected
     language before translating.
 detectedLanguageChangedAfter
@@ -1554,16 +1558,19 @@ detectedLanguageChangedAfter
     language after having first translated the page.
 
 Additional daily counts broken down by language are reported in the following
 properties:
 
 translationOpportunityCountsByLanguage
     A mapping from language to count of opportunities to translate that
     language.
+missedTranslationOpportunityCountsByLanguage
+    A mapping from language to count of missed opportunities to translate that
+    language.
 pageTranslatedCountsByLanguage
     A mapping from language to the counts of pages translated from that
     language. Each language entry will be an object containing a "total" member
     along with individual counts for each language translated to.
 
 Other properties:
 
 detectLanguageEnabled