Bug 1481790 - Determine locale dependent default values for preferences without a localized preference file. r=philipp
authorMakeMyDay <makemyday@gmx-topmail.de>
Thu, 23 Aug 2018 09:40:14 +0200
changeset 24552 6d879599a12695435e7f39bc5bd3076d761301de
parent 24551 c451efd60c38438871bfd74806e4e838f526cb60
child 24553 fb37006d3c59c2d87b78fc022007768c06cc525e
push id14778
push usermozilla@jorgk.com
push dateThu, 23 Aug 2018 21:59:01 +0000
treeherdercomm-central@fb37006d3c59 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersphilipp
bugs1481790
Bug 1481790 - Determine locale dependent default values for preferences without a localized preference file. r=philipp
calendar/base/content/calendar-chrome-startup.js
calendar/base/modules/utils/calL10NUtils.jsm
calendar/test/unit/test_l10n_utils.js
calendar/test/unit/xpcshell-shared.ini
--- a/calendar/base/content/calendar-chrome-startup.js
+++ b/calendar/base/content/calendar-chrome-startup.js
@@ -8,16 +8,19 @@ ChromeUtils.import("resource://gre/modul
 ChromeUtils.import("resource://gre/modules/AppConstants.jsm");
 
 /* exported commonInitCalendar, commonFinishCalendar */
 
 /**
  * Common initialization steps for calendar chrome windows.
  */
 function commonInitCalendar() {
+    // load locale specific default values for preferences
+    setLocaleDefaultPreferences();
+
     // Move around toolbarbuttons and whatever is needed in the UI.
     migrateCalendarUI();
 
     // Load the Calendar Manager
     loadCalendarManager();
 
     // set up the unifinder
     prepareCalendarToDoUnifinder();
@@ -218,8 +221,56 @@ function migrateCalendarUI() {
             }
         }
         Preferences.set("calendar.ui.version", UI_VERSION);
     } catch (e) {
         cal.ERROR("Error upgrading UI from " + currentUIVersion + " to " +
                   UI_VERSION + ": " + e);
     }
 }
+
+function setLocaleDefaultPreferences() {
+    function setDefaultLocaleValue(aName) {
+        let startDefault = calendarInfo.firstDayOfWeek - 1;
+        if (aName == "calendar.categories.names" &&
+            defaultBranch.getStringPref(aName) == "") {
+            defaultBranch.setStringPref(aName, cal.l10n.getString("categories", "categories2"));
+        } else if (aName == "calendar.week.start" &&
+                   defaultBranch.getIntPref(aName) != startDefault) {
+            defaultBranch.setIntPref(aName, startDefault);
+        } else if (aName.startsWith("calendar.week.d")) {
+            let weStart = calendarInfo.weekendStart - 1;
+            let weEnd = calendarInfo.weekendEnd - 1;
+            if (weStart > weEnd) {
+                weEnd += 7;
+            }
+            let weekend = [];
+            for (let i = weStart; i <= weEnd; i++) {
+                weekend.push(i > 6 ? i - 7 : i);
+            }
+            if (defaultBranch.getBoolPref(aName) === weekend.includes(aName[15])) {
+                defaultBranch.setBoolPref(aName, weekend.includes(aName[15]));
+            }
+        }
+    }
+
+    cal.LOG("Start loading of locale dependent preference default values...");
+
+    let defaultBranch = Services.prefs.getDefaultBranch("");
+    let calendarInfo = cal.l10n.calendarInfo();
+
+    let prefDefaults = [
+        "calendar.week.start",
+        "calendar.week.d0sundaysoff",
+        "calendar.week.d1mondaysoff",
+        "calendar.week.d2tuesdaysoff",
+        "calendar.week.d3wednesdaysoff",
+        "calendar.week.d4thursdaysoff",
+        "calendar.week.d5fridaysoff",
+        "calendar.week.d6saturdaysoff",
+        "calendar.categories.names"
+    ];
+    for (let prefDefault of prefDefaults) {
+        setDefaultLocaleValue(prefDefault);
+    }
+
+    cal.LOG("Loading of locale sensitive preference default values completed.");
+}
--- a/calendar/base/modules/utils/calL10NUtils.jsm
+++ b/calendar/base/modules/utils/calL10NUtils.jsm
@@ -39,16 +39,45 @@ function _getString(aComponent, aBundleN
     } catch (ex) {
         let msg = `Failed to read '${aStringName}' from ${propName}.`;
         Components.utils.reportError(`${msg} Error: ${ex}`);
         return aStringName;
     }
 }
 _getString._bundleCache = {};
 
+/**
+ * Provides locale dependent parameters for displaying calendar views
+ *
+ * @param {String}  aLocale      The locale to get the info for, e.g. "en-US",
+ *                                 "de-DE" or null for the current locale
+ * @param {Bollean} aResetCache  Whether to reset the internal cache - for test
+ *                                 purposes only don't use it otherwise atm
+ * @return {Object}              The getCalendarInfo object from mozIMozIntl
+ */
+function _calendarInfo(aLocale=null, aResetCache=false) {
+    if (aResetCache) {
+        _calendarInfo._startup = {};
+    }
+    // we cache the result to prevent updates at runtime except for test
+    // purposes since changing intl.regional_prefs.use_os_locales preference
+    // would provide different result when called without aLocale and we
+    // need to investigate whether this is wanted or chaching more selctively.
+    // when starting to use it to deteremine the first week of a year, we would
+    // need to at least reset that chached properties on pref change.
+    if (!("firstDayOfWeek" in _calendarInfo._startup) || aLocale) {
+        let info = Services.intl.getCalendarInfo(aLocale);
+        if (aLocale) {
+            return info;
+        }
+        _calendarInfo._startup = info;
+    }
+    return _calendarInfo._startup;
+}
+_calendarInfo._startup = {};
 
 var call10n = {
     /**
      * Gets the value of a string in a .properties file.
      *
      * @param {String} aComponent       Stringbundle component name
      * @param {String} aBundleName      The name of the properties file
      * @param {String} aStringName      The name of the string within the properties file
@@ -129,10 +158,19 @@ var call10n = {
      *
      * @param {String[]} aStringArray   The strings to sort
      * @return {String[]}               The sorted strings, more specifically aStringArray
      */
     sortArrayByLocaleCollator: function(aStringArray) {
         let collator = call10n.createLocaleCollator();
         aStringArray.sort((a, b) => collator.compareString(0, a, b));
         return aStringArray;
-    }
+    },
+
+    /**
+     * Provides locale dependent parameters for displaying calendar views
+     *
+     * @param {String} aLocale     The locale to get the info for, e.g. "en-US",
+     *                               "de-DE" or null for the current locale
+     * @return {Object}            The getCalendarInfo object from mozIMozIntl
+     */
+    calendarInfo: _calendarInfo
 };
new file mode 100644
--- /dev/null
+++ b/calendar/test/unit/test_l10n_utils.js
@@ -0,0 +1,107 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+ChromeUtils.import("resource://gre/modules/Preferences.jsm");
+ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+function run_test() {
+    do_calendar_startup(run_next_test);
+}
+
+// tests for calL10NUtils.jsm
+/* Incomplete - still missing test coverage for:
+   * getAnyString
+   * getString
+   * getCalString
+   * getLtnString
+   * getDateFmtString
+   * formatMonth
+   * createLocaleCollator
+*/
+
+add_task(async function calendarInfo_test() {
+    let data = [{
+        input: { locale: "en-US" },
+        expected: {
+            properties: [
+                "firstDayOfWeek", "minDays", "weekendStart", "weekendEnd",
+                "calendar", "locale"
+            ]
+        }
+    }, {
+        input: { locale: "EN-US" },
+        expected: {
+            properties: [
+                "firstDayOfWeek", "minDays", "weekendStart", "weekendEnd",
+                "calendar", "locale"
+            ]
+        }
+    }, {
+        input: { locale: "et" },
+        expected: {
+            properties: [
+                "firstDayOfWeek", "minDays", "weekendStart", "weekendEnd",
+                "calendar", "locale"
+            ]
+        }
+    }, {
+        input: { locale: null }, // this also would trigger caching tests
+        expected: {
+            properties: [
+                "firstDayOfWeek", "minDays", "weekendStart", "weekendEnd",
+                "calendar", "locale"
+            ]
+        }
+    }];
+    let useOSLocaleFormat = Preferences.get("intl.regional_prefs.use_os_locales", false);
+    // let localeService = Cc["@mozilla.org/intl/localeservice;1"].getService(Ci.mozILocaleService);
+    let osprefs = Cc["@mozilla.org/intl/ospreferences;1"].getService(Ci.mozIOSPreferences);
+    let appLocale = Services.locale.getAppLocalesAsBCP47()[0];
+    let rsLocale = osprefs.getRegionalPrefsLocales()[0];
+
+    let i = 0;
+    for (let test of data) {
+        i++;
+        let info = cal.l10n.calendarInfo(test.input.locale);
+        equal(
+            Object.keys(info).length,
+            test.expected.properties.length,
+            "expected number of attributes (test #" + i + ")"
+        );
+        for (let prop of test.expected.properties) {
+            ok(prop in info, prop + " exists (test #" + i + ")");
+        }
+
+        if (!test.input.locale && appLocale != rsLocale) {
+            // if aLoacle is null we test with the current date and time formatting setting
+            // let's test the caching mechanism - this test section is pointless if app and
+            // OS locale are the same like probably on automation
+            Preferences.set("intl.regional_prefs.use_os_locales", !useOSLocaleFormat);
+            let info2 = cal.l10n.calendarInfo();
+            equal(
+                Object.keys(info).length,
+                test.expected.properties.length,
+                "caching test - equal number of properties (test #" + i + ")"
+            );
+            for (let prop of Object.keys(info)) {
+                ok(prop in info2,
+                   "caching test - " + prop + " exists in both objects (test #" + i + ")");
+                equal(
+                    info2[prop],
+                    info[prop],
+                    "caching test - value for " + prop + " is equal in both objects (test #" + i + ")"
+                );
+            }
+            // we reset the cache and test again - it's suffient here to find one changed property,
+            // so we use locale since that must change always in that scenario
+            info2 = cal.l10n.calendarInfo(null, true);
+            Preferences.set("intl.regional_prefs.use_os_locales", useOSLocaleFormat);
+            notEqual(
+                info2.locale,
+                info.locale,
+                "caching retest - value for locale is different in both objects (test #" + i + ")"
+            );
+        }
+    }
+});
--- a/calendar/test/unit/xpcshell-shared.ini
+++ b/calendar/test/unit/xpcshell-shared.ini
@@ -32,16 +32,17 @@
 [test_gdata_provider.js]
 skip-if = true # See bug 1481180. requesttimeoutfactor = 2
 [test_hashedarray.js]
 [test_ics.js]
 [test_ics_parser.js]
 [test_ics_service.js]
 [test_imip.js]
 [test_items.js]
+[test_l10n_utils.js]
 [test_ltninvitationutils.js]
 [test_providers.js]
 [test_recur.js]
 [test_relation.js]
 [test_rfc3339_parser.js]
 [test_search_service.js]
 [test_startup_service.js]
 [test_storage.js]