Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4 "use strict";
6 module.metadata = {
7 "stability": "unstable"
8 };
10 const prefs = require("../preferences/service");
11 const { Cu, Cc, Ci } = require("chrome");
12 const { Services } = Cu.import("resource://gre/modules/Services.jsm");
14 /**
15 * Gets the currently selected locale for display.
16 * Gets all usable locale that we can use sorted by priority of relevance
17 * @return Array of locales, begins with highest priority
18 */
19 const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS";
20 const PREF_SELECTED_LOCALE = "general.useragent.locale";
21 const PREF_ACCEPT_LANGUAGES = "intl.accept_languages";
23 function getPreferedLocales(caseSensitve) {
24 let locales = [];
25 function addLocale(locale) {
26 locale = locale.trim();
27 if (!caseSensitve)
28 locale = locale.toLowerCase();
29 if (locales.indexOf(locale) === -1)
30 locales.push(locale);
31 }
33 // Most important locale is OS one. But we use it, only if
34 // "intl.locale.matchOS" pref is set to `true`.
35 // Currently only used for multi-locales mobile builds.
36 // http://mxr.mozilla.org/mozilla-central/source/mobile/android/installer/Makefile.in#46
37 if (prefs.get(PREF_MATCH_OS_LOCALE, false)) {
38 let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"].
39 getService(Ci.nsILocaleService);
40 let osLocale = localeService.getLocaleComponentForUserAgent();
41 addLocale(osLocale);
42 }
44 // In some cases, mainly on Fennec and on Linux version,
45 // `general.useragent.locale` is a special 'localized' value, like:
46 // "chrome://global/locale/intl.properties"
47 let browserUiLocale = prefs.getLocalized(PREF_SELECTED_LOCALE, "") ||
48 prefs.get(PREF_SELECTED_LOCALE, "");
49 if (browserUiLocale)
50 addLocale(browserUiLocale);
52 // Third priority is the list of locales used for web content
53 let contentLocales = prefs.get(PREF_ACCEPT_LANGUAGES, "");
54 if (contentLocales) {
55 // This list is a string of locales seperated by commas.
56 // There is spaces after commas, so strip each item
57 for each(let locale in contentLocales.split(","))
58 addLocale(locale.replace(/(^\s+)|(\s+$)/g, ""));
59 }
61 // Finally, we ensure that en-US is the final fallback if it wasn't added
62 addLocale("en-US");
64 return locales;
65 }
66 exports.getPreferedLocales = getPreferedLocales;
68 /**
69 * Selects the closest matching locale from a list of locales.
70 *
71 * @param aLocales
72 * An array of available locales
73 * @param aMatchLocales
74 * An array of prefered locales, ordered by priority. Most wanted first.
75 * Locales have to be in lowercase.
76 * If null, uses getPreferedLocales() results
77 * @return the best match for the currently selected locale
78 *
79 * Stolen from http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIProvider.jsm
80 */
81 exports.findClosestLocale = function findClosestLocale(aLocales, aMatchLocales) {
82 aMatchLocales = aMatchLocales || getPreferedLocales();
84 // Holds the best matching localized resource
85 let bestmatch = null;
86 // The number of locale parts it matched with
87 let bestmatchcount = 0;
88 // The number of locale parts in the match
89 let bestpartcount = 0;
91 for each (let locale in aMatchLocales) {
92 let lparts = locale.split("-");
93 for each (let localized in aLocales) {
94 let found = localized.toLowerCase();
95 // Exact match is returned immediately
96 if (locale == found)
97 return localized;
99 let fparts = found.split("-");
100 /* If we have found a possible match and this one isn't any longer
101 then we dont need to check further. */
102 if (bestmatch && fparts.length < bestmatchcount)
103 continue;
105 // Count the number of parts that match
106 let maxmatchcount = Math.min(fparts.length, lparts.length);
107 let matchcount = 0;
108 while (matchcount < maxmatchcount &&
109 fparts[matchcount] == lparts[matchcount])
110 matchcount++;
112 /* If we matched more than the last best match or matched the same and
113 this locale is less specific than the last best match. */
114 if (matchcount > bestmatchcount ||
115 (matchcount == bestmatchcount && fparts.length < bestpartcount)) {
116 bestmatch = localized;
117 bestmatchcount = matchcount;
118 bestpartcount = fparts.length;
119 }
120 }
121 // If we found a valid match for this locale return it
122 if (bestmatch)
123 return bestmatch;
124 }
125 return null;
126 }