1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/addon-sdk/source/lib/sdk/l10n/locale.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,126 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 +"use strict"; 1.8 + 1.9 +module.metadata = { 1.10 + "stability": "unstable" 1.11 +}; 1.12 + 1.13 +const prefs = require("../preferences/service"); 1.14 +const { Cu, Cc, Ci } = require("chrome"); 1.15 +const { Services } = Cu.import("resource://gre/modules/Services.jsm"); 1.16 + 1.17 +/** 1.18 + * Gets the currently selected locale for display. 1.19 + * Gets all usable locale that we can use sorted by priority of relevance 1.20 + * @return Array of locales, begins with highest priority 1.21 + */ 1.22 +const PREF_MATCH_OS_LOCALE = "intl.locale.matchOS"; 1.23 +const PREF_SELECTED_LOCALE = "general.useragent.locale"; 1.24 +const PREF_ACCEPT_LANGUAGES = "intl.accept_languages"; 1.25 + 1.26 +function getPreferedLocales(caseSensitve) { 1.27 + let locales = []; 1.28 + function addLocale(locale) { 1.29 + locale = locale.trim(); 1.30 + if (!caseSensitve) 1.31 + locale = locale.toLowerCase(); 1.32 + if (locales.indexOf(locale) === -1) 1.33 + locales.push(locale); 1.34 + } 1.35 + 1.36 + // Most important locale is OS one. But we use it, only if 1.37 + // "intl.locale.matchOS" pref is set to `true`. 1.38 + // Currently only used for multi-locales mobile builds. 1.39 + // http://mxr.mozilla.org/mozilla-central/source/mobile/android/installer/Makefile.in#46 1.40 + if (prefs.get(PREF_MATCH_OS_LOCALE, false)) { 1.41 + let localeService = Cc["@mozilla.org/intl/nslocaleservice;1"]. 1.42 + getService(Ci.nsILocaleService); 1.43 + let osLocale = localeService.getLocaleComponentForUserAgent(); 1.44 + addLocale(osLocale); 1.45 + } 1.46 + 1.47 + // In some cases, mainly on Fennec and on Linux version, 1.48 + // `general.useragent.locale` is a special 'localized' value, like: 1.49 + // "chrome://global/locale/intl.properties" 1.50 + let browserUiLocale = prefs.getLocalized(PREF_SELECTED_LOCALE, "") || 1.51 + prefs.get(PREF_SELECTED_LOCALE, ""); 1.52 + if (browserUiLocale) 1.53 + addLocale(browserUiLocale); 1.54 + 1.55 + // Third priority is the list of locales used for web content 1.56 + let contentLocales = prefs.get(PREF_ACCEPT_LANGUAGES, ""); 1.57 + if (contentLocales) { 1.58 + // This list is a string of locales seperated by commas. 1.59 + // There is spaces after commas, so strip each item 1.60 + for each(let locale in contentLocales.split(",")) 1.61 + addLocale(locale.replace(/(^\s+)|(\s+$)/g, "")); 1.62 + } 1.63 + 1.64 + // Finally, we ensure that en-US is the final fallback if it wasn't added 1.65 + addLocale("en-US"); 1.66 + 1.67 + return locales; 1.68 +} 1.69 +exports.getPreferedLocales = getPreferedLocales; 1.70 + 1.71 +/** 1.72 + * Selects the closest matching locale from a list of locales. 1.73 + * 1.74 + * @param aLocales 1.75 + * An array of available locales 1.76 + * @param aMatchLocales 1.77 + * An array of prefered locales, ordered by priority. Most wanted first. 1.78 + * Locales have to be in lowercase. 1.79 + * If null, uses getPreferedLocales() results 1.80 + * @return the best match for the currently selected locale 1.81 + * 1.82 + * Stolen from http://mxr.mozilla.org/mozilla-central/source/toolkit/mozapps/extensions/internal/XPIProvider.jsm 1.83 + */ 1.84 +exports.findClosestLocale = function findClosestLocale(aLocales, aMatchLocales) { 1.85 + aMatchLocales = aMatchLocales || getPreferedLocales(); 1.86 + 1.87 + // Holds the best matching localized resource 1.88 + let bestmatch = null; 1.89 + // The number of locale parts it matched with 1.90 + let bestmatchcount = 0; 1.91 + // The number of locale parts in the match 1.92 + let bestpartcount = 0; 1.93 + 1.94 + for each (let locale in aMatchLocales) { 1.95 + let lparts = locale.split("-"); 1.96 + for each (let localized in aLocales) { 1.97 + let found = localized.toLowerCase(); 1.98 + // Exact match is returned immediately 1.99 + if (locale == found) 1.100 + return localized; 1.101 + 1.102 + let fparts = found.split("-"); 1.103 + /* If we have found a possible match and this one isn't any longer 1.104 + then we dont need to check further. */ 1.105 + if (bestmatch && fparts.length < bestmatchcount) 1.106 + continue; 1.107 + 1.108 + // Count the number of parts that match 1.109 + let maxmatchcount = Math.min(fparts.length, lparts.length); 1.110 + let matchcount = 0; 1.111 + while (matchcount < maxmatchcount && 1.112 + fparts[matchcount] == lparts[matchcount]) 1.113 + matchcount++; 1.114 + 1.115 + /* If we matched more than the last best match or matched the same and 1.116 + this locale is less specific than the last best match. */ 1.117 + if (matchcount > bestmatchcount || 1.118 + (matchcount == bestmatchcount && fparts.length < bestpartcount)) { 1.119 + bestmatch = localized; 1.120 + bestmatchcount = matchcount; 1.121 + bestpartcount = fparts.length; 1.122 + } 1.123 + } 1.124 + // If we found a valid match for this locale return it 1.125 + if (bestmatch) 1.126 + return bestmatch; 1.127 + } 1.128 + return null; 1.129 +}