summaryrefslogtreecommitdiffstats
path: root/intl/locale
diff options
context:
space:
mode:
Diffstat (limited to 'intl/locale')
-rw-r--r--intl/locale/PluralForm.jsm184
-rw-r--r--intl/locale/langGroups.properties226
-rw-r--r--intl/locale/language.properties273
-rw-r--r--intl/locale/mac/moz.build16
-rw-r--r--intl/locale/mac/nsCollationMacUC.cpp253
-rw-r--r--intl/locale/mac/nsCollationMacUC.h44
-rw-r--r--intl/locale/mac/nsDateTimeFormatMac.cpp266
-rw-r--r--intl/locale/mac/nsDateTimeFormatMac.h61
-rw-r--r--intl/locale/mac/nsMacCharset.cpp59
-rw-r--r--intl/locale/moz.build69
-rw-r--r--intl/locale/nsCollation.cpp134
-rw-r--r--intl/locale/nsCollation.h51
-rw-r--r--intl/locale/nsCollationCID.h27
-rw-r--r--intl/locale/nsDateTimeFormatCID.h20
-rw-r--r--intl/locale/nsICollation.idl64
-rw-r--r--intl/locale/nsIDateTimeFormat.cpp39
-rw-r--r--intl/locale/nsIDateTimeFormat.h69
-rw-r--r--intl/locale/nsILanguageAtomService.h45
-rw-r--r--intl/locale/nsILocale.idl47
-rw-r--r--intl/locale/nsILocaleService.idl77
-rw-r--r--intl/locale/nsIPlatformCharset.h58
-rw-r--r--intl/locale/nsIScriptableDateFormat.idl179
-rw-r--r--intl/locale/nsLanguageAtomService.cpp123
-rw-r--r--intl/locale/nsLanguageAtomService.h42
-rw-r--r--intl/locale/nsLocale.cpp108
-rw-r--r--intl/locale/nsLocale.h52
-rw-r--r--intl/locale/nsLocaleConstructors.h79
-rw-r--r--intl/locale/nsLocaleService.cpp380
-rw-r--r--intl/locale/nsPlatformCharset.h35
-rw-r--r--intl/locale/nsPosixLocale.h24
-rw-r--r--intl/locale/nsScriptableDateFormat.cpp145
-rw-r--r--intl/locale/nsUConvPropertySearch.cpp44
-rw-r--r--intl/locale/nsUConvPropertySearch.h37
-rw-r--r--intl/locale/nsWin32Locale.h32
-rw-r--r--intl/locale/props2arrays.py27
-rw-r--r--intl/locale/tests/nsLocaleTest.html44
-rw-r--r--intl/locale/tests/sort/us-ascii_base.txt95
-rw-r--r--intl/locale/tests/sort/us-ascii_base_case_res.txt96
-rw-r--r--intl/locale/tests/sort/us-ascii_base_nocase_res.txt96
-rw-r--r--intl/locale/tests/sort/us-ascii_sort.txt78
-rw-r--r--intl/locale/tests/sort/us-ascii_sort_case_res.txt79
-rw-r--r--intl/locale/tests/sort/us-ascii_sort_nocase_res.txt79
-rw-r--r--intl/locale/tests/unit/data/chrome.manifest1
-rw-r--r--intl/locale/tests/unit/data/intl_on_workers_worker.js4
-rw-r--r--intl/locale/tests/unit/test_bug1086527.js20
-rw-r--r--intl/locale/tests/unit/test_bug22310.js54
-rw-r--r--intl/locale/tests/unit/test_bug371611.js26
-rw-r--r--intl/locale/tests/unit/test_bug374040.js39
-rw-r--r--intl/locale/tests/unit/test_collation_mac_icu.js83
-rw-r--r--intl/locale/tests/unit/test_intl_on_workers.js23
-rw-r--r--intl/locale/tests/unit/test_pluralForm.js615
-rw-r--r--intl/locale/tests/unit/test_pluralForm_english.js26
-rw-r--r--intl/locale/tests/unit/test_pluralForm_makeGetter.js36
-rw-r--r--intl/locale/tests/unit/xpcshell.ini22
-rw-r--r--intl/locale/unix/moz.build38
-rw-r--r--intl/locale/unix/nsAndroidCharset.cpp49
-rw-r--r--intl/locale/unix/nsCollationUnix.cpp189
-rw-r--r--intl/locale/unix/nsCollationUnix.h43
-rw-r--r--intl/locale/unix/nsDateTimeFormatUnix.cpp284
-rw-r--r--intl/locale/unix/nsDateTimeFormatUnix.h70
-rw-r--r--intl/locale/unix/nsPosixLocale.cpp243
-rw-r--r--intl/locale/unix/nsUNIXCharset.cpp185
-rw-r--r--intl/locale/unix/unixcharset.properties536
-rw-r--r--intl/locale/windows/moz.build26
-rw-r--r--intl/locale/windows/nsCollationWin.cpp146
-rw-r--r--intl/locale/windows/nsCollationWin.h35
-rw-r--r--intl/locale/windows/nsDateTimeFormatWin.cpp253
-rw-r--r--intl/locale/windows/nsDateTimeFormatWin.h71
-rw-r--r--intl/locale/windows/nsWin32Locale.cpp748
-rw-r--r--intl/locale/windows/nsWinCharset.cpp101
-rw-r--r--intl/locale/windows/wincharset.properties23
71 files changed, 7945 insertions, 0 deletions
diff --git a/intl/locale/PluralForm.jsm b/intl/locale/PluralForm.jsm
new file mode 100644
index 000000000..9f249fce5
--- /dev/null
+++ b/intl/locale/PluralForm.jsm
@@ -0,0 +1,184 @@
+/* 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/. */
+
+this.EXPORTED_SYMBOLS = [ "PluralForm" ];
+
+/**
+ * This module provides the PluralForm object which contains a method to figure
+ * out which plural form of a word to use for a given number based on the
+ * current localization. There is also a makeGetter method that creates a get
+ * function for the desired plural rule. This is useful for extensions that
+ * specify their own plural rule instead of relying on the browser default.
+ * (I.e., the extension hasn't been localized to the browser's locale.)
+ *
+ * See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
+ *
+ * List of methods:
+ *
+ * string pluralForm
+ * get(int aNum, string aWords)
+ *
+ * int numForms
+ * numForms()
+ *
+ * [string pluralForm get(int aNum, string aWords), int numForms numForms()]
+ * makeGetter(int aRuleNum)
+ * Note: Basically, makeGetter returns 2 functions that do "get" and "numForm"
+ */
+
+const Cc = Components.classes;
+const Ci = Components.interfaces;
+
+const kIntlProperties = "chrome://global/locale/intl.properties";
+
+// These are the available plural functions that give the appropriate index
+// based on the plural rule number specified. The first element is the number
+// of plural forms and the second is the function to figure out the index.
+var gFunctions = [
+ // 0: Chinese
+ [1, (n) => 0],
+ // 1: English
+ [2, (n) => n!=1?1:0],
+ // 2: French
+ [2, (n) => n>1?1:0],
+ // 3: Latvian
+ [3, (n) => n%10==1&&n%100!=11?1:n!=0?2:0],
+ // 4: Scottish Gaelic
+ [4, (n) => n==1||n==11?0:n==2||n==12?1:n>0&&n<20?2:3],
+ // 5: Romanian
+ [3, (n) => n==1?0:n==0||n%100>0&&n%100<20?1:2],
+ // 6: Lithuanian
+ [3, (n) => n%10==1&&n%100!=11?0:n%10>=2&&(n%100<10||n%100>=20)?2:1],
+ // 7: Russian
+ [3, (n) => n%10==1&&n%100!=11?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2],
+ // 8: Slovak
+ [3, (n) => n==1?0:n>=2&&n<=4?1:2],
+ // 9: Polish
+ [3, (n) => n==1?0:n%10>=2&&n%10<=4&&(n%100<10||n%100>=20)?1:2],
+ // 10: Slovenian
+ [4, (n) => n%100==1?0:n%100==2?1:n%100==3||n%100==4?2:3],
+ // 11: Irish Gaeilge
+ [5, (n) => n==1?0:n==2?1:n>=3&&n<=6?2:n>=7&&n<=10?3:4],
+ // 12: Arabic
+ [6, (n) => n==0?5:n==1?0:n==2?1:n%100>=3&&n%100<=10?2:n%100>=11&&n%100<=99?3:4],
+ // 13: Maltese
+ [4, (n) => n==1?0:n==0||n%100>0&&n%100<=10?1:n%100>10&&n%100<20?2:3],
+ // 14: Macedonian
+ [3, (n) => n%10==1?0:n%10==2?1:2],
+ // 15: Icelandic
+ [2, (n) => n%10==1&&n%100!=11?0:1],
+ // 16: Breton
+ [5, (n) => n%10==1&&n%100!=11&&n%100!=71&&n%100!=91?0:n%10==2&&n%100!=12&&n%100!=72&&n%100!=92?1:(n%10==3||n%10==4||n%10==9)&&n%100!=13&&n%100!=14&&n%100!=19&&n%100!=73&&n%100!=74&&n%100!=79&&n%100!=93&&n%100!=94&&n%100!=99?2:n%1000000==0&&n!=0?3:4],
+];
+
+this.PluralForm = {
+ /**
+ * Get the correct plural form of a word based on the number
+ *
+ * @param aNum
+ * The number to decide which plural form to use
+ * @param aWords
+ * A semi-colon (;) separated string of words to pick the plural form
+ * @return The appropriate plural form of the word
+ */
+ get get()
+ {
+ // This method will lazily load to avoid perf when it is first needed and
+ // creates getPluralForm function. The function it creates is based on the
+ // value of pluralRule specified in the intl stringbundle.
+ // See: http://developer.mozilla.org/en/docs/Localization_and_Plurals
+
+ // Delete the getters to be overwritten
+ delete PluralForm.numForms;
+ delete PluralForm.get;
+
+ // Make the plural form get function and set it as the default get
+ [PluralForm.get, PluralForm.numForms] = PluralForm.makeGetter(PluralForm.ruleNum);
+ return PluralForm.get;
+ },
+
+ /**
+ * Create a pair of plural form functions for the given plural rule number.
+ *
+ * @param aRuleNum
+ * The plural rule number to create functions
+ * @return A pair: [function that gets the right plural form,
+ * function that returns the number of plural forms]
+ */
+ makeGetter: function(aRuleNum)
+ {
+ // Default to "all plural" if the value is out of bounds or invalid
+ if (aRuleNum < 0 || aRuleNum >= gFunctions.length || isNaN(aRuleNum)) {
+ log(["Invalid rule number: ", aRuleNum, " -- defaulting to 0"]);
+ aRuleNum = 0;
+ }
+
+ // Get the desired pluralRule function
+ let [numForms, pluralFunc] = gFunctions[aRuleNum];
+
+ // Return functions that give 1) the number of forms and 2) gets the right
+ // plural form
+ return [function(aNum, aWords) {
+ // Figure out which index to use for the semi-colon separated words
+ let index = pluralFunc(aNum ? Number(aNum) : 0);
+ let words = aWords ? aWords.split(/;/) : [""];
+
+ // Explicitly check bounds to avoid strict warnings
+ let ret = index < words.length ? words[index] : undefined;
+
+ // Check for array out of bounds or empty strings
+ if ((ret == undefined) || (ret == "")) {
+ // Report the caller to help figure out who is causing badness
+ let caller = Components.stack.caller ? Components.stack.caller.name : "top";
+
+ // Display a message in the error console
+ log(["Index #", index, " of '", aWords, "' for value ", aNum,
+ " is invalid -- plural rule #", aRuleNum, "; called by ", caller]);
+
+ // Default to the first entry (which might be empty, but not undefined)
+ ret = words[0];
+ }
+
+ return ret;
+ }, () => numForms];
+ },
+
+ /**
+ * Get the number of forms for the current plural rule
+ *
+ * @return The number of forms
+ */
+ get numForms()
+ {
+ // We lazily load numForms, so trigger the init logic with get()
+ PluralForm.get();
+ return PluralForm.numForms;
+ },
+
+ /**
+ * Get the plural rule number from the intl stringbundle
+ *
+ * @return The plural rule number
+ */
+ get ruleNum()
+ {
+ return Number(Cc["@mozilla.org/intl/stringbundle;1"].
+ getService(Ci.nsIStringBundleService).createBundle(kIntlProperties).
+ GetStringFromName("pluralRule"));
+ }
+};
+
+/**
+ * Private helper function to log errors to the error console and command line
+ *
+ * @param aMsg
+ * Error message to log or an array of strings to concat
+ */
+function log(aMsg)
+{
+ let msg = "PluralForm.jsm: " + (aMsg.join ? aMsg.join("") : aMsg);
+ Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).
+ logStringMessage(msg);
+ dump(msg + "\n");
+}
diff --git a/intl/locale/langGroups.properties b/intl/locale/langGroups.properties
new file mode 100644
index 000000000..dd573bd75
--- /dev/null
+++ b/intl/locale/langGroups.properties
@@ -0,0 +1,226 @@
+#
+# 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/.
+#
+# References: http://www.omniglot.com/writing/atoz.htm
+# http://www.loc.gov/standards/iso639-2/englangn.html
+# http://www.ethnologue.com
+# http://www.worldlanguage.com/Languages/
+# http://www.rosettaproject.org/
+# http://www.sweb.cz/ls78/diacritics.htm
+# see also toolkit/locales/en-US/chrome/global/languageNames.properties
+# and bug 178491
+#
+# Strictly speaking, Avestan did not use Arabic script but Aramaic
+# (arc)/Avestan script.)
+#ae=ar
+
+ab=x-cyrillic
+af=x-western
+alg=x-cans
+am=x-ethi
+ar=ar
+as=x-beng
+ay=x-western
+be=x-cyrillic
+bg=x-cyrillic
+bn=x-beng
+bo=x-tibt
+br=x-western
+bs=x-western
+ca=x-western
+ce=x-western
+ch=x-western
+co=x-western
+cr=x-cans
+cs=x-western
+csb=x-western
+#cu=x-cyrillic
+cv=x-cyrillic
+cy=x-western
+da=x-western
+de=x-western
+dsb=x-western
+#dv=Thaanna
+dz=x-tibt
+ee=x-western
+el=el
+en=x-western
+eo=x-western
+es=x-western
+et=x-western
+eu=x-western
+fa=ar
+ff=x-western
+fi=x-western
+fj=x-western
+fo=x-western
+fr=x-western
+fy=x-western
+ga=x-western
+gd=x-western
+gl=x-western
+gn=x-western
+#ha=x-western : Latin and Ajami scripts
+gu=x-gujr
+gv=x-western
+haw=x-western
+he=he
+hi=x-devanagari
+hil=x-western
+hr=x-western
+hsb=x-western
+ht=x-western
+hu=x-western
+hy=x-armn
+ia=x-western
+id=x-western
+ie=x-western
+is=x-western
+it=x-western
+iu=x-cans
+ja=ja
+ka=x-geor
+kk=x-cyrillic
+kl=x-western
+km=x-khmr
+kn=x-knda
+ko=ko
+kok=x-devanagari
+ks=ar
+# Arabic script is also used for Kurdish
+ku=x-western
+kw=x-western
+#ky=x-cyrillic
+la=x-western
+lb=x-western
+ln=x-western
+lt=x-western
+lv=x-western
+mg=x-western
+mh=x-western
+mi=x-western
+mk=x-cyrillic
+ml=x-mlym
+# Mongolian script is also used for Mongolian
+mn=x-cyrillic
+mr=x-devanagari
+ms=x-western
+mt=x-western
+na=x-western
+nb=x-western
+nd=x-western
+ne=x-devanagari
+nl=x-western
+nn=x-western
+no=x-western
+nr=x-western
+nso=x-western
+nv=x-western
+ny=x-western
+oc=x-western
+oj=x-cans
+om=x-western
+or=x-orya
+os=x-cyrillic
+#pa: Punjabi is usually written in Gurmukhi script in India and Arabic script
+# in Pakistan. We make pa default to Gurmukhi based on comments in bug 248690
+pa-in=x-guru
+pa-pk=ar
+pa=x-guru
+pl=x-western
+ps=ar
+pt=x-western
+qu=x-western
+rm=x-western
+rn=x-western
+ro=x-western
+ru=x-cyrillic
+rw=x-western
+sa=x-devanagari
+sc=x-western
+sd=ar
+# African language (but related with French)
+sg=x-western
+sh=x-western
+si=x-sinh
+sk=x-western
+sl=x-western
+sm=x-western
+so=x-western
+son=x-western
+sq=x-western
+sr=x-cyrillic
+ss=x-western
+st=x-western
+sv=x-western
+sw=x-western
+ta=x-tamil
+te=x-telu
+th=th
+ti=x-ethi
+tig=x-ethi
+tk=x-cyrillic
+#tk=x-western # (The country declared in 1992 to gradually move to Latin script)
+tl=x-western
+tlh=x-western
+tn=x-western
+to=x-western
+tr=x-western
+ts=x-western
+tt=x-western
+uk=x-cyrillic
+ur=ar
+ve=x-western
+vi=x-western
+vo=x-western
+wa=x-western
+wo=x-western
+xh=x-western
+yi=he
+yo=x-western
+zh-cn=zh-CN
+# XXX : The following five entries are added as a quick fix (bug 251241, bug 1104589).
+# When we have a general solution for ISO 15924 (script codes), the issue has
+# to be revisited.
+zh-hans=zh-CN
+zh-hant=zh-TW
+zh-latn=x-western
+ja-latn=x-western
+ko-latn=x-western
+#
+zh-tw=zh-TW
+zh-hk=zh-HK
+zh=zh-CN
+zh-min-nan=x-western
+zu=x-western
+#
+#==============================
+#
+# mapping mozilla's internal x-* to themselves (see bug 256257)
+x-western=x-western
+x-cyrillic=x-cyrillic
+# el
+# he
+# ar
+# th
+# ja
+# zh-CN
+# ko
+# zh-TW
+x-tamil=x-tamil
+x-devanagari=x-devanagari
+x-unicode=x-unicode
+x-armn=x-armn
+x-geor=x-geor
+x-math=x-math
+# These self-mappings are not necessary unless somebody use them to specify
+# lang in (X)HTML/XML documents, which they shouldn't. (see bug 256257)
+#x-beng=x-beng
+#x-cans=x-cans
+#x-ethi=x-ethi
+#x-guru=x-guru
+#x-gujr=x-gujr
+#x-khmr=x-khmr
+#x-mlym=x-mlym
diff --git a/intl/locale/language.properties b/intl/locale/language.properties
new file mode 100644
index 000000000..75179063c
--- /dev/null
+++ b/intl/locale/language.properties
@@ -0,0 +1,273 @@
+# 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/.
+
+aa.accept = true
+ab.accept = true
+ae.accept = true
+af.accept = true
+ak.accept = true
+am.accept = true
+an.accept = true
+ar.accept = true
+ar-ae.accept = true
+ar-bh.accept = true
+ar-dz.accept = true
+ar-eg.accept = true
+ar-iq.accept = true
+ar-jo.accept = true
+ar-kw.accept = true
+ar-lb.accept = true
+ar-ly.accept = true
+ar-ma.accept = true
+ar-om.accept = true
+ar-qa.accept = true
+ar-sa.accept = true
+ar-sy.accept = true
+ar-tn.accept = true
+ar-ye.accept = true
+as.accept = true
+ast.accept = true
+av.accept = true
+ay.accept = true
+az.accept = true
+ba.accept = true
+be.accept = true
+bg.accept = true
+bh.accept = true
+bi.accept = true
+bm.accept = true
+bn.accept = true
+bo.accept = true
+br.accept = true
+bs.accept = true
+ca.accept = true
+ce.accept = true
+ch.accept = true
+co.accept = true
+cr.accept = true
+cs.accept = true
+csb.accept = true
+cu.accept = true
+cv.accept = true
+cy.accept = true
+da.accept = true
+de.accept = true
+de-at.accept = true
+de-ch.accept = true
+de-de.accept = true
+de-li.accept = true
+de-lu.accept = true
+dsb.accept = true
+dv.accept = true
+dz.accept = true
+ee.accept = true
+el.accept = true
+en.accept = true
+en-au.accept = true
+en-bz.accept = true
+en-ca.accept = true
+en-gb.accept = true
+en-ie.accept = true
+en-jm.accept = true
+en-nz.accept = true
+en-ph.accept = true
+en-tt.accept = true
+en-us.accept = true
+en-za.accept = true
+en-zw.accept = true
+eo.accept = true
+es.accept = true
+es-ar.accept = true
+es-bo.accept = true
+es-cl.accept = true
+es-co.accept = true
+es-cr.accept = true
+es-do.accept = true
+es-ec.accept = true
+es-es.accept = true
+es-gt.accept = true
+es-hn.accept = true
+es-mx.accept = true
+es-ni.accept = true
+es-pa.accept = true
+es-pe.accept = true
+es-pr.accept = true
+es-py.accept = true
+es-sv.accept = true
+es-uy.accept = true
+es-ve.accept = true
+et.accept = true
+eu.accept = true
+fa.accept = true
+fa-ir.accept = true
+ff.accept = true
+fi.accept = true
+fj.accept = true
+fo.accept = true
+fr.accept = true
+fr-be.accept = true
+fr-ca.accept = true
+fr-ch.accept = true
+fr-fr.accept = true
+fr-lu.accept = true
+fr-mc.accept = true
+fur.accept = true
+fy.accept = true
+ga.accept = true
+gd.accept = true
+gl.accept = true
+gn.accept = true
+gu.accept = true
+gv.accept = true
+ha.accept = true
+haw.accept = true
+he.accept = true
+hi.accept = true
+hil.accept = true
+ho.accept = true
+hsb.accept = true
+hr.accept = true
+ht.accept = true
+hu.accept = true
+hy.accept = true
+hz.accept = true
+ia.accept = true
+id.accept = true
+ie.accept = true
+ig.accept = true
+ii.accept = true
+ik.accept = true
+io.accept = true
+is.accept = true
+it.accept = true
+it-ch.accept = true
+iu.accept = true
+ja.accept = true
+jv.accept = true
+ka.accept = true
+kg.accept = true
+ki.accept = true
+kk.accept = true
+kl.accept = true
+km.accept = true
+kn.accept = true
+ko.accept = true
+ko-kp.accept = true
+ko-kr.accept = true
+kok.accept = true
+kr.accept = true
+ks.accept = true
+ku.accept = true
+kv.accept = true
+kw.accept = true
+ky.accept = true
+la.accept = true
+lb.accept = true
+lg.accept = true
+li.accept = true
+ln.accept = true
+lo.accept = true
+lt.accept = true
+lu.accept = true
+lv.accept = true
+mg.accept = true
+mh.accept = true
+mi.accept = true
+mk.accept = true
+mk-mk.accept = true
+ml.accept = true
+mn.accept = true
+mr.accept = true
+ms.accept = true
+mt.accept = true
+my.accept = true
+na.accept = true
+nb.accept = true
+nd.accept = true
+ne.accept = true
+ng.accept = true
+nl.accept = true
+nl-be.accept = true
+nn.accept = true
+no.accept = true
+nr.accept = true
+nso.accept = true
+nv.accept = true
+ny.accept = true
+oc.accept = true
+oj.accept = true
+om.accept = true
+or.accept = true
+os.accept = true
+pa.accept = true
+pa-in.accept = true
+pa-pk.accept = true
+pi.accept = true
+pl.accept = true
+ps.accept = true
+pt.accept = true
+pt-br.accept = true
+qu.accept = true
+rm.accept = true
+rn.accept = true
+ro.accept = true
+ro-md.accept = true
+ro-ro.accept = true
+ru.accept = true
+ru-md.accept = true
+rw.accept = true
+sa.accept = true
+sc.accept = true
+sd.accept = true
+sg.accept = true
+si.accept = true
+sk.accept = true
+sl.accept = true
+sm.accept = true
+so.accept = true
+son-ml.accept = true
+sq.accept = true
+sr.accept = true
+ss.accept = true
+st.accept = true
+su.accept = true
+sv.accept = true
+sv-fi.accept = true
+sv-se.accept = true
+sw.accept = true
+ta.accept = true
+te.accept = true
+tg.accept = true
+th.accept = true
+ti.accept = true
+tig.accept = true
+tk.accept = true
+tl.accept = true
+tlh.accept = true
+tn.accept = true
+to.accept = true
+tr.accept = true
+ts.accept = true
+tt.accept = true
+tw.accept = true
+ty.accept = true
+ug.accept = true
+uk.accept = true
+ur.accept = true
+uz.accept = true
+ve.accept = true
+vi.accept = true
+vo.accept = true
+wa.accept = true
+wo.accept = true
+xh.accept = true
+yi.accept = true
+yo.accept = true
+za.accept = true
+zh.accept = true
+zh-cn.accept = true
+zh-hk.accept = true
+zh-sg.accept = true
+zh-tw.accept = true
+zu.accept = true
diff --git a/intl/locale/mac/moz.build b/intl/locale/mac/moz.build
new file mode 100644
index 000000000..beda4fa26
--- /dev/null
+++ b/intl/locale/mac/moz.build
@@ -0,0 +1,16 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+UNIFIED_SOURCES += [
+ 'nsCollationMacUC.cpp',
+ 'nsDateTimeFormatMac.cpp',
+ 'nsMacCharset.cpp',
+]
+
+FINAL_LIBRARY = 'xul'
+LOCAL_INCLUDES += [
+ '..',
+]
diff --git a/intl/locale/mac/nsCollationMacUC.cpp b/intl/locale/mac/nsCollationMacUC.cpp
new file mode 100644
index 000000000..d230f4d77
--- /dev/null
+++ b/intl/locale/mac/nsCollationMacUC.cpp
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsCollationMacUC.h"
+#include "nsILocaleService.h"
+#include "nsIPrefBranch.h"
+#include "nsIPrefService.h"
+#include "nsIServiceManager.h"
+#include "prmem.h"
+#include "nsString.h"
+
+NS_IMPL_ISUPPORTS(nsCollationMacUC, nsICollation)
+
+nsCollationMacUC::nsCollationMacUC()
+ : mInit(false)
+ , mHasCollator(false)
+ , mLocaleICU(nullptr)
+ , mLastStrength(-1)
+ , mCollatorICU(nullptr)
+{ }
+
+nsCollationMacUC::~nsCollationMacUC()
+{
+#ifdef DEBUG
+ nsresult res =
+#endif
+ CleanUpCollator();
+ NS_ASSERTION(NS_SUCCEEDED(res), "CleanUpCollator failed");
+ if (mLocaleICU) {
+ free(mLocaleICU);
+ mLocaleICU = nullptr;
+ }
+}
+
+nsresult nsCollationMacUC::ConvertStrength(const int32_t aNSStrength,
+ UCollationStrength* aICUStrength,
+ UColAttributeValue* aCaseLevelOut)
+{
+ NS_ENSURE_ARG_POINTER(aICUStrength);
+ NS_ENSURE_TRUE((aNSStrength < 4), NS_ERROR_FAILURE);
+
+ UCollationStrength strength = UCOL_DEFAULT;
+ UColAttributeValue caseLevel = UCOL_OFF;
+ switch (aNSStrength) {
+ case kCollationCaseInSensitive:
+ strength = UCOL_PRIMARY;
+ break;
+ case kCollationCaseInsensitiveAscii:
+ strength = UCOL_SECONDARY;
+ break;
+ case kCollationAccentInsenstive:
+ caseLevel = UCOL_ON;
+ strength = UCOL_PRIMARY;
+ break;
+ case kCollationCaseSensitive:
+ strength = UCOL_TERTIARY;
+ break;
+ default:
+ NS_WARNING("Bad aNSStrength passed to ConvertStrength.");
+ return NS_ERROR_FAILURE;
+ }
+
+ *aICUStrength = strength;
+ *aCaseLevelOut = caseLevel;
+
+ return NS_OK;
+}
+
+nsresult nsCollationMacUC::ConvertLocaleICU(nsILocale* aNSLocale, char** aICULocale)
+{
+ NS_ENSURE_ARG_POINTER(aNSLocale);
+ NS_ENSURE_ARG_POINTER(aICULocale);
+
+ nsAutoString localeString;
+ nsresult res = aNSLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"), localeString);
+ NS_ENSURE_TRUE(NS_SUCCEEDED(res) && !localeString.IsEmpty(),
+ NS_ERROR_FAILURE);
+ NS_LossyConvertUTF16toASCII tmp(localeString);
+ tmp.ReplaceChar('-', '_');
+ char* locale = (char*)malloc(tmp.Length() + 1);
+ if (!locale) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ strcpy(locale, tmp.get());
+
+ *aICULocale = locale;
+
+ return NS_OK;
+}
+
+nsresult nsCollationMacUC::EnsureCollator(const int32_t newStrength)
+{
+ NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
+ if (mHasCollator && (mLastStrength == newStrength))
+ return NS_OK;
+
+ nsresult res;
+ res = CleanUpCollator();
+ NS_ENSURE_SUCCESS(res, res);
+
+ NS_ENSURE_TRUE(mLocaleICU, NS_ERROR_NOT_INITIALIZED);
+
+ UErrorCode status;
+ status = U_ZERO_ERROR;
+ mCollatorICU = ucol_open(mLocaleICU, &status);
+ NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
+
+ UCollationStrength strength;
+ UColAttributeValue caseLevel;
+ res = ConvertStrength(newStrength, &strength, &caseLevel);
+ NS_ENSURE_SUCCESS(res, res);
+
+ status = U_ZERO_ERROR;
+ ucol_setAttribute(mCollatorICU, UCOL_STRENGTH, strength, &status);
+ NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
+ ucol_setAttribute(mCollatorICU, UCOL_CASE_LEVEL, caseLevel, &status);
+ NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
+ ucol_setAttribute(mCollatorICU, UCOL_ALTERNATE_HANDLING, UCOL_DEFAULT, &status);
+ NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
+ ucol_setAttribute(mCollatorICU, UCOL_NUMERIC_COLLATION, UCOL_OFF, &status);
+ NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
+ ucol_setAttribute(mCollatorICU, UCOL_NORMALIZATION_MODE, UCOL_ON, &status);
+ NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
+ ucol_setAttribute(mCollatorICU, UCOL_CASE_FIRST, UCOL_DEFAULT, &status);
+ NS_ENSURE_TRUE(U_SUCCESS(status), NS_ERROR_FAILURE);
+
+ mHasCollator = true;
+
+ mLastStrength = newStrength;
+ return NS_OK;
+}
+
+nsresult nsCollationMacUC::CleanUpCollator(void)
+{
+ if (mHasCollator) {
+ ucol_close(mCollatorICU);
+ mHasCollator = false;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsCollationMacUC::Initialize(nsILocale* locale)
+{
+ NS_ENSURE_TRUE((!mInit), NS_ERROR_ALREADY_INITIALIZED);
+ nsCOMPtr<nsILocale> appLocale;
+
+ nsresult rv;
+ if (!locale) {
+ nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
+ NS_ENSURE_SUCCESS(rv, rv);
+ rv = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
+ NS_ENSURE_SUCCESS(rv, rv);
+ locale = appLocale;
+ }
+
+ rv = ConvertLocaleICU(locale, &mLocaleICU);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ mInit = true;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsCollationMacUC::AllocateRawSortKey(int32_t strength, const nsAString& stringIn,
+ uint8_t** key, uint32_t* outLen)
+{
+ NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
+ NS_ENSURE_ARG_POINTER(key);
+ NS_ENSURE_ARG_POINTER(outLen);
+
+ nsresult res = EnsureCollator(strength);
+ NS_ENSURE_SUCCESS(res, res);
+
+ uint32_t stringInLen = stringIn.Length();
+
+ const UChar* str = (const UChar*)stringIn.BeginReading();
+
+ int32_t keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, nullptr, 0);
+ NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
+
+ // Since key is freed elsewhere with PR_Free, allocate with PR_Malloc.
+ uint8_t* newKey = (uint8_t*)PR_Malloc(keyLength + 1);
+ if (!newKey) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ keyLength = ucol_getSortKey(mCollatorICU, str, stringInLen, newKey, keyLength + 1);
+ NS_ENSURE_TRUE((stringInLen == 0 || keyLength > 0), NS_ERROR_FAILURE);
+
+ *key = newKey;
+ *outLen = keyLength;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsCollationMacUC::CompareString(int32_t strength, const nsAString& string1,
+ const nsAString& string2, int32_t* result)
+{
+ NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
+ NS_ENSURE_ARG_POINTER(result);
+ *result = 0;
+
+ nsresult rv = EnsureCollator(strength);
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ UCollationResult uresult;
+ uresult = ucol_strcoll(mCollatorICU,
+ (const UChar*)string1.BeginReading(),
+ string1.Length(),
+ (const UChar*)string2.BeginReading(),
+ string2.Length());
+ int32_t res;
+ switch (uresult) {
+ case UCOL_LESS:
+ res = -1;
+ break;
+ case UCOL_EQUAL:
+ res = 0;
+ break;
+ case UCOL_GREATER:
+ res = 1;
+ break;
+ default:
+ MOZ_CRASH("ucol_strcoll returned bad UCollationResult");
+ }
+ *result = res;
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsCollationMacUC::CompareRawSortKey(const uint8_t* key1, uint32_t len1,
+ const uint8_t* key2, uint32_t len2,
+ int32_t* result)
+{
+ NS_ENSURE_TRUE(mInit, NS_ERROR_NOT_INITIALIZED);
+ NS_ENSURE_ARG_POINTER(key1);
+ NS_ENSURE_ARG_POINTER(key2);
+ NS_ENSURE_ARG_POINTER(result);
+ *result = 0;
+
+ int32_t tmpResult = strcmp((const char*)key1, (const char*)key2);
+ int32_t res;
+ if (tmpResult < 0) {
+ res = -1;
+ } else if (tmpResult > 0) {
+ res = 1;
+ } else {
+ res = 0;
+ }
+ *result = res;
+ return NS_OK;
+}
diff --git a/intl/locale/mac/nsCollationMacUC.h b/intl/locale/mac/nsCollationMacUC.h
new file mode 100644
index 000000000..46bb0145d
--- /dev/null
+++ b/intl/locale/mac/nsCollationMacUC.h
@@ -0,0 +1,44 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef nsCollationMacUC_h_
+#define nsCollationMacUC_h_
+
+#include "nsICollation.h"
+#include "nsCollation.h"
+#include "mozilla/Attributes.h"
+
+#include "unicode/ucol.h"
+
+class nsCollationMacUC final : public nsICollation {
+
+public:
+ nsCollationMacUC();
+
+ // nsISupports interface
+ NS_DECL_ISUPPORTS
+
+ // nsICollation interface
+ NS_DECL_NSICOLLATION
+
+protected:
+ ~nsCollationMacUC();
+
+ nsresult ConvertLocaleICU(nsILocale* aNSLocale, char** aICULocale);
+ nsresult ConvertStrength(const int32_t aStrength,
+ UCollationStrength* aStrengthOut,
+ UColAttributeValue* aCaseLevelOut);
+ nsresult EnsureCollator(const int32_t newStrength);
+ nsresult CleanUpCollator(void);
+
+private:
+ bool mInit;
+ bool mHasCollator;
+ char* mLocaleICU;
+ int32_t mLastStrength;
+ UCollator* mCollatorICU;
+};
+
+#endif /* nsCollationMacUC_h_ */
diff --git a/intl/locale/mac/nsDateTimeFormatMac.cpp b/intl/locale/mac/nsDateTimeFormatMac.cpp
new file mode 100644
index 000000000..6ee73292d
--- /dev/null
+++ b/intl/locale/mac/nsDateTimeFormatMac.cpp
@@ -0,0 +1,266 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include <CoreFoundation/CoreFoundation.h>
+#include "nsIServiceManager.h"
+#include "nsDateTimeFormatMac.h"
+#include <CoreFoundation/CFDateFormatter.h>
+#include "nsIComponentManager.h"
+#include "nsILocaleService.h"
+#include "nsCRT.h"
+#include "plstr.h"
+#include "nsUnicharUtils.h"
+#include "nsTArray.h"
+
+
+NS_IMPL_ISUPPORTS(nsDateTimeFormatMac, nsIDateTimeFormat)
+
+nsresult nsDateTimeFormatMac::Initialize(nsILocale* locale)
+{
+ nsAutoString localeStr;
+ nsAutoString category(NS_LITERAL_STRING("NSILOCALE_TIME"));
+ nsresult res;
+
+ // use cached info if match with stored locale
+ if (nullptr == locale) {
+ if (!mLocale.IsEmpty() &&
+ mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) {
+ return NS_OK;
+ }
+ }
+ else {
+ res = locale->GetCategory(category, localeStr);
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ if (!mLocale.IsEmpty() &&
+ mLocale.Equals(localeStr,
+ nsCaseInsensitiveStringComparator())) {
+ return NS_OK;
+ }
+ }
+ }
+
+ // get application locale
+ nsCOMPtr<nsILocaleService> localeService =
+ do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
+ if (NS_SUCCEEDED(res)) {
+ nsCOMPtr<nsILocale> appLocale;
+ res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
+ if (NS_SUCCEEDED(res)) {
+ res = appLocale->GetCategory(category, localeStr);
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ mAppLocale = localeStr; // cache app locale name
+ }
+ }
+ }
+
+ // use app default if no locale specified
+ if (nullptr == locale) {
+ mUseDefaultLocale = true;
+ }
+ else {
+ mUseDefaultLocale = false;
+ res = locale->GetCategory(category, localeStr);
+ }
+
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ mLocale.Assign(localeStr); // cache locale name
+ }
+
+ return res;
+}
+
+// performs a locale sensitive date formatting operation on the time_t parameter
+nsresult nsDateTimeFormatMac::FormatTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const time_t timetTime,
+ nsAString& stringOut)
+{
+ struct tm tmTime;
+ return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, localtime_r(&timetTime, &tmTime), stringOut);
+}
+
+// performs a locale sensitive date formatting operation on the struct tm parameter
+nsresult nsDateTimeFormatMac::FormatTMTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const struct tm* tmTime,
+ nsAString& stringOut)
+{
+ nsresult res = NS_OK;
+
+ // set up locale data
+ (void) Initialize(locale);
+
+ // return, nothing to format
+ if (dateFormatSelector == kDateFormatNone && timeFormatSelector == kTimeFormatNone) {
+ stringOut.Truncate();
+ return NS_OK;
+ }
+
+ NS_ASSERTION(tmTime->tm_mon >= 0, "tm is not set correctly");
+ NS_ASSERTION(tmTime->tm_mday >= 1, "tm is not set correctly");
+ NS_ASSERTION(tmTime->tm_hour >= 0, "tm is not set correctly");
+ NS_ASSERTION(tmTime->tm_min >= 0, "tm is not set correctly");
+ NS_ASSERTION(tmTime->tm_sec >= 0, "tm is not set correctly");
+ NS_ASSERTION(tmTime->tm_wday >= 0, "tm is not set correctly");
+
+ // Got the locale for the formatter:
+ CFLocaleRef formatterLocale;
+ if (!locale) {
+ formatterLocale = CFLocaleCopyCurrent();
+ } else {
+ CFStringRef localeStr = CFStringCreateWithCharacters(nullptr,
+ reinterpret_cast<const UniChar*>(mLocale.get()),
+ mLocale.Length());
+ formatterLocale = CFLocaleCreate(nullptr, localeStr);
+ CFRelease(localeStr);
+ }
+
+ // Get the date style for the formatter:
+ CFDateFormatterStyle dateStyle;
+ switch (dateFormatSelector) {
+ case kDateFormatLong:
+ dateStyle = kCFDateFormatterLongStyle;
+ break;
+ case kDateFormatShort:
+ dateStyle = kCFDateFormatterShortStyle;
+ break;
+ case kDateFormatYearMonth:
+ case kDateFormatWeekday:
+ dateStyle = kCFDateFormatterNoStyle; // formats handled below
+ break;
+ case kDateFormatNone:
+ dateStyle = kCFDateFormatterNoStyle;
+ break;
+ default:
+ NS_ERROR("Unknown nsDateFormatSelector");
+ res = NS_ERROR_FAILURE;
+ dateStyle = kCFDateFormatterNoStyle;
+ }
+
+ // Get the time style for the formatter:
+ CFDateFormatterStyle timeStyle;
+ switch (timeFormatSelector) {
+ case kTimeFormatSeconds:
+ case kTimeFormatSecondsForce24Hour: // 24 hour part fixed below
+ timeStyle = kCFDateFormatterMediumStyle;
+ break;
+ case kTimeFormatNoSeconds:
+ case kTimeFormatNoSecondsForce24Hour: // 24 hour part fixed below
+ timeStyle = kCFDateFormatterShortStyle;
+ break;
+ case kTimeFormatNone:
+ timeStyle = kCFDateFormatterNoStyle;
+ break;
+ default:
+ NS_ERROR("Unknown nsTimeFormatSelector");
+ res = NS_ERROR_FAILURE;
+ timeStyle = kCFDateFormatterNoStyle;
+ }
+
+ // Create the formatter and fix up its formatting as necessary:
+ CFDateFormatterRef formatter =
+ CFDateFormatterCreate(nullptr, formatterLocale, dateStyle, timeStyle);
+
+ CFRelease(formatterLocale);
+
+ if (dateFormatSelector == kDateFormatYearMonth ||
+ dateFormatSelector == kDateFormatWeekday) {
+ CFStringRef dateFormat =
+ dateFormatSelector == kDateFormatYearMonth ? CFSTR("yyyy/MM ") : CFSTR("EEE ");
+
+ CFStringRef oldFormat = CFDateFormatterGetFormat(formatter);
+ CFMutableStringRef newFormat = CFStringCreateMutableCopy(nullptr, 0, oldFormat);
+ CFStringInsert(newFormat, 0, dateFormat);
+ CFDateFormatterSetFormat(formatter, newFormat);
+ CFRelease(newFormat); // note we don't own oldFormat
+ }
+
+ if (timeFormatSelector == kTimeFormatSecondsForce24Hour ||
+ timeFormatSelector == kTimeFormatNoSecondsForce24Hour) {
+ // Replace "h" with "H", and remove "a":
+ CFStringRef oldFormat = CFDateFormatterGetFormat(formatter);
+ CFMutableStringRef newFormat = CFStringCreateMutableCopy(nullptr, 0, oldFormat);
+ CFIndex replaceCount = CFStringFindAndReplace(newFormat,
+ CFSTR("h"), CFSTR("H"),
+ CFRangeMake(0, CFStringGetLength(newFormat)),
+ 0);
+ NS_ASSERTION(replaceCount <= 2, "Unexpected number of \"h\" occurrences");
+ replaceCount = CFStringFindAndReplace(newFormat,
+ CFSTR("a"), CFSTR(""),
+ CFRangeMake(0, CFStringGetLength(newFormat)),
+ 0);
+ NS_ASSERTION(replaceCount <= 1, "Unexpected number of \"a\" occurrences");
+ CFDateFormatterSetFormat(formatter, newFormat);
+ CFRelease(newFormat); // note we don't own oldFormat
+ }
+
+ // Now get the formatted date:
+ CFGregorianDate date;
+ date.second = tmTime->tm_sec;
+ date.minute = tmTime->tm_min;
+ date.hour = tmTime->tm_hour;
+ date.day = tmTime->tm_mday; // Mac is 1-based, tm is 1-based
+ date.month = tmTime->tm_mon + 1; // Mac is 1-based, tm is 0-based
+ date.year = tmTime->tm_year + 1900;
+
+ CFTimeZoneRef timeZone = CFTimeZoneCopySystem(); // tmTime is in local time
+ CFAbsoluteTime absTime = CFGregorianDateGetAbsoluteTime(date, timeZone);
+ CFRelease(timeZone);
+
+ CFStringRef formattedDate = CFDateFormatterCreateStringWithAbsoluteTime(nullptr,
+ formatter,
+ absTime);
+
+ CFIndex stringLen = CFStringGetLength(formattedDate);
+
+ AutoTArray<UniChar, 256> stringBuffer;
+ stringBuffer.SetLength(stringLen + 1);
+ CFStringGetCharacters(formattedDate, CFRangeMake(0, stringLen), stringBuffer.Elements());
+ stringOut.Assign(reinterpret_cast<char16_t*>(stringBuffer.Elements()), stringLen);
+
+ CFRelease(formattedDate);
+ CFRelease(formatter);
+
+ return res;
+}
+
+// performs a locale sensitive date formatting operation on the PRTime parameter
+nsresult nsDateTimeFormatMac::FormatPRTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRTime prTime,
+ nsAString& stringOut)
+{
+ PRExplodedTime explodedTime;
+ PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime);
+
+ return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut);
+}
+
+// performs a locale sensitive date formatting operation on the PRExplodedTime parameter
+nsresult nsDateTimeFormatMac::FormatPRExplodedTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRExplodedTime* explodedTime,
+ nsAString& stringOut)
+{
+ struct tm tmTime;
+ memset( &tmTime, 0, sizeof(tmTime) );
+
+ tmTime.tm_yday = explodedTime->tm_yday;
+ tmTime.tm_wday = explodedTime->tm_wday;
+ tmTime.tm_year = explodedTime->tm_year;
+ tmTime.tm_year -= 1900;
+ tmTime.tm_mon = explodedTime->tm_month;
+ tmTime.tm_mday = explodedTime->tm_mday;
+ tmTime.tm_hour = explodedTime->tm_hour;
+ tmTime.tm_min = explodedTime->tm_min;
+ tmTime.tm_sec = explodedTime->tm_sec;
+
+ return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
+}
+
diff --git a/intl/locale/mac/nsDateTimeFormatMac.h b/intl/locale/mac/nsDateTimeFormatMac.h
new file mode 100644
index 000000000..dfdf70378
--- /dev/null
+++ b/intl/locale/mac/nsDateTimeFormatMac.h
@@ -0,0 +1,61 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+#ifndef nsDateTimeFormatMac_h__
+#define nsDateTimeFormatMac_h__
+
+
+#include "nsCOMPtr.h"
+#include "nsIDateTimeFormat.h"
+
+
+class nsDateTimeFormatMac : public nsIDateTimeFormat {
+
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ // performs a locale sensitive date formatting operation on the time_t parameter
+ NS_IMETHOD FormatTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const time_t timetTime,
+ nsAString& stringOut) override;
+
+ // performs a locale sensitive date formatting operation on the struct tm parameter
+ NS_IMETHOD FormatTMTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const struct tm* tmTime,
+ nsAString& stringOut) override;
+ // performs a locale sensitive date formatting operation on the PRTime parameter
+ NS_IMETHOD FormatPRTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRTime prTime,
+ nsAString& stringOut) override;
+
+ // performs a locale sensitive date formatting operation on the PRExplodedTime parameter
+ NS_IMETHOD FormatPRExplodedTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRExplodedTime* explodedTime,
+ nsAString& stringOut) override;
+
+ nsDateTimeFormatMac() {}
+
+protected:
+ virtual ~nsDateTimeFormatMac() {}
+
+private:
+ // init this interface to a specified locale
+ NS_IMETHOD Initialize(nsILocale* locale);
+
+ nsString mLocale;
+ nsString mAppLocale;
+ bool mUseDefaultLocale;
+};
+
+#endif /* nsDateTimeFormatMac_h__ */
diff --git a/intl/locale/mac/nsMacCharset.cpp b/intl/locale/mac/nsMacCharset.cpp
new file mode 100644
index 000000000..956560fba
--- /dev/null
+++ b/intl/locale/mac/nsMacCharset.cpp
@@ -0,0 +1,59 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include <Carbon/Carbon.h>
+#include "nsIPlatformCharset.h"
+#include "nsCOMPtr.h"
+#include "nsIServiceManager.h"
+#include "nsReadableUtils.h"
+#include "nsPlatformCharset.h"
+#include "nsEncoderDecoderUtils.h"
+
+NS_IMPL_ISUPPORTS(nsPlatformCharset, nsIPlatformCharset)
+
+nsPlatformCharset::nsPlatformCharset()
+{
+}
+nsPlatformCharset::~nsPlatformCharset()
+{
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::GetCharset(nsPlatformCharsetSel selector, nsACString& oResult)
+{
+ oResult.AssignLiteral("UTF-8");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString &oResult)
+{
+ oResult.AssignLiteral("UTF-8");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::Init()
+{
+ return NS_OK;
+}
+
+nsresult
+nsPlatformCharset::MapToCharset(nsAString& inANSICodePage, nsACString& outCharset)
+{
+ return NS_OK;
+}
+
+nsresult
+nsPlatformCharset::InitGetCharset(nsACString &oString)
+{
+ return NS_OK;
+}
+
+nsresult
+nsPlatformCharset::VerifyCharset(nsCString &aCharset)
+{
+ return NS_OK;
+}
diff --git a/intl/locale/moz.build b/intl/locale/moz.build
new file mode 100644
index 000000000..2da1c2dd5
--- /dev/null
+++ b/intl/locale/moz.build
@@ -0,0 +1,69 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+XPCSHELL_TESTS_MANIFESTS += ['tests/unit/xpcshell.ini']
+
+toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
+
+if toolkit == 'windows':
+ DIRS += ['windows']
+elif toolkit == 'cocoa':
+ DIRS += ['mac']
+else:
+ DIRS += ['unix']
+
+XPIDL_SOURCES += [
+ 'nsICollation.idl',
+ 'nsILocale.idl',
+ 'nsILocaleService.idl',
+ 'nsIScriptableDateFormat.idl',
+]
+
+XPIDL_MODULE = 'locale'
+
+EXPORTS += [
+ 'nsCollation.h',
+ 'nsCollationCID.h',
+ 'nsDateTimeFormatCID.h',
+ 'nsIDateTimeFormat.h',
+ 'nsILanguageAtomService.h',
+ 'nsIPlatformCharset.h',
+ 'nsPosixLocale.h',
+ 'nsUConvPropertySearch.h',
+ 'nsWin32Locale.h',
+]
+
+UNIFIED_SOURCES += [
+ 'nsCollation.cpp',
+ 'nsIDateTimeFormat.cpp',
+ 'nsLanguageAtomService.cpp',
+ 'nsLocale.cpp',
+ 'nsLocaleService.cpp',
+ 'nsScriptableDateFormat.cpp',
+ 'nsUConvPropertySearch.cpp',
+]
+
+EXTRA_JS_MODULES += [
+ 'PluralForm.jsm',
+]
+
+FINAL_LIBRARY = 'xul'
+
+LOCAL_INCLUDES += [
+ '/intl/uconv',
+]
+
+RESOURCE_FILES += [
+ 'langGroups.properties',
+ 'language.properties',
+]
+
+GENERATED_FILES += [
+ 'langGroups.properties.h',
+]
+langgroups = GENERATED_FILES['langGroups.properties.h']
+langgroups.script = 'props2arrays.py'
+langgroups.inputs = ['langGroups.properties']
diff --git a/intl/locale/nsCollation.cpp b/intl/locale/nsCollation.cpp
new file mode 100644
index 000000000..f6fa54471
--- /dev/null
+++ b/intl/locale/nsCollation.cpp
@@ -0,0 +1,134 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsCollation.h"
+#include "nsCollationCID.h"
+#include "nsUnicharUtils.h"
+#include "prmem.h"
+#include "nsIUnicodeEncoder.h"
+#include "nsServiceManagerUtils.h"
+#include "mozilla/dom/EncodingUtils.h"
+
+using mozilla::dom::EncodingUtils;
+
+////////////////////////////////////////////////////////////////////////////////
+
+NS_DEFINE_CID(kCollationCID, NS_COLLATION_CID);
+
+NS_IMPL_ISUPPORTS(nsCollationFactory, nsICollationFactory)
+
+nsresult nsCollationFactory::CreateCollation(nsILocale* locale, nsICollation** instancePtr)
+{
+ // Create a collation interface instance.
+ //
+ nsICollation *inst;
+ nsresult res;
+
+ res = CallCreateInstance(kCollationCID, &inst);
+ if (NS_FAILED(res)) {
+ return res;
+ }
+
+ inst->Initialize(locale);
+ *instancePtr = inst;
+
+ return res;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+nsCollation::nsCollation()
+{
+ MOZ_COUNT_CTOR(nsCollation);
+}
+
+nsCollation::~nsCollation()
+{
+ MOZ_COUNT_DTOR(nsCollation);
+}
+
+nsresult nsCollation::NormalizeString(const nsAString& stringIn, nsAString& stringOut)
+{
+ int32_t aLength = stringIn.Length();
+
+ if (aLength <= 64) {
+ char16_t conversionBuffer[64];
+ ToLowerCase(PromiseFlatString(stringIn).get(), conversionBuffer, aLength);
+ stringOut.Assign(conversionBuffer, aLength);
+ }
+ else {
+ char16_t* conversionBuffer;
+ conversionBuffer = new char16_t[aLength];
+ if (!conversionBuffer) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+ ToLowerCase(PromiseFlatString(stringIn).get(), conversionBuffer, aLength);
+ stringOut.Assign(conversionBuffer, aLength);
+ delete [] conversionBuffer;
+ }
+ return NS_OK;
+}
+
+nsresult nsCollation::SetCharset(const char* aCharset)
+{
+ NS_ENSURE_ARG_POINTER(aCharset);
+
+ nsDependentCString label(aCharset);
+ nsAutoCString encoding;
+ if (!EncodingUtils::FindEncodingForLabelNoReplacement(label, encoding)) {
+ return NS_ERROR_UCONV_NOCONV;
+ }
+ mEncoder = EncodingUtils::EncoderForEncoding(encoding);
+ return NS_OK;
+}
+
+nsresult nsCollation::UnicodeToChar(const nsAString& aSrc, char** dst)
+{
+ NS_ENSURE_ARG_POINTER(dst);
+
+ nsresult res = NS_OK;
+ if (!mEncoder)
+ res = SetCharset("ISO-8859-1");
+
+ if (NS_SUCCEEDED(res)) {
+ const nsPromiseFlatString& src = PromiseFlatString(aSrc);
+ const char16_t *unichars = src.get();
+ int32_t unicharLength = src.Length();
+ int32_t dstLength;
+ res = mEncoder->GetMaxLength(unichars, unicharLength, &dstLength);
+ if (NS_SUCCEEDED(res)) {
+ int32_t bufLength = dstLength + 1 + 32; // extra 32 bytes for Finish() call
+ *dst = (char *) PR_Malloc(bufLength);
+ if (*dst) {
+ **dst = '\0';
+ res = mEncoder->Convert(unichars, &unicharLength, *dst, &dstLength);
+
+ if (NS_SUCCEEDED(res) || (NS_ERROR_UENC_NOMAPPING == res)) {
+ // Finishes the conversion. The converter has the possibility to write some
+ // extra data and flush its final state.
+ int32_t finishLength = bufLength - dstLength; // remaining unused buffer length
+ if (finishLength > 0) {
+ res = mEncoder->Finish((*dst + dstLength), &finishLength);
+ if (NS_SUCCEEDED(res)) {
+ (*dst)[dstLength + finishLength] = '\0';
+ }
+ }
+ }
+ if (NS_FAILED(res)) {
+ PR_Free(*dst);
+ *dst = nullptr;
+ }
+ }
+ else {
+ res = NS_ERROR_OUT_OF_MEMORY;
+ }
+ }
+ }
+
+ return res;
+}
+
+
+
diff --git a/intl/locale/nsCollation.h b/intl/locale/nsCollation.h
new file mode 100644
index 000000000..4d9366822
--- /dev/null
+++ b/intl/locale/nsCollation.h
@@ -0,0 +1,51 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+#ifndef nsCollation_h__
+#define nsCollation_h__
+
+
+#include "nsICollation.h"
+#include "nsCOMPtr.h"
+#include "mozilla/Attributes.h"
+
+class nsIUnicodeEncoder;
+
+// Create a collation interface for an input locale.
+//
+class nsCollationFactory final : public nsICollationFactory {
+
+ ~nsCollationFactory() {}
+
+public:
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD CreateCollation(nsILocale* locale, nsICollation** instancePtr) override;
+
+ nsCollationFactory() {}
+};
+
+
+struct nsCollation {
+
+public:
+
+ nsCollation();
+
+ ~nsCollation();
+
+ // normalize string before collation key generation
+ nsresult NormalizeString(const nsAString& stringIn, nsAString& stringOut);
+
+ // charset conversion util, C string buffer is allocate by PR_Malloc, caller should call PR_Free
+ nsresult SetCharset(const char* aCharset);
+ nsresult UnicodeToChar(const nsAString& aSrc, char** dst);
+
+protected:
+ nsCOMPtr <nsIUnicodeEncoder> mEncoder;
+};
+
+#endif /* nsCollation_h__ */
diff --git a/intl/locale/nsCollationCID.h b/intl/locale/nsCollationCID.h
new file mode 100644
index 000000000..d71db3387
--- /dev/null
+++ b/intl/locale/nsCollationCID.h
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+#ifndef nsCollationCID_h__
+#define nsCollationCID_h__
+
+
+#include "nscore.h"
+#include "nsISupports.h"
+
+// {AA13E4A0-A5AC-11d2-9119-006008A6EDF6}
+#define NS_COLLATION_CID \
+{ 0xaa13e4a0, 0xa5ac, 0x11d2, \
+{ 0x91, 0x19, 0x0, 0x60, 0x8, 0xa6, 0xed, 0xf6 } }
+
+#define NS_COLLATION_CONTRACTID "@mozilla.org/intl/collation;1"
+
+// {A1B72850-A999-11d2-9119-006008A6EDF6}
+#define NS_COLLATIONFACTORY_CID \
+{ 0xa1b72850, 0xa999, 0x11d2, \
+{ 0x91, 0x19, 0x0, 0x60, 0x8, 0xa6, 0xed, 0xf6 } }
+
+#define NS_COLLATIONFACTORY_CONTRACTID "@mozilla.org/intl/collation-factory;1"
+
+#endif // nsCollationCID_h__
+
diff --git a/intl/locale/nsDateTimeFormatCID.h b/intl/locale/nsDateTimeFormatCID.h
new file mode 100644
index 000000000..31115bc4d
--- /dev/null
+++ b/intl/locale/nsDateTimeFormatCID.h
@@ -0,0 +1,20 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+#ifndef nsDateTimeFormatCID_h__
+#define nsDateTimeFormatCID_h__
+
+
+#include "nscore.h"
+#include "nsISupports.h"
+
+#define NS_DATETIMEFORMAT_CONTRACTID "@mozilla.org/intl/datetimeformat;1"
+
+// {0704E7C0-A758-11d2-9119-006008A6EDF6}
+#define NS_DATETIMEFORMAT_CID \
+{ 0x704e7c0, 0xa758, 0x11d2, \
+{ 0x91, 0x19, 0x0, 0x60, 0x8, 0xa6, 0xed, 0xf6 } }
+
+#endif // nsDateTimeFormatCID_h__
+
diff --git a/intl/locale/nsICollation.idl b/intl/locale/nsICollation.idl
new file mode 100644
index 000000000..bbcfb395b
--- /dev/null
+++ b/intl/locale/nsICollation.idl
@@ -0,0 +1,64 @@
+/* -*- Mode: idl; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsILocale.idl"
+
+interface nsICollation;
+
+[scriptable, uuid(04971e14-d6b3-4ada-8cbb-c3a13842b349)]
+interface nsICollationFactory : nsISupports
+{
+ /**
+ * Create the collation for a given locale.
+ *
+ * Use NULL as the locale parameter to use the user's locale preference
+ * from the operating system.
+ *
+ * @param locale
+ * The locale for which to create the collation or null to use
+ * user preference.
+ * @return A collation for the given locale.
+ */
+ nsICollation CreateCollation(in nsILocale locale);
+};
+
+[scriptable, uuid(b0132cc0-3786-4557-9874-910d7def5f93)]
+interface nsICollation : nsISupports {
+
+ // use the primary comparison for the given locale - no flags
+ const long kCollationStrengthDefault = 0;
+
+ // do not consider case differences when doing the comparison i.e. A=a)
+ const long kCollationCaseInsensitiveAscii = 1;
+
+ // do not consider accent differences when doing the comparison a=á)
+ const long kCollationAccentInsenstive = 2;
+
+ // case sensitive collation (default)
+ const long kCollationCaseSensitive = kCollationStrengthDefault;
+
+ // case insensitive collation
+ const long kCollationCaseInSensitive = (kCollationCaseInsensitiveAscii | kCollationAccentInsenstive);
+
+ // init this interface to a specified locale (should only be called by collation factory)
+ void initialize(in nsILocale locale);
+
+ // compare two strings
+ // result is same as strcmp
+ long compareString(in long strength, in AString string1, in AString string2);
+
+ // allocate sort key from input string
+ // returns newly allocated key, and its band its byte length
+ [noscript] void allocateRawSortKey(in long strength,
+ in AString stringIn,
+ [array,size_is(outLen)] out octet key,
+ out unsigned long outLen);
+
+ // compare two sort keys
+ // length is a byte length, result is same as strcmp
+ [noscript] long compareRawSortKey([const,array,size_is(len1)] in octet key1, in unsigned long len1,
+ [const,array,size_is(len2)] in octet key2, in unsigned long len2);
+
+};
diff --git a/intl/locale/nsIDateTimeFormat.cpp b/intl/locale/nsIDateTimeFormat.cpp
new file mode 100644
index 000000000..263b3abb4
--- /dev/null
+++ b/intl/locale/nsIDateTimeFormat.cpp
@@ -0,0 +1,39 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsIDateTimeFormat.h"
+#include "mozilla/RefPtr.h"
+
+#if defined(XP_MACOSX)
+#define USE_MAC_LOCALE
+#elif defined(XP_UNIX)
+#define USE_UNIX_LOCALE
+#endif
+
+#ifdef XP_WIN
+#include "windows/nsDateTimeFormatWin.h"
+#endif
+#ifdef USE_UNIX_LOCALE
+#include "unix/nsDateTimeFormatUnix.h"
+#endif
+#ifdef USE_MAC_LOCALE
+#include "mac/nsDateTimeFormatMac.h"
+#endif
+
+using mozilla::MakeAndAddRef;
+
+/*static*/ already_AddRefed<nsIDateTimeFormat>
+nsIDateTimeFormat::Create()
+{
+#ifdef XP_WIN
+ return MakeAndAddRef<nsDateTimeFormatWin>();
+#elif defined(USE_UNIX_LOCALE)
+ return MakeAndAddRef<nsDateTimeFormatUnix>();
+#elif defined(USE_MAC_LOCALE)
+ return MakeAndAddRef<nsDateTimeFormatMac>();
+#else
+ return nullptr;
+#endif
+}
diff --git a/intl/locale/nsIDateTimeFormat.h b/intl/locale/nsIDateTimeFormat.h
new file mode 100644
index 000000000..37ee9de46
--- /dev/null
+++ b/intl/locale/nsIDateTimeFormat.h
@@ -0,0 +1,69 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+#ifndef nsIDateTimeFormat_h__
+#define nsIDateTimeFormat_h__
+
+
+#include "nsISupports.h"
+#include "nscore.h"
+#include "nsStringGlue.h"
+#include "nsILocale.h"
+#include "nsIScriptableDateFormat.h"
+#include "prtime.h"
+#include <time.h>
+
+
+// {2BBAA0B0-A591-11d2-9119-006008A6EDF6}
+#define NS_IDATETIMEFORMAT_IID \
+{ 0x2bbaa0b0, 0xa591, 0x11d2, \
+{ 0x91, 0x19, 0x0, 0x60, 0x8, 0xa6, 0xed, 0xf6 } }
+
+
+// Locale sensitive date and time format interface
+//
+class nsIDateTimeFormat : public nsISupports {
+protected:
+ nsIDateTimeFormat() {}
+ virtual ~nsIDateTimeFormat() {}
+
+public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IDATETIMEFORMAT_IID)
+
+ static already_AddRefed<nsIDateTimeFormat> Create();
+
+ // performs a locale sensitive date formatting operation on the time_t parameter
+ NS_IMETHOD FormatTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const time_t timetTime,
+ nsAString& stringOut) = 0;
+
+ // performs a locale sensitive date formatting operation on the struct tm parameter
+ NS_IMETHOD FormatTMTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const struct tm* tmTime,
+ nsAString& stringOut) = 0;
+
+ // performs a locale sensitive date formatting operation on the PRTime parameter
+ NS_IMETHOD FormatPRTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRTime prTime,
+ nsAString& stringOut) = 0;
+
+ // performs a locale sensitive date formatting operation on the PRExplodedTime parameter
+ NS_IMETHOD FormatPRExplodedTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRExplodedTime* explodedTime,
+ nsAString& stringOut) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIDateTimeFormat, NS_IDATETIMEFORMAT_IID)
+
+#endif /* nsIDateTimeFormat_h__ */
diff --git a/intl/locale/nsILanguageAtomService.h b/intl/locale/nsILanguageAtomService.h
new file mode 100644
index 000000000..656102ffe
--- /dev/null
+++ b/intl/locale/nsILanguageAtomService.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+
+#ifndef nsILanguageAtomService_h_
+#define nsILanguageAtomService_h_
+
+/*
+ * The nsILanguageAtomService provides a mapping from languages or charsets
+ * to language groups, and access to the system locale language.
+ */
+
+#include "nsISupports.h"
+#include "nsCOMPtr.h"
+#include "nsIAtom.h"
+
+#define NS_ILANGUAGEATOMSERVICE_IID \
+ {0xcb3892a0, 0x6a76, 0x461c, \
+ { 0xb0, 0x24, 0x23, 0x0e, 0xe3, 0xe0, 0x81, 0x1a }}
+
+#define NS_LANGUAGEATOMSERVICE_CONTRACTID \
+ "@mozilla.org/intl/nslanguageatomservice;1"
+
+class nsILanguageAtomService : public nsISupports
+{
+ public:
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_ILANGUAGEATOMSERVICE_IID)
+
+ virtual nsIAtom* LookupLanguage(const nsACString &aLanguage,
+ nsresult *aError = nullptr) = 0;
+ virtual already_AddRefed<nsIAtom>
+ LookupCharSet(const nsACString& aCharSet) = 0;
+
+ virtual nsIAtom* GetLocaleLanguage(nsresult *aError = nullptr) = 0;
+
+ virtual nsIAtom* GetLanguageGroup(nsIAtom *aLanguage,
+ nsresult *aError = nullptr) = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsILanguageAtomService,
+ NS_ILANGUAGEATOMSERVICE_IID)
+
+#endif
diff --git a/intl/locale/nsILocale.idl b/intl/locale/nsILocale.idl
new file mode 100644
index 000000000..e0449d777
--- /dev/null
+++ b/intl/locale/nsILocale.idl
@@ -0,0 +1,47 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+
+%{C++
+#define NSILOCALE_COLLATE "NSILOCALE_COLLATE"
+#define NSILOCALE_CTYPE "NSILOCALE_CTYPE"
+#define NSILOCALE_MONETARY "NSILOCALE_MONETARY"
+#define NSILOCALE_NUMERIC "NSILOCALE_NUMERIC"
+#define NSILOCALE_TIME "NSILOCALE_TIME"
+#define NSILOCALE_MESSAGE "NSILOCALE_MESSAGES"
+
+#define NS_LOCALE_CONTRACTID "@mozilla.org/intl/nslocale;1"
+%}
+
+/**
+ * Represents one locale, which can be used for things like sorting text strings
+ * and formatting numbers, dates and times.
+ */
+[scriptable, uuid(21035ee0-4556-11d3-91cd-00105aa3f7dc)]
+interface nsILocale : nsISupports
+{
+ /**
+ * Get the locale code for a given category.
+ *
+ * A locale code is of the form language[-COUNTRY[-region]], where
+ * "language" is an ISO 639 language code (two letter codes preferred over
+ * three letter codes when available), "COUNTRY" is an ISO 3166 two letter
+ * country code, and "region" is a string of up to 5 letters.
+ *
+ * A category is one of the following:
+ * NSILOCALE_CTYPE: Character classification and case conversion.
+ * NSILOCALE_COLLATE: Collation order. How strings are sorted.
+ * NSILOCALE_MONETARY: Monetary formatting.
+ * NSILOCALE_NUMERIC: Numeric, non-monetary formatting.
+ * NSILOCALE_TIME: Date and time formats.
+ * NSILOCALE_MESSAGES: Related to fonts, character encodings etc.
+ *
+ * @param category
+ * The category of interest.
+ * @return The locale code to be used for the given category.
+ */
+ AString getCategory(in AString category);
+};
diff --git a/intl/locale/nsILocaleService.idl b/intl/locale/nsILocaleService.idl
new file mode 100644
index 000000000..477470a86
--- /dev/null
+++ b/intl/locale/nsILocaleService.idl
@@ -0,0 +1,77 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+#include "nsILocale.idl"
+
+/**
+ * The Locale service interface. This is a singleton object, and should be
+ * obtained from the <tt>nsServiceManager</tt>.
+ */
+[scriptable, uuid(c2edc848-4219-4440-abbf-98119882c83f)]
+interface nsILocaleService : nsISupports
+{
+ /**
+ * Create a new nsILocale from a locale string.
+ *
+ * @param aLocale
+ * A locale code as described in nsILocale.
+ * @return A nsILocale representing the given locale.
+ */
+ nsILocale newLocale(in AString aLocale);
+
+ /**
+ * Get the user preference for locale from the operating system.
+ *
+ * @return User's OS setting for preferred locale.
+ */
+ nsILocale getSystemLocale();
+
+ /**
+ * Get the user preference for locale from the operating system.
+ *
+ * NOTE: This has nothing to do with the locale used for localization of
+ * the application (UI text strings etc.). This method returns something
+ * similar to getSystemLocale.
+ *
+ * @return User's OS setting for preferred locale.
+ */
+ nsILocale getApplicationLocale();
+
+ /**
+ * Get the most preferred locale from a list of locale preferences.
+ *
+ * @param acceptLanguage
+ * Locale preference in the same format as the Accept-Language HTTP
+ * header.
+ * @return The most preferred locale according to the acceptLanguage
+ * parameter.
+ */
+ nsILocale getLocaleFromAcceptLanguage(in string acceptLanguage);
+
+ /**
+ * Get the user preference for locale from the operating system.
+ *
+ * NOTE: This has nothing to do with any HTTP User-Agent. This method
+ * returns the same as getSystemLocale, but as a string.
+ *
+ * @return User's OS setting for preferred locale in the format described
+ * in nsILocale.
+ */
+ AString getLocaleComponentForUserAgent();
+};
+
+%{C++
+
+// {C8E518C1-47AE-11d3-91CD-00105AA3F7DC}
+#define NS_LOCALESERVICE_CID {0xc8e518c1,0x47ae,0x11d3,{0x91,0xcd,0x0,0x10,0x5a,0xa3,0xf7,0xdc}}
+#define NS_LOCALESERVICE_CONTRACTID "@mozilla.org/intl/nslocaleservice;1"
+
+extern nsresult
+NS_NewLocaleService(nsILocaleService** result);
+
+%}
+
+
diff --git a/intl/locale/nsIPlatformCharset.h b/intl/locale/nsIPlatformCharset.h
new file mode 100644
index 000000000..1cc889bb6
--- /dev/null
+++ b/intl/locale/nsIPlatformCharset.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef nsIPlatformCharset_h__
+#define nsIPlatformCharset_h__
+
+#include "nsStringGlue.h"
+#include "nsISupports.h"
+
+// Interface ID for our nsIPlatformCharset interface
+
+/* 778859d5-fc01-4f4b-bfaa-3c0d1b6c81d6 */
+#define NS_IPLATFORMCHARSET_IID \
+{ 0x778859d5, \
+ 0xfc01, \
+ 0x4f4b, \
+ {0xbf, 0xaa, 0x3c, 0x0d, 0x1b, 0x6c, 0x81, 0xd6} }
+
+#define NS_PLATFORMCHARSET_CID \
+{ 0x84b0f182, 0xc6c7, 0x11d2, {0xb3, 0xb0, 0x0, 0x80, 0x5f, 0x8a, 0x66, 0x70 }}
+
+#define NS_PLATFORMCHARSET_CONTRACTID "@mozilla.org/intl/platformcharset;1"
+
+typedef enum {
+ kPlatformCharsetSel_PlainTextInClipboard = 0,
+ kPlatformCharsetSel_FileName = 1,
+ kPlatformCharsetSel_Menu = 2,
+ kPlatformCharsetSel_4xBookmarkFile = 3,
+ kPlatformCharsetSel_KeyboardInput = 4,
+ kPlatformCharsetSel_WindowManager = 5,
+ kPlatformCharsetSel_4xPrefsJS = 6,
+ kPlatformCharsetSel_PlainTextInFile = 7
+} nsPlatformCharsetSel;
+
+/**
+ * DO NOT ADD NEW USES OF THIS INTERFACE!
+ * Removal is https://bugzilla.mozilla.org/show_bug.cgi?id=943272
+ *
+ * Instead, use UTF-16 APIs on Windows and UTF-8 APIs everywhere else.
+ * Assume plain text files are UTF-8.
+ */
+class nsIPlatformCharset : public nsISupports
+{
+public:
+
+ NS_DECLARE_STATIC_IID_ACCESSOR(NS_IPLATFORMCHARSET_IID)
+
+ NS_IMETHOD GetCharset(nsPlatformCharsetSel selector, nsACString& oResult) = 0;
+
+ NS_IMETHOD GetDefaultCharsetForLocale(const nsAString& localeName, nsACString& oResult) = 0;
+
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIPlatformCharset, NS_IPLATFORMCHARSET_IID)
+
+#endif /* nsIPlatformCharset_h__ */
diff --git a/intl/locale/nsIScriptableDateFormat.idl b/intl/locale/nsIScriptableDateFormat.idl
new file mode 100644
index 000000000..04dcbe333
--- /dev/null
+++ b/intl/locale/nsIScriptableDateFormat.idl
@@ -0,0 +1,179 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+#include "nsISupports.idl"
+
+typedef long nsDateFormatSelector;
+%{ C++
+enum
+{
+ kDateFormatNone = 0, // do not include the date in the format string
+ kDateFormatLong, // provides the long date format for the given locale
+ kDateFormatShort, // provides the short date format for the given locale
+ kDateFormatYearMonth, // formats using only the year and month
+ kDateFormatWeekday // week day (e.g. Mon, Tue)
+};
+%}
+
+typedef long nsTimeFormatSelector;
+%{ C++
+enum
+{
+ kTimeFormatNone = 0, // don't include the time in the format string
+ kTimeFormatSeconds, // provides the time format with seconds in the given locale
+ kTimeFormatNoSeconds, // provides the time format without seconds in the given locale
+ kTimeFormatSecondsForce24Hour, // forces the time format to use the 24 clock, regardless of the locale conventions
+ kTimeFormatNoSecondsForce24Hour // forces the time format to use the 24 clock, regardless of the locale conventions
+};
+%}
+
+%{C++
+// Define Contractid and CID
+// {2EA2E7D0-4095-11d3-9144-006008A6EDF6}
+#define NS_SCRIPTABLEDATEFORMAT_CID \
+{ 0x2ea2e7d0, 0x4095, 0x11d3, { 0x91, 0x44, 0x0, 0x60, 0x8, 0xa6, 0xed, 0xf6 } }
+
+#define NS_SCRIPTABLEDATEFORMAT_CONTRACTID "@mozilla.org/intl/scriptabledateformat;1"
+
+extern nsresult
+NS_NewScriptableDateFormat(nsISupports* aOuter, REFNSIID aIID, void** aResult);
+%}
+
+/**
+ * Format date and time in a human readable format.
+ */
+[scriptable, uuid(0c89efb0-1aae-11d3-9141-006008a6edf6)]
+interface nsIScriptableDateFormat : nsISupports
+{
+ /**
+ * Do not include the date in the format string.
+ */
+ const long dateFormatNone = 0;
+
+ /**
+ * Provide the long date format.
+ *
+ * NOTE:
+ * The original definitions of dateFormatLong and dateFormatShort are from
+ * the Windows platform.
+ * In US English dateFormatLong output will be like:
+ * Wednesday, January 29, 2003 4:02:14 PM
+ * In US English dateFormatShort output will be like:
+ * 1/29/03 4:02:14 PM
+ * On platforms like Linux, it is rather difficult to achieve exact
+ * same output, and since we are aiming at human readers, it does not make
+ * sense to achieve exact same result. We will do just enough as the
+ * platform allow us to do.
+ */
+ const long dateFormatLong = 1;
+
+ /**
+ * Provide the short date format. See also dateFormatLong.
+ */
+ const long dateFormatShort = 2;
+
+ /**
+ * Format using only the year and month.
+ */
+ const long dateFormatYearMonth = 3;
+
+ /**
+ * Provide the Week day (e.g. Mo, Mon, Monday or similar).
+ */
+ const long dateFormatWeekday = 4;
+
+ /**
+ * Don't include the time in the format string.
+ */
+ const long timeFormatNone = 0;
+
+ /**
+ * Provide the time format with seconds.
+ */
+ const long timeFormatSeconds = 1;
+
+ /**
+ * Provide the time format without seconds.
+ */
+ const long timeFormatNoSeconds = 2;
+
+ /**
+ * Provide the time format with seconds, and force the time format to use
+ * 24-hour clock, regardless of the locale conventions.
+ */
+ const long timeFormatSecondsForce24Hour = 3;
+
+ /**
+ * Provide the time format without seconds, and force the time format to use
+ * 24-hour clock, regardless of the locale conventions.
+ */
+ const long timeFormatNoSecondsForce24Hour = 4;
+
+ /**
+ * Format the given date and time in a human readable format.
+ *
+ * The underlying operating system is used to format the date and time.
+ *
+ * Pass an empty string as the locale parameter to use the OS settings with
+ * the preferred date and time formatting given by the user.
+ *
+ * Pass a locale code as described in nsILocale as the locale parameter
+ * (e.g. en-US) to use a specific locale. If the given locale is not
+ * available, a fallback will be used.
+ *
+ * NOTE: The output of this method depends on the operating system and user
+ * settings. Even if you pass a locale code as the first parameter, there
+ * are no guarantees about which locale and exact format the returned value
+ * uses. Even if you know the locale, the format might be customized by the
+ * user. Therefore you should not use the returned values in contexts where
+ * you depend on any specific format or language.
+ *
+ * @param locale
+ * Locale code of locale used to format the date or an empty string
+ * to follow user preference.
+ * @param dateFormatSelector
+ * Indicate which format should preferably be used for the date.
+ * Use one of the dateFormat* constants.
+ * @param timeFormatSelector
+ * Indicate which format should preferably be used for the time.
+ * Use one of the timeFormat* constants.
+ * @param year, month, day, hour, minute and second
+ * The date and time to be formatted, given in the computer's local
+ * time zone.
+ * @return The date and time formatted as human readable text according to
+ * user preferences or the given locale.
+ */
+ wstring FormatDateTime(in wstring locale,
+ in long dateFormatSelector,
+ in long timeFormatSelector,
+ in long year,
+ in long month,
+ in long day,
+ in long hour,
+ in long minute,
+ in long second);
+
+ /**
+ * Format the given date in a human readable format.
+ *
+ * See FormatDateTime for details.
+ */
+ wstring FormatDate(in wstring locale,
+ in long dateFormatSelector,
+ in long year,
+ in long month,
+ in long day);
+
+ /**
+ * Format the given time in a human readable format.
+ *
+ * See FormatDateTime for details.
+ */
+ wstring FormatTime(in wstring locale,
+ in long timeFormatSelector,
+ in long hour,
+ in long minute,
+ in long second);
+};
diff --git a/intl/locale/nsLanguageAtomService.cpp b/intl/locale/nsLanguageAtomService.cpp
new file mode 100644
index 000000000..9002a03f7
--- /dev/null
+++ b/intl/locale/nsLanguageAtomService.cpp
@@ -0,0 +1,123 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsLanguageAtomService.h"
+#include "nsILocaleService.h"
+#include "nsUConvPropertySearch.h"
+#include "nsUnicharUtils.h"
+#include "nsIAtom.h"
+#include "mozilla/ArrayUtils.h"
+#include "mozilla/Services.h"
+#include "nsServiceManagerUtils.h"
+#include "mozilla/dom/EncodingUtils.h"
+
+using namespace mozilla;
+
+static const nsUConvProp kLangGroups[] = {
+#include "langGroups.properties.h"
+};
+
+NS_IMPL_ISUPPORTS(nsLanguageAtomService, nsILanguageAtomService)
+
+nsLanguageAtomService::nsLanguageAtomService()
+{
+}
+
+nsIAtom*
+nsLanguageAtomService::LookupLanguage(const nsACString &aLanguage,
+ nsresult *aError)
+{
+ nsAutoCString lowered(aLanguage);
+ ToLowerCase(lowered);
+
+ nsCOMPtr<nsIAtom> lang = NS_Atomize(lowered);
+ return GetLanguageGroup(lang, aError);
+}
+
+already_AddRefed<nsIAtom>
+nsLanguageAtomService::LookupCharSet(const nsACString& aCharSet)
+{
+ nsAutoCString group;
+ mozilla::dom::EncodingUtils::LangGroupForEncoding(aCharSet, group);
+ return NS_Atomize(group);
+}
+
+nsIAtom*
+nsLanguageAtomService::GetLocaleLanguage(nsresult *aError)
+{
+ nsresult res = NS_OK;
+
+ do {
+ if (!mLocaleLanguage) {
+ nsCOMPtr<nsILocaleService> localeService;
+ localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID);
+ if (!localeService) {
+ res = NS_ERROR_FAILURE;
+ break;
+ }
+
+ nsCOMPtr<nsILocale> locale;
+ res = localeService->GetApplicationLocale(getter_AddRefs(locale));
+ if (NS_FAILED(res))
+ break;
+
+ nsAutoString loc;
+ res = locale->GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), loc);
+ if (NS_FAILED(res))
+ break;
+
+ ToLowerCase(loc); // use lowercase for all language atoms
+ mLocaleLanguage = NS_Atomize(loc);
+ }
+ } while (0);
+
+ if (aError)
+ *aError = res;
+
+ return mLocaleLanguage;
+}
+
+nsIAtom*
+nsLanguageAtomService::GetLanguageGroup(nsIAtom *aLanguage,
+ nsresult *aError)
+{
+ nsIAtom *retVal;
+ nsresult res = NS_OK;
+
+ retVal = mLangToGroup.GetWeak(aLanguage);
+
+ if (!retVal) {
+ nsAutoCString langStr;
+ aLanguage->ToUTF8String(langStr);
+
+ nsAutoCString langGroupStr;
+ res = nsUConvPropertySearch::SearchPropertyValue(kLangGroups,
+ ArrayLength(kLangGroups),
+ langStr, langGroupStr);
+ while (NS_FAILED(res)) {
+ int32_t hyphen = langStr.RFindChar('-');
+ if (hyphen <= 0) {
+ langGroupStr.AssignLiteral("x-unicode");
+ break;
+ }
+ langStr.Truncate(hyphen);
+ res = nsUConvPropertySearch::SearchPropertyValue(kLangGroups,
+ ArrayLength(kLangGroups),
+ langStr, langGroupStr);
+ }
+
+ nsCOMPtr<nsIAtom> langGroup = NS_Atomize(langGroupStr);
+
+ // The hashtable will keep an owning reference to the atom
+ mLangToGroup.Put(aLanguage, langGroup);
+ retVal = langGroup.get();
+ }
+
+ if (aError) {
+ *aError = res;
+ }
+
+ return retVal;
+}
diff --git a/intl/locale/nsLanguageAtomService.h b/intl/locale/nsLanguageAtomService.h
new file mode 100644
index 000000000..83f6e7096
--- /dev/null
+++ b/intl/locale/nsLanguageAtomService.h
@@ -0,0 +1,42 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsCOMPtr.h"
+#include "nsILanguageAtomService.h"
+#include "nsIStringBundle.h"
+#include "nsInterfaceHashtable.h"
+#include "nsIAtom.h"
+#include "nsUConvPropertySearch.h"
+#include "mozilla/Attributes.h"
+
+#define NS_LANGUAGEATOMSERVICE_CID \
+ {0xB7C65853, 0x2996, 0x435E, {0x96, 0x54, 0xDC, 0xC1, 0x78, 0xAA, 0xB4, 0x8C}}
+
+class nsLanguageAtomService final : public nsILanguageAtomService
+{
+public:
+ NS_DECL_ISUPPORTS
+
+ // nsILanguageAtomService
+ virtual nsIAtom*
+ LookupLanguage(const nsACString &aLanguage, nsresult *aError) override;
+
+ virtual already_AddRefed<nsIAtom>
+ LookupCharSet(const nsACString& aCharSet) override;
+
+ virtual nsIAtom* GetLocaleLanguage(nsresult *aError) override;
+
+ virtual nsIAtom* GetLanguageGroup(nsIAtom *aLanguage,
+ nsresult *aError) override;
+
+ nsLanguageAtomService();
+
+private:
+ ~nsLanguageAtomService() { }
+
+protected:
+ nsInterfaceHashtable<nsISupportsHashKey, nsIAtom> mLangToGroup;
+ nsCOMPtr<nsIAtom> mLocaleLanguage;
+};
diff --git a/intl/locale/nsLocale.cpp b/intl/locale/nsLocale.cpp
new file mode 100644
index 000000000..5cf901866
--- /dev/null
+++ b/intl/locale/nsLocale.cpp
@@ -0,0 +1,108 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsString.h"
+#include "nsISupports.h"
+#include "nsILocale.h"
+#include "nsLocale.h"
+#include "nsMemory.h"
+#include "nsCRT.h"
+
+#define LOCALE_HASH_SIZE 0xFF
+
+
+/* nsILocale */
+NS_IMPL_ISUPPORTS(nsLocale, nsILocale)
+
+nsLocale::nsLocale(void)
+: fHashtable(nullptr), fCategoryCount(0)
+{
+ fHashtable = PL_NewHashTable(LOCALE_HASH_SIZE,&nsLocale::Hash_HashFunction,
+ &nsLocale::Hash_CompareNSString,
+ &nsLocale::Hash_CompareNSString,
+ nullptr, nullptr);
+ NS_ASSERTION(fHashtable, "nsLocale: failed to allocate PR_Hashtable");
+}
+
+nsLocale::~nsLocale(void)
+{
+ // enumerate all the entries with a delete function to
+ // safely delete all the keys and values
+ PL_HashTableEnumerateEntries(fHashtable, &nsLocale::Hash_EnumerateDelete,
+ nullptr);
+
+ PL_HashTableDestroy(fHashtable);
+}
+
+NS_IMETHODIMP
+nsLocale::GetCategory(const nsAString& category, nsAString& result)
+{
+ const char16_t *value = (const char16_t*)
+ PL_HashTableLookup(fHashtable, PromiseFlatString(category).get());
+
+ if (value)
+ {
+ result.Assign(value);
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsLocale::AddCategory(const nsAString &category, const nsAString &value)
+{
+ char16_t* newKey = ToNewUnicode(category);
+ if (!newKey)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ char16_t* newValue = ToNewUnicode(value);
+ if (!newValue) {
+ free(newKey);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ if (!PL_HashTableAdd(fHashtable, newKey, newValue)) {
+ free(newKey);
+ free(newValue);
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ return NS_OK;
+}
+
+
+PLHashNumber
+nsLocale::Hash_HashFunction(const void* key)
+{
+ const char16_t* ptr = (const char16_t *) key;
+ PLHashNumber hash;
+
+ hash = (PLHashNumber)0;
+
+ while (*ptr)
+ hash += (PLHashNumber) *ptr++;
+
+ return hash;
+}
+
+
+int
+nsLocale::Hash_CompareNSString(const void* s1, const void* s2)
+{
+ return !nsCRT::strcmp((const char16_t *) s1, (const char16_t *) s2);
+}
+
+
+int
+nsLocale::Hash_EnumerateDelete(PLHashEntry *he, int hashIndex, void *arg)
+{
+ // delete an entry
+ free((char16_t *)he->key);
+ free((char16_t *)he->value);
+
+ return (HT_ENUMERATE_NEXT | HT_ENUMERATE_REMOVE);
+}
+
diff --git a/intl/locale/nsLocale.h b/intl/locale/nsLocale.h
new file mode 100644
index 000000000..168f0614a
--- /dev/null
+++ b/intl/locale/nsLocale.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/.
+ *
+ *
+ * This Original Code has been modified by IBM Corporation.
+ * Modifications made by IBM described herein are
+ * Copyright (c) International Business Machines
+ * Corporation, 2000
+ *
+ * Modifications to Mozilla code or documentation
+ * identified per MPL Section 3.3
+ *
+ * Date Modified by Description of modification
+ * 03/27/2000 IBM Corp. Added PR_CALLBACK for Optlink
+ * use in OS2
+ */
+#ifndef nsLocale_h__
+#define nsLocale_h__
+
+#include "nsStringFwd.h"
+#include "nsILocale.h"
+#include "plhash.h"
+
+class nsLocale : public nsILocale {
+ friend class nsLocaleService;
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+public:
+ nsLocale(void);
+
+ /* Declare methods from nsILocale */
+ NS_DECL_NSILOCALE
+
+protected:
+
+ NS_IMETHOD AddCategory(const nsAString& category, const nsAString& value);
+
+ static PLHashNumber Hash_HashFunction(const void* key);
+ static int Hash_CompareNSString(const void* s1, const void* s2);
+ static int Hash_EnumerateDelete(PLHashEntry *he, int hashIndex, void *arg);
+
+ PLHashTable* fHashtable;
+ uint32_t fCategoryCount;
+
+ virtual ~nsLocale(void);
+};
+
+
+#endif
diff --git a/intl/locale/nsLocaleConstructors.h b/intl/locale/nsLocaleConstructors.h
new file mode 100644
index 000000000..2d2e57974
--- /dev/null
+++ b/intl/locale/nsLocaleConstructors.h
@@ -0,0 +1,79 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#ifndef nsLocaleConstructors_h__
+#define nsLocaleConstructors_h__
+
+#include "nsCollationCID.h"
+#include "nsDateTimeFormatCID.h"
+#include "mozilla/ModuleUtils.h"
+#include "nsILocaleService.h"
+#include "nsIScriptableDateFormat.h"
+#include "nsIServiceManager.h"
+#include "nsLanguageAtomService.h"
+#include "nsPlatformCharset.h"
+
+#if defined(XP_MACOSX)
+#define USE_MAC_LOCALE
+#endif
+
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+#define USE_UNIX_LOCALE
+#endif
+
+#ifdef XP_WIN
+#include "windows/nsCollationWin.h"
+#include "windows/nsDateTimeFormatWin.h"
+#endif
+
+#ifdef USE_MAC_LOCALE
+#include "mac/nsCollationMacUC.h"
+#include "mac/nsDateTimeFormatMac.h"
+#endif
+
+#ifdef USE_UNIX_LOCALE
+#include "unix/nsCollationUnix.h"
+#include "unix/nsDateTimeFormatUnix.h"
+#endif
+
+#define NSLOCALE_MAKE_CTOR(ctor_, iface_, func_) \
+static nsresult \
+ctor_(nsISupports* aOuter, REFNSIID aIID, void** aResult) \
+{ \
+ *aResult = nullptr; \
+ if (aOuter) \
+ return NS_ERROR_NO_AGGREGATION; \
+ iface_* inst; \
+ nsresult rv = func_(&inst); \
+ if (NS_SUCCEEDED(rv)) { \
+ rv = inst->QueryInterface(aIID, aResult); \
+ NS_RELEASE(inst); \
+ } \
+ return rv; \
+}
+
+
+NSLOCALE_MAKE_CTOR(CreateLocaleService, nsILocaleService, NS_NewLocaleService)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationFactory)
+//NS_GENERIC_FACTORY_CONSTRUCTOR(nsScriptableDateTimeFormat)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsLanguageAtomService)
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPlatformCharset, Init)
+
+#ifdef XP_WIN
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationWin)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsDateTimeFormatWin)
+#endif
+
+#ifdef USE_UNIX_LOCALE
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationUnix)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsDateTimeFormatUnix)
+#endif
+
+#ifdef USE_MAC_LOCALE
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsCollationMacUC)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsDateTimeFormatMac)
+#endif
+
+#endif
diff --git a/intl/locale/nsLocaleService.cpp b/intl/locale/nsLocaleService.cpp
new file mode 100644
index 000000000..6d45ec9af
--- /dev/null
+++ b/intl/locale/nsLocaleService.cpp
@@ -0,0 +1,380 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+#include "nsCOMPtr.h"
+#include "nsILocale.h"
+#include "nsILocaleService.h"
+#include "nsLocale.h"
+#include "nsCRT.h"
+#include "prprf.h"
+#include "nsTArray.h"
+#include "nsString.h"
+#include "mozilla/UniquePtr.h"
+
+#include <ctype.h>
+
+#if defined(XP_WIN)
+# include "nsWin32Locale.h"
+#elif defined(XP_MACOSX)
+# include <Carbon/Carbon.h>
+#elif defined(XP_UNIX)
+# include <locale.h>
+# include <stdlib.h>
+# include "nsPosixLocale.h"
+#endif
+
+//
+// implementation constants
+const int LocaleListLength = 6;
+const char* LocaleList[LocaleListLength] =
+{
+ NSILOCALE_COLLATE,
+ NSILOCALE_CTYPE,
+ NSILOCALE_MONETARY,
+ NSILOCALE_NUMERIC,
+ NSILOCALE_TIME,
+ NSILOCALE_MESSAGE
+};
+
+#define NSILOCALE_MAX_ACCEPT_LANGUAGE 16
+#define NSILOCALE_MAX_ACCEPT_LENGTH 18
+
+#if (defined(XP_UNIX) && !defined(XP_MACOSX))
+static int posix_locale_category[LocaleListLength] =
+{
+ LC_COLLATE,
+ LC_CTYPE,
+ LC_MONETARY,
+ LC_NUMERIC,
+ LC_TIME,
+#ifdef HAVE_I18N_LC_MESSAGES
+ LC_MESSAGES
+#else
+ LC_CTYPE
+#endif
+};
+#endif
+
+//
+// nsILocaleService implementation
+//
+class nsLocaleService: public nsILocaleService {
+
+public:
+
+ //
+ // nsISupports
+ //
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ //
+ // nsILocaleService
+ //
+ NS_DECL_NSILOCALESERVICE
+
+
+ nsLocaleService(void);
+
+protected:
+
+ nsresult SetSystemLocale(void);
+ nsresult SetApplicationLocale(void);
+
+ nsCOMPtr<nsILocale> mSystemLocale;
+ nsCOMPtr<nsILocale> mApplicationLocale;
+
+ virtual ~nsLocaleService(void);
+};
+
+//
+// nsLocaleService methods
+//
+nsLocaleService::nsLocaleService(void)
+{
+#ifdef XP_WIN
+ nsAutoString xpLocale;
+ //
+ // get the system LCID
+ //
+ LCID win_lcid = GetSystemDefaultLCID();
+ NS_ENSURE_TRUE_VOID(win_lcid);
+ nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
+ nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
+ NS_ENSURE_SUCCESS_VOID(rv);
+
+ //
+ // get the application LCID
+ //
+ win_lcid = GetUserDefaultLCID();
+ NS_ENSURE_TRUE_VOID(win_lcid);
+ nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
+ rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
+ NS_ENSURE_SUCCESS_VOID(rv);
+#endif
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+ RefPtr<nsLocale> resultLocale(new nsLocale());
+ NS_ENSURE_TRUE_VOID(resultLocale);
+
+ // Get system configuration
+ const char* lang = getenv("LANG");
+
+ nsAutoString xpLocale, platformLocale;
+ nsAutoString category, category_platform;
+ int i;
+
+ for( i = 0; i < LocaleListLength; i++ ) {
+ nsresult result;
+ // setlocale( , "") evaluates LC_* and LANG
+ char* lc_temp = setlocale(posix_locale_category[i], "");
+ CopyASCIItoUTF16(LocaleList[i], category);
+ category_platform = category;
+ category_platform.AppendLiteral("##PLATFORM");
+
+ bool lc_temp_valid = lc_temp != nullptr;
+
+#if defined(MOZ_WIDGET_ANDROID)
+ // Treat the "C" env as nothing useful. See Bug 1095298.
+ lc_temp_valid = lc_temp_valid && strcmp(lc_temp, "C") != 0;
+#endif
+
+ if (lc_temp_valid) {
+ result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale);
+ CopyASCIItoUTF16(lc_temp, platformLocale);
+ } else {
+ if ( lang == nullptr ) {
+ platformLocale.AssignLiteral("en_US");
+ result = nsPosixLocale::GetXPLocale("en-US", xpLocale);
+ } else {
+ CopyASCIItoUTF16(lang, platformLocale);
+ result = nsPosixLocale::GetXPLocale(lang, xpLocale);
+ }
+ }
+ if (NS_FAILED(result)) {
+ return;
+ }
+ resultLocale->AddCategory(category, xpLocale);
+ resultLocale->AddCategory(category_platform, platformLocale);
+ }
+ mSystemLocale = do_QueryInterface(resultLocale);
+ mApplicationLocale = do_QueryInterface(resultLocale);
+
+#endif // XP_UNIX
+
+#ifdef XP_MACOSX
+ // Get string representation of user's current locale
+ CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
+ CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
+ ::CFRetain(userLocaleStr);
+
+ AutoTArray<UniChar, 32> buffer;
+ int size = ::CFStringGetLength(userLocaleStr);
+ buffer.SetLength(size + 1);
+ CFRange range = ::CFRangeMake(0, size);
+ ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
+ buffer[size] = 0;
+
+ // Convert the locale string to the format that Mozilla expects
+ nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));
+ xpLocale.ReplaceChar('_', '-');
+
+ nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
+ if (NS_SUCCEEDED(rv)) {
+ mApplicationLocale = mSystemLocale;
+ }
+
+ ::CFRelease(userLocaleStr);
+ ::CFRelease(userLocaleRef);
+
+ NS_ASSERTION(mApplicationLocale, "Failed to create locale objects");
+#endif // XP_MACOSX
+}
+
+nsLocaleService::~nsLocaleService(void)
+{
+}
+
+NS_IMPL_ISUPPORTS(nsLocaleService, nsILocaleService)
+
+NS_IMETHODIMP
+nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
+{
+ nsresult result;
+
+ *_retval = nullptr;
+
+ RefPtr<nsLocale> resultLocale(new nsLocale());
+ if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
+
+ for (int32_t i = 0; i < LocaleListLength; i++) {
+ NS_ConvertASCIItoUTF16 category(LocaleList[i]);
+ result = resultLocale->AddCategory(category, aLocale);
+ if (NS_FAILED(result)) return result;
+#if defined(XP_UNIX) && !defined(XP_MACOSX)
+ category.AppendLiteral("##PLATFORM");
+ result = resultLocale->AddCategory(category, aLocale);
+ if (NS_FAILED(result)) return result;
+#endif
+ }
+
+ NS_ADDREF(*_retval = resultLocale);
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP
+nsLocaleService::GetSystemLocale(nsILocale **_retval)
+{
+ if (mSystemLocale) {
+ NS_ADDREF(*_retval = mSystemLocale);
+ return NS_OK;
+ }
+
+ *_retval = (nsILocale*)nullptr;
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsLocaleService::GetApplicationLocale(nsILocale **_retval)
+{
+ if (mApplicationLocale) {
+ NS_ADDREF(*_retval = mApplicationLocale);
+ return NS_OK;
+ }
+
+ *_retval=(nsILocale*)nullptr;
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval)
+{
+ char* cPtr;
+ char* cPtr1;
+ char* cPtr2;
+ int i;
+ int j;
+ int countLang = 0;
+ char acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];
+ nsresult result;
+
+ auto input = MakeUnique<char[]>(strlen(acceptLanguage)+1);
+
+ strcpy(input.get(), acceptLanguage);
+ cPtr1 = input.get()-1;
+ cPtr2 = input.get();
+
+ /* put in standard form */
+ while (*(++cPtr1)) {
+ if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
+ else if (isspace(*cPtr1)) ; /* ignore any space */
+ else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
+ else if (*cPtr1=='*') ; /* ignore "*" */
+ else *cPtr2++ = *cPtr1; /* else unchanged */
+ }
+ *cPtr2 = '\0';
+
+ countLang = 0;
+
+ if (strchr(input.get(), ';')) {
+ /* deal with the quality values */
+
+ float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];
+ float qSwap;
+ float bias = 0.0f;
+ char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE];
+ char* ptrSwap;
+
+ cPtr = nsCRT::strtok(input.get(),",",&cPtr2);
+ while (cPtr) {
+ qvalue[countLang] = 1.0f;
+ /* add extra parens to get rid of warning */
+ if ((cPtr1 = strchr(cPtr,';')) != nullptr) {
+ PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]);
+ *cPtr1 = '\0';
+ }
+ if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LANGUAGE) { /* ignore if too long */
+ qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
+ ptrLanguage[countLang++] = cPtr;
+ if (countLang>=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
+ }
+ cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
+ }
+
+ /* sort according to decending qvalue */
+ /* not a very good algorithm, but count is not likely large */
+ for ( i=0 ; i<countLang-1 ; i++ ) {
+ for ( j=i+1 ; j<countLang ; j++ ) {
+ if (qvalue[i]<qvalue[j]) {
+ qSwap = qvalue[i];
+ qvalue[i] = qvalue[j];
+ qvalue[j] = qSwap;
+ ptrSwap = ptrLanguage[i];
+ ptrLanguage[i] = ptrLanguage[j];
+ ptrLanguage[j] = ptrSwap;
+ }
+ }
+ }
+ for ( i=0 ; i<countLang ; i++ ) {
+ PL_strncpyz(acceptLanguageList[i],ptrLanguage[i],NSILOCALE_MAX_ACCEPT_LENGTH);
+ }
+
+ } else {
+ /* simple case: no quality values */
+
+ cPtr = nsCRT::strtok(input.get(),",",&cPtr2);
+ while (cPtr) {
+ if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LENGTH) { /* ignore if too long */
+ PL_strncpyz(acceptLanguageList[countLang++],cPtr,NSILOCALE_MAX_ACCEPT_LENGTH);
+ if (countLang>=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */
+ }
+ cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
+ }
+ }
+
+ //
+ // now create the locale
+ //
+ result = NS_ERROR_FAILURE;
+ if (countLang>0) {
+ result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval);
+ }
+
+ //
+ // clean up
+ //
+ return result;
+}
+
+
+nsresult
+nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval)
+{
+ nsCOMPtr<nsILocale> system_locale;
+ nsresult result;
+
+ result = GetSystemLocale(getter_AddRefs(system_locale));
+ if (NS_SUCCEEDED(result))
+ {
+ result = system_locale->
+ GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval);
+ return result;
+ }
+
+ return result;
+}
+
+
+
+nsresult
+NS_NewLocaleService(nsILocaleService** result)
+{
+ if(!result)
+ return NS_ERROR_NULL_POINTER;
+ *result = new nsLocaleService();
+ if (! *result)
+ return NS_ERROR_OUT_OF_MEMORY;
+ NS_ADDREF(*result);
+ return NS_OK;
+}
diff --git a/intl/locale/nsPlatformCharset.h b/intl/locale/nsPlatformCharset.h
new file mode 100644
index 000000000..6af995f46
--- /dev/null
+++ b/intl/locale/nsPlatformCharset.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+#ifndef nsPlatformCharset_h__
+#define nsPlatformCharset_h__
+
+#include "nsIPlatformCharset.h"
+
+class nsPlatformCharset : public nsIPlatformCharset
+{
+ NS_DECL_ISUPPORTS
+
+public:
+
+ nsPlatformCharset();
+
+ NS_IMETHOD Init();
+ NS_IMETHOD GetCharset(nsPlatformCharsetSel selector, nsACString& oResult) override;
+ NS_IMETHOD GetDefaultCharsetForLocale(const nsAString& localeName, nsACString& oResult) override;
+
+private:
+ nsCString mCharset;
+ nsString mLocale; // remember the locale & charset
+
+ nsresult MapToCharset(nsAString& inANSICodePage, nsACString& outCharset);
+ nsresult InitGetCharset(nsACString& oString);
+ nsresult VerifyCharset(nsCString &aCharset);
+
+ virtual ~nsPlatformCharset();
+};
+
+#endif // nsPlatformCharset_h__
+
+
diff --git a/intl/locale/nsPosixLocale.h b/intl/locale/nsPosixLocale.h
new file mode 100644
index 000000000..b3a680842
--- /dev/null
+++ b/intl/locale/nsPosixLocale.h
@@ -0,0 +1,24 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+#ifndef nsIPosixLocale_h__
+#define nsIPosixLocale_h__
+
+
+#include "nscore.h"
+#include "nsString.h"
+
+#define MAX_LANGUAGE_CODE_LEN 3
+#define MAX_COUNTRY_CODE_LEN 3
+#define MAX_LOCALE_LEN 128
+#define MAX_EXTRA_LEN 65
+
+class nsPosixLocale {
+
+public:
+ static nsresult GetPlatformLocale(const nsAString& locale, nsACString& posixLocale);
+ static nsresult GetXPLocale(const char* posixLocale, nsAString& locale);
+};
+
+#endif
diff --git a/intl/locale/nsScriptableDateFormat.cpp b/intl/locale/nsScriptableDateFormat.cpp
new file mode 100644
index 000000000..a75cdaf29
--- /dev/null
+++ b/intl/locale/nsScriptableDateFormat.cpp
@@ -0,0 +1,145 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* 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/. */
+
+#include "mozilla/Sprintf.h"
+#include "nsILocaleService.h"
+#include "nsDateTimeFormatCID.h"
+#include "nsIDateTimeFormat.h"
+#include "nsIScriptableDateFormat.h"
+#include "nsCOMPtr.h"
+#include "nsServiceManagerUtils.h"
+
+static NS_DEFINE_CID(kLocaleServiceCID, NS_LOCALESERVICE_CID);
+static NS_DEFINE_CID(kDateTimeFormatCID, NS_DATETIMEFORMAT_CID);
+
+class nsScriptableDateFormat : public nsIScriptableDateFormat {
+ public:
+ NS_DECL_ISUPPORTS
+
+ NS_IMETHOD FormatDateTime(const char16_t *locale,
+ nsDateFormatSelector dateFormatSelector,
+ nsTimeFormatSelector timeFormatSelector,
+ int32_t year,
+ int32_t month,
+ int32_t day,
+ int32_t hour,
+ int32_t minute,
+ int32_t second,
+ char16_t **dateTimeString) override;
+
+ NS_IMETHOD FormatDate(const char16_t *locale,
+ nsDateFormatSelector dateFormatSelector,
+ int32_t year,
+ int32_t month,
+ int32_t day,
+ char16_t **dateString) override
+ {return FormatDateTime(locale, dateFormatSelector, kTimeFormatNone,
+ year, month, day, 0, 0, 0, dateString);}
+
+ NS_IMETHOD FormatTime(const char16_t *locale,
+ nsTimeFormatSelector timeFormatSelector,
+ int32_t hour,
+ int32_t minute,
+ int32_t second,
+ char16_t **timeString) override
+ {return FormatDateTime(locale, kDateFormatNone, timeFormatSelector,
+ 1999, 1, 1, hour, minute, second, timeString);}
+
+ nsScriptableDateFormat() {}
+
+private:
+ nsString mStringOut;
+
+ virtual ~nsScriptableDateFormat() {}
+};
+
+NS_IMPL_ISUPPORTS(nsScriptableDateFormat, nsIScriptableDateFormat)
+
+NS_IMETHODIMP nsScriptableDateFormat::FormatDateTime(
+ const char16_t *aLocale,
+ nsDateFormatSelector dateFormatSelector,
+ nsTimeFormatSelector timeFormatSelector,
+ int32_t year,
+ int32_t month,
+ int32_t day,
+ int32_t hour,
+ int32_t minute,
+ int32_t second,
+ char16_t **dateTimeString)
+{
+ // We can't have a valid date with the year, month or day
+ // being lower than 1.
+ if (year < 1 || month < 1 || day < 1)
+ return NS_ERROR_INVALID_ARG;
+
+ nsresult rv;
+ nsAutoString localeName(aLocale);
+ *dateTimeString = nullptr;
+
+ nsCOMPtr<nsILocale> locale;
+ // re-initialise locale pointer only if the locale was given explicitly
+ if (!localeName.IsEmpty()) {
+ // get locale service
+ nsCOMPtr<nsILocaleService> localeService(do_GetService(kLocaleServiceCID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+ // get locale
+ rv = localeService->NewLocale(localeName, getter_AddRefs(locale));
+ NS_ENSURE_SUCCESS(rv, rv);
+ }
+
+ nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(kDateTimeFormatCID, &rv));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ tm tmTime;
+ time_t timetTime;
+
+ memset(&tmTime, 0, sizeof(tmTime));
+ tmTime.tm_year = year - 1900;
+ tmTime.tm_mon = month - 1;
+ tmTime.tm_mday = day;
+ tmTime.tm_hour = hour;
+ tmTime.tm_min = minute;
+ tmTime.tm_sec = second;
+ tmTime.tm_yday = tmTime.tm_wday = 0;
+ tmTime.tm_isdst = -1;
+ timetTime = mktime(&tmTime);
+
+ if ((time_t)-1 != timetTime) {
+ rv = dateTimeFormat->FormatTime(locale, dateFormatSelector, timeFormatSelector,
+ timetTime, mStringOut);
+ }
+ else {
+ // if mktime fails (e.g. year <= 1970), then try NSPR.
+ PRTime prtime;
+ char string[32];
+ SprintfLiteral(string, "%.2d/%.2d/%d %.2d:%.2d:%.2d", month, day, year, hour, minute, second);
+ if (PR_SUCCESS != PR_ParseTimeString(string, false, &prtime))
+ return NS_ERROR_INVALID_ARG;
+
+ rv = dateTimeFormat->FormatPRTime(locale, dateFormatSelector, timeFormatSelector,
+ prtime, mStringOut);
+ }
+ if (NS_SUCCEEDED(rv))
+ *dateTimeString = ToNewUnicode(mStringOut);
+
+ return rv;
+}
+
+nsresult
+NS_NewScriptableDateFormat(nsISupports* aOuter, REFNSIID aIID, void** aResult)
+{
+ if (aOuter)
+ return NS_ERROR_NO_AGGREGATION;
+
+ nsScriptableDateFormat* result = new nsScriptableDateFormat();
+ if (! result)
+ return NS_ERROR_OUT_OF_MEMORY;
+
+ NS_ADDREF(result);
+ nsresult rv = result->QueryInterface(aIID, aResult);
+ NS_RELEASE(result);
+
+ return rv;
+}
diff --git a/intl/locale/nsUConvPropertySearch.cpp b/intl/locale/nsUConvPropertySearch.cpp
new file mode 100644
index 000000000..934244516
--- /dev/null
+++ b/intl/locale/nsUConvPropertySearch.cpp
@@ -0,0 +1,44 @@
+/* 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/. */
+
+#include "nsUConvPropertySearch.h"
+#include "nsCRT.h"
+#include "nsString.h"
+#include "mozilla/BinarySearch.h"
+
+namespace {
+
+struct PropertyComparator
+{
+ const nsCString& mKey;
+ explicit PropertyComparator(const nsCString& aKey) : mKey(aKey) {}
+ int operator()(const nsUConvProp& aProperty) const {
+ return mKey.Compare(aProperty.mKey);
+ }
+};
+
+} // namespace
+
+// static
+nsresult
+nsUConvPropertySearch::SearchPropertyValue(const nsUConvProp aProperties[],
+ int32_t aNumberOfProperties,
+ const nsACString& aKey,
+ nsACString& aValue)
+{
+ using mozilla::BinarySearchIf;
+
+ const nsCString& flat = PromiseFlatCString(aKey);
+ size_t index;
+ if (BinarySearchIf(aProperties, 0, aNumberOfProperties,
+ PropertyComparator(flat), &index)) {
+ nsDependentCString val(aProperties[index].mValue,
+ aProperties[index].mValueLength);
+ aValue.Assign(val);
+ return NS_OK;
+ }
+
+ aValue.Truncate();
+ return NS_ERROR_FAILURE;
+}
diff --git a/intl/locale/nsUConvPropertySearch.h b/intl/locale/nsUConvPropertySearch.h
new file mode 100644
index 000000000..b27faa85b
--- /dev/null
+++ b/intl/locale/nsUConvPropertySearch.h
@@ -0,0 +1,37 @@
+/* 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/. */
+
+#ifndef nsUConvPropertySearch_h_
+#define nsUConvPropertySearch_h_
+
+#include "nsStringFwd.h"
+
+struct nsUConvProp
+{
+ const char* const mKey;
+ const char* const mValue;
+ const uint32_t mValueLength;
+};
+
+class nsUConvPropertySearch
+{
+ public:
+ /**
+ * Looks up a property by value.
+ *
+ * @param aProperties
+ * the static property array
+ * @param aKey
+ * the key to look up
+ * @param aValue
+ * the return value (empty string if not found)
+ * @return NS_OK if found or NS_ERROR_FAILURE if not found
+ */
+ static nsresult SearchPropertyValue(const nsUConvProp aProperties[],
+ int32_t aNumberOfProperties,
+ const nsACString& aKey,
+ nsACString& aValue);
+};
+
+#endif /* nsUConvPropertySearch_h_ */
diff --git a/intl/locale/nsWin32Locale.h b/intl/locale/nsWin32Locale.h
new file mode 100644
index 000000000..a7a8b589d
--- /dev/null
+++ b/intl/locale/nsWin32Locale.h
@@ -0,0 +1,32 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+#ifndef nsWin32Locale_h__
+#define nsWin32Locale_h__
+
+#include "nscore.h"
+#include "nsString.h"
+#include <windows.h>
+
+
+class nsWin32Locale {
+public:
+ static nsresult GetPlatformLocale(const nsAString& locale, LCID* winLCID);
+ static void GetXPLocale(LCID winLCID, nsAString& locale);
+
+private:
+ // Static class - Don't allow instantiation.
+ nsWin32Locale(void) {}
+
+ typedef LCID (WINAPI*LocaleNameToLCIDPtr)(LPCWSTR lpName, DWORD dwFlags);
+ typedef int (WINAPI*LCIDToLocaleNamePtr)(LCID Locale, LPWSTR lpName,
+ int cchName, DWORD dwFlags);
+
+ static LocaleNameToLCIDPtr localeNameToLCID;
+ static LCIDToLocaleNamePtr lcidToLocaleName;
+
+ static void initFunctionPointers ();
+};
+
+#endif
diff --git a/intl/locale/props2arrays.py b/intl/locale/props2arrays.py
new file mode 100644
index 000000000..510e0d51a
--- /dev/null
+++ b/intl/locale/props2arrays.py
@@ -0,0 +1,27 @@
+# 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/.
+
+import sys
+
+def main(header, propFile):
+ mappings = {}
+
+ with open(propFile, 'r') as f:
+ for line in f:
+ line = line.strip()
+ if not line.startswith('#'):
+ parts = line.split("=", 1)
+ if len(parts) == 2 and len(parts[0]) > 0:
+ mappings[parts[0].strip()] = parts[1].strip()
+
+ keys = mappings.keys()
+ keys.sort()
+
+ header.write("// This is a generated file. Please do not edit.\n")
+ header.write("// Please edit the corresponding .properties file instead.\n")
+
+ entries = ['{ "%s", "%s", %d }'
+ % (key, mappings[key], len(mappings[key])) for key in keys]
+ header.write(',\n'.join(entries) + '\n')
+
diff --git a/intl/locale/tests/nsLocaleTest.html b/intl/locale/tests/nsLocaleTest.html
new file mode 100644
index 000000000..5b7aa415b
--- /dev/null
+++ b/intl/locale/tests/nsLocaleTest.html
@@ -0,0 +1,44 @@
+<html>
+<head>
+ <title>nsLocale Scriptability Test</title>
+
+</head>
+
+<script>
+
+var localeService = null;
+var applicationLocale = null;
+var systemLocale = null;
+
+function get_locale_service() {
+ localeService = Components.classes["@mozilla.org/intl/nslocaleservice;1"].createInstance();
+ localeService = localeService.QueryInterface(Components.interfaces.nsILocaleService);
+ applicationLocale = localeService.GetApplicationLocale();
+ systemLocale = localeService.GetSystemLocale();
+}
+
+function do_application_locale(t) {
+ t.value = applicationLocale.GetCategory("NSILOCALE_MESSAGES");
+}
+
+function do_system_locale(t) {
+ t.value = systemLocale.GetCategory("NSILOCALE_MESSAGES");
+}
+
+</script>
+
+<body BGCOLOR="#FFFFFF" TEXT="#000000" onLoad="get_locale_service();">
+
+<form name="locale">
+<b>Application Locale: </b>
+<input type="button" value="Get Application Locale" onClick=do_application_locale(this);></br>
+<b>System Locale: </b>
+<input type="button" value="Get System Locale" onClick=do_system_locale(this);></br>
+</form>
+
+<hr>
+<address><a href="mailto:tague@netscape.com">Tague Griffith</a></address>
+</body>
+</html>
+
+
diff --git a/intl/locale/tests/sort/us-ascii_base.txt b/intl/locale/tests/sort/us-ascii_base.txt
new file mode 100644
index 000000000..3bc7fbc7b
--- /dev/null
+++ b/intl/locale/tests/sort/us-ascii_base.txt
@@ -0,0 +1,95 @@
+
+!
+"
+#
+$
+%
+&
+'
+(
+)
+*
++
+,
+-
+.
+/
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+:
+;
+<
+=
+>
+?
+@
+A
+B
+C
+D
+E
+F
+G
+H
+I
+J
+K
+L
+M
+N
+O
+P
+Q
+R
+S
+T
+U
+V
+W
+X
+Y
+Z
+[
+\
+]
+^
+_
+`
+a
+b
+c
+d
+e
+f
+g
+h
+i
+j
+k
+l
+m
+n
+o
+p
+q
+r
+s
+t
+u
+v
+w
+x
+y
+z
+{
+|
+}
+~
diff --git a/intl/locale/tests/sort/us-ascii_base_case_res.txt b/intl/locale/tests/sort/us-ascii_base_case_res.txt
new file mode 100644
index 000000000..3e526d226
--- /dev/null
+++ b/intl/locale/tests/sort/us-ascii_base_case_res.txt
@@ -0,0 +1,96 @@
+'
+-
+
+!
+"
+#
+$
+%
+&
+(
+)
+*
+,
+.
+/
+:
+;
+?
+@
+[
+\
+]
+^
+_
+`
+{
+|
+}
+~
++
+<
+=
+>
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+a
+A
+b
+B
+c
+C
+d
+D
+e
+E
+f
+F
+g
+G
+h
+H
+i
+I
+j
+J
+k
+K
+l
+L
+m
+M
+n
+N
+o
+O
+p
+P
+q
+Q
+r
+R
+s
+S
+t
+T
+u
+U
+v
+V
+w
+W
+x
+X
+y
+Y
+z
+Z
+
diff --git a/intl/locale/tests/sort/us-ascii_base_nocase_res.txt b/intl/locale/tests/sort/us-ascii_base_nocase_res.txt
new file mode 100644
index 000000000..2d18096db
--- /dev/null
+++ b/intl/locale/tests/sort/us-ascii_base_nocase_res.txt
@@ -0,0 +1,96 @@
+'
+-
+
+!
+"
+#
+$
+%
+&
+(
+)
+*
+,
+.
+/
+:
+;
+?
+@
+[
+\
+]
+^
+_
+`
+{
+|
+}
+~
++
+<
+=
+>
+0
+1
+2
+3
+4
+5
+6
+7
+8
+9
+A
+a
+B
+b
+C
+c
+d
+D
+e
+E
+f
+F
+g
+G
+h
+H
+i
+I
+j
+J
+k
+K
+L
+l
+m
+M
+n
+N
+O
+o
+p
+P
+q
+Q
+r
+R
+s
+S
+t
+T
+u
+U
+v
+V
+w
+W
+X
+x
+Y
+y
+Z
+z
+
diff --git a/intl/locale/tests/sort/us-ascii_sort.txt b/intl/locale/tests/sort/us-ascii_sort.txt
new file mode 100644
index 000000000..b6962f8de
--- /dev/null
+++ b/intl/locale/tests/sort/us-ascii_sort.txt
@@ -0,0 +1,78 @@
+ludwig van beethoven
+Ludwig van Beethoven
+Ludwig van beethoven
+Jane
+jane
+JANE
+jAne
+jaNe
+janE
+JAne
+JaNe
+JanE
+JANe
+JaNE
+JAnE
+jANE
+Umberto Eco
+Umberto eco
+umberto eco
+umberto Eco
+UMBERTO ECO
+ace
+bash
+*ace
+!ace
+%ace
+~ace
+#ace
+cork
+denizen
+[denizen]
+(denizen)
+{denizen}
+/denizen/
+#denizen#
+$denizen$
+@denizen
+elf
+full
+gnome
+gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Japanese
+gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Javanese
+hint
+Internationalization
+Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization
+Zinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizatio
+n
+Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalization
+ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTioninternationalizationinternationalizationinternationalizationinternationalization
+ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTion
+jostle
+kin
+Laymen
+lumens
+Lumens
+motleycrew
+motley crew
+niven's creative talents
+nivens creative talents
+opie
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rockies
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rokkies
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the rockies
+quilt's
+quilts
+quilt
+Rondo
+street
+tamale oxidization and iodization in rapid progress
+tamale oxidization and iodization in rapid Progress
+until
+vera
+Wobble
+Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoneme
+Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoname
+yearn
+zodiac
+
diff --git a/intl/locale/tests/sort/us-ascii_sort_case_res.txt b/intl/locale/tests/sort/us-ascii_sort_case_res.txt
new file mode 100644
index 000000000..2720a8342
--- /dev/null
+++ b/intl/locale/tests/sort/us-ascii_sort_case_res.txt
@@ -0,0 +1,79 @@
+!ace
+#ace
+#denizen#
+$denizen$
+%ace
+(denizen)
+*ace
+/denizen/
+@denizen
+[denizen]
+{denizen}
+~ace
+ace
+bash
+cork
+denizen
+elf
+full
+gnome
+gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Japanese
+gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Javanese
+hint
+Internationalization
+jane
+janE
+jaNe
+jAne
+jANE
+Jane
+JanE
+JaNe
+JaNE
+JAne
+JAnE
+JANe
+JANE
+jostle
+kin
+Laymen
+ludwig van beethoven
+Ludwig van beethoven
+Ludwig van Beethoven
+lumens
+Lumens
+motley crew
+motleycrew
+nivens creative talents
+niven's creative talents
+opie
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the rockies
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rockies
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rokkies
+quilt
+quilts
+quilt's
+Rondo
+street
+tamale oxidization and iodization in rapid progress
+tamale oxidization and iodization in rapid Progress
+umberto eco
+umberto Eco
+Umberto eco
+Umberto Eco
+UMBERTO ECO
+until
+veda
+Veda
+vera
+Vera
+Wobble
+Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoname
+Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoneme
+yearn
+Zinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization
+Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalization
+Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization
+ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTion
+ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTioninternationalizationinternationalizationinternationalizationinternationalization
+zodiac
diff --git a/intl/locale/tests/sort/us-ascii_sort_nocase_res.txt b/intl/locale/tests/sort/us-ascii_sort_nocase_res.txt
new file mode 100644
index 000000000..fa3426d4e
--- /dev/null
+++ b/intl/locale/tests/sort/us-ascii_sort_nocase_res.txt
@@ -0,0 +1,79 @@
+!ace
+#ace
+#denizen#
+$denizen$
+%ace
+(denizen)
+*ace
+/denizen/
+@denizen
+[denizen]
+{denizen}
+~ace
+ace
+bash
+cork
+denizen
+elf
+full
+gnome
+gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Japanese
+gnomic investigation of typological factors in the grammaticalization process of Malayo-Polynesian substaratum in the protoAltaic vocabulary core in the proto-layers of pre-historic Javanese
+hint
+Internationalization
+JANe
+jANE
+JAnE
+JaNE
+Jane
+JanE
+JaNe
+JAne
+janE
+jaNe
+jAne
+JANE
+jane
+jostle
+kin
+Laymen
+Ludwig van beethoven
+Ludwig van Beethoven
+ludwig van beethoven
+Lumens
+lumens
+motley crew
+motleycrew
+nivens creative talents
+niven's creative talents
+opie
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the rockies
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rockies
+posh restaurants in surbanized and still urban incorporated subsection of this beautifl city in the Rokkies
+quilt
+quilts
+quilt's
+Rondo
+street
+tamale oxidization and iodization in rapid Progress
+tamale oxidization and iodization in rapid progress
+Umberto eco
+Umberto Eco
+umberto eco
+UMBERTO ECO
+umberto Eco
+until
+Veda
+veda
+Vera
+vera
+Wobble
+Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoname
+Xanadu's legenary imaginary floccinaucinihilipilification in localization of theoretical portions of glottochronological understanding of the phoneme
+yearn
+Zinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization
+Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization internationalizationinternationalizationinternationalizationinternationalizationinternationalization
+ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTioninternationalizationinternationalizationinternationalizationinternationalization
+ZinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizaTion
+Zinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalizationinternationalization
+zodiac
diff --git a/intl/locale/tests/unit/data/chrome.manifest b/intl/locale/tests/unit/data/chrome.manifest
new file mode 100644
index 000000000..a8678deef
--- /dev/null
+++ b/intl/locale/tests/unit/data/chrome.manifest
@@ -0,0 +1 @@
+content locale ./
diff --git a/intl/locale/tests/unit/data/intl_on_workers_worker.js b/intl/locale/tests/unit/data/intl_on_workers_worker.js
new file mode 100644
index 000000000..98aeeb5c0
--- /dev/null
+++ b/intl/locale/tests/unit/data/intl_on_workers_worker.js
@@ -0,0 +1,4 @@
+self.onmessage = function (data) {
+ let myLocale = Intl.NumberFormat().resolvedOptions().locale;
+ self.postMessage(myLocale);
+};
diff --git a/intl/locale/tests/unit/test_bug1086527.js b/intl/locale/tests/unit/test_bug1086527.js
new file mode 100644
index 000000000..ae0c5b17a
--- /dev/null
+++ b/intl/locale/tests/unit/test_bug1086527.js
@@ -0,0 +1,20 @@
+/* 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/. */
+
+/**
+ * This unit test makes sure that PluralForm.get can be called from strict mode
+ */
+
+Components.utils.import("resource://gre/modules/PluralForm.jsm");
+
+delete PluralForm.numForms;
+delete PluralForm.get;
+[PluralForm.get, PluralForm.numForms] = PluralForm.makeGetter(9);
+
+function run_test() {
+ "use strict";
+
+ do_check_eq(3, PluralForm.numForms());
+ do_check_eq("one", PluralForm.get(5, 'one;many'));
+}
diff --git a/intl/locale/tests/unit/test_bug22310.js b/intl/locale/tests/unit/test_bug22310.js
new file mode 100644
index 000000000..d0877db5d
--- /dev/null
+++ b/intl/locale/tests/unit/test_bug22310.js
@@ -0,0 +1,54 @@
+String.prototype.has = function(s) { return this.indexOf(s) != -1; }
+
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+
+function dt(locale) {
+ var date = new Date("2008-06-30T13:56:34");
+ const dtOptions = { year: 'numeric', month: 'long', day: 'numeric',
+ hour: 'numeric', minute: 'numeric', second: 'numeric' };
+ return date.toLocaleString(locale, dtOptions);
+}
+
+var all_passed = true;
+const tests =
+[
+ [dt("en-US").has("June"), "month name in en-US"],
+ [dt("en-US").has("2008"), "year in en-US"],
+ [dt("da").has("jun"), "month name in da"],
+ [dt("da-DK") == dt("da"), "da same as da-DK"],
+ [dt("en-GB").has("30") && dt("en-GB").has("June") &&
+ dt("en-GB").indexOf("30") < dt("en-GB").indexOf("June"),
+ "day before month in en-GB"],
+ [dt("en-US").has("30") && dt("en-US").has("June") &&
+ dt("en-US").indexOf("30") > dt("en-US").indexOf("June"),
+ "month before day in en-US"],
+ [dt("ja-JP").has("\u5E746\u670830\u65E5"), "year month and day in ja-JP"],
+ // The Firefox locale code ja-JP-mac will be resolved to a BCP47-compliant
+ // tag ja-JP-x-lvariant-mac by uloc_toLanguageTag
+ [dt("ja-JP") == dt("ja-JP-x-lvariant-mac"), "ja-JP-x-lvariant-mac same as ja-JP"],
+ [dt("nn-NO").has("juni"), "month name in nn-NO"],
+ [dt("nb-NO").has("juni"), "month name in nb-NO"],
+ // Bug 1261775 - failures on win10
+ //[dt("no-NO").has("30. juni"), "month name in no-NO"],
+ [dt("sv-SE").has("30 jun"), "month name in sv-SE"],
+ [dt("kok").has("\u091C\u0942\u0928"), "month name in kok"],
+ [dt("ta-IN").has("\u0B9C\u0BC2\u0BA9\u0BCD"), "month name in ta-IN"],
+ [dt("ab-CD").length > 0, "fallback for ab-CD"]
+];
+
+function one_test(testcase, msg)
+{
+ if (!testcase) {
+ all_passed = false;
+ dump("Unexpected date format: " + msg + "\n");
+ }
+}
+
+function run_test()
+{
+ for (var i = 0; i < tests.length; ++i) {
+ one_test(tests[i][0], tests[i][1]);
+ }
+ do_check_true(all_passed);
+}
diff --git a/intl/locale/tests/unit/test_bug371611.js b/intl/locale/tests/unit/test_bug371611.js
new file mode 100644
index 000000000..807c9ecc5
--- /dev/null
+++ b/intl/locale/tests/unit/test_bug371611.js
@@ -0,0 +1,26 @@
+var Cc = Components.classes;
+var Ci = Components.interfaces;
+var Cr = Components.results;
+
+function test_formatdatetime_return()
+{
+ var dateConv = Cc["@mozilla.org/intl/scriptabledateformat;1"].
+ getService(Ci.nsIScriptableDateFormat);
+
+ /* Testing if we throw instead of crashing when we are passed 0s. */
+ var x = false;
+ try {
+ dateConv.FormatDate("", Ci.nsIScriptableDateFormat.dateFormatLong,
+ 0, 0, 0);
+ }
+ catch (e if (e.result == Cr.NS_ERROR_INVALID_ARG)) {
+ x = true;
+ }
+ if (!x)
+ do_throw("FormatDate didn't throw when passed 0 for its arguments.");
+}
+
+function run_test()
+{
+ test_formatdatetime_return();
+}
diff --git a/intl/locale/tests/unit/test_bug374040.js b/intl/locale/tests/unit/test_bug374040.js
new file mode 100644
index 000000000..f662c235d
--- /dev/null
+++ b/intl/locale/tests/unit/test_bug374040.js
@@ -0,0 +1,39 @@
+function test_full() {
+ var date = new Date();
+ var scriptableDateServ =
+ Components.classes["@mozilla.org/intl/scriptabledateformat;1"].createInstance(Components.interfaces.nsIScriptableDateFormat);
+
+ var dateStrXpcom = scriptableDateServ.FormatDateTime("",
+ scriptableDateServ.dateFormatLong, scriptableDateServ.timeFormatSeconds,
+ date.getFullYear(), date.getMonth()+1, date.getDate(), date.getHours(),
+ date.getMinutes(), date.getSeconds());
+
+ var dateStrJs = date.toLocaleString();
+
+ do_check_eq(dateStrXpcom, dateStrJs);
+
+}
+
+function test_kTimeFormatSeconds() {
+ var date = new Date();
+ var scriptableDateServ =
+ Components.classes["@mozilla.org/intl/scriptabledateformat;1"].createInstance(Components.interfaces.nsIScriptableDateFormat);
+
+ var dateStrXpcom = scriptableDateServ.FormatDateTime("",
+ scriptableDateServ.dateFormatLong, scriptableDateServ.timeFormatNone,
+ date.getFullYear(), date.getMonth()+1, date.getDate(), date.getHours(),
+ date.getMinutes(), date.getSeconds());
+
+ var dateStrJs = date.toLocaleDateString()
+
+ do_check_eq(dateStrXpcom, dateStrJs);
+
+}
+
+function run_test()
+{
+ // XXX test disabled due to bug 421790
+ return;
+ test_full();
+ test_kTimeFormatSeconds();
+}
diff --git a/intl/locale/tests/unit/test_collation_mac_icu.js b/intl/locale/tests/unit/test_collation_mac_icu.js
new file mode 100644
index 000000000..32ebc60eb
--- /dev/null
+++ b/intl/locale/tests/unit/test_collation_mac_icu.js
@@ -0,0 +1,83 @@
+var {classes: Cc, interfaces: Ci, utils: Cu, results: Cr} = Components;
+
+Cu.import("resource://gre/modules/Services.jsm");
+
+function run_test()
+{
+ var input = [
+ "Argentina",
+ "Oerlikon",
+ "Offenbach",
+ "Sverige",
+ "Vaticano",
+ "Zimbabwe",
+ "la France",
+ "¡viva España!",
+ "Österreich",
+ "中国",
+ "日本",
+ "한국",
+ ];
+
+ function test(locale, expected) {
+ var localeSvc = Cc["@mozilla.org/intl/nslocaleservice;1"].
+ getService(Ci.nsILocaleService);
+ var collator = Cc["@mozilla.org/intl/collation-factory;1"].
+ createInstance(Ci.nsICollationFactory).
+ CreateCollation(localeSvc.newLocale(locale));
+ var strength = Ci.nsICollation.kCollationStrengthDefault;
+ var actual = input.sort((x, y) => collator.compareString(strength, x,y));
+ deepEqual(actual, expected, locale);
+ }
+
+ // Locale en-US; default options.
+ test("en-US", [
+ "¡viva España!",
+ "Argentina",
+ "la France",
+ "Oerlikon",
+ "Offenbach",
+ "Österreich",
+ "Sverige",
+ "Vaticano",
+ "Zimbabwe",
+ "한국",
+ "中国",
+ "日本",
+ ]);
+
+ // Locale sv-SE; default options.
+ // Swedish treats "Ö" as a separate character, which sorts after "Z".
+ test("sv-SE", [
+ "¡viva España!",
+ "Argentina",
+ "la France",
+ "Oerlikon",
+ "Offenbach",
+ "Sverige",
+ "Vaticano",
+ "Zimbabwe",
+ "Österreich",
+ "한국",
+ "中国",
+ "日本",
+ ]);
+
+ // Locale de-DE; default options.
+ // In German standard sorting, umlauted characters are treated as variants
+ // of their base characters: ä ≅ a, ö ≅ o, ü ≅ u.
+ test("de-DE", [
+ "¡viva España!",
+ "Argentina",
+ "la France",
+ "Oerlikon",
+ "Offenbach",
+ "Österreich",
+ "Sverige",
+ "Vaticano",
+ "Zimbabwe",
+ "한국",
+ "中国",
+ "日本",
+ ]);
+}
diff --git a/intl/locale/tests/unit/test_intl_on_workers.js b/intl/locale/tests/unit/test_intl_on_workers.js
new file mode 100644
index 000000000..899e39d38
--- /dev/null
+++ b/intl/locale/tests/unit/test_intl_on_workers.js
@@ -0,0 +1,23 @@
+function run_test() {
+ do_load_manifest("data/chrome.manifest");
+
+ if (typeof Intl !== "object") {
+ dump("Intl not enabled, skipping test\n");
+ equal(true, true);
+ return;
+ }
+
+ let mainThreadLocale = Intl.NumberFormat().resolvedOptions().locale;
+ let testWorker = new Worker("chrome://locale/content/intl_on_workers_worker.js");
+ testWorker.onmessage = function (e) {
+ try {
+ let workerLocale = e.data;
+ equal(mainThreadLocale, workerLocale, "Worker should inherit Intl locale from main thread.");
+ } finally {
+ do_test_finished();
+ }
+ };
+
+ do_test_pending();
+ testWorker.postMessage("go!");
+}
diff --git a/intl/locale/tests/unit/test_pluralForm.js b/intl/locale/tests/unit/test_pluralForm.js
new file mode 100644
index 000000000..834605b1f
--- /dev/null
+++ b/intl/locale/tests/unit/test_pluralForm.js
@@ -0,0 +1,615 @@
+/* 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/. */
+
+/**
+ * Make sure each of the plural forms have the correct number of forms and
+ * match up in functionality.
+ */
+
+Components.utils.import("resource://gre/modules/PluralForm.jsm");
+
+function run_test()
+{
+ let allExpect = [[
+ // 0: Chinese 0-9, 10-19, ..., 90-99
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ // 100-109, 110-119, ..., 190-199
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ // 200-209, 210-219, ..., 290-299
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ 1,1,1,1,1,1,1,1,1,1,
+ ], [
+ // 1: English 0-9, 10-19, ..., 90-99
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ // 100-109, 110-119, ..., 190-199
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ // 200-209, 210-219, ..., 290-299
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ ], [
+ // 2: French 0-9, 10-19, ..., 90-99
+ 1,1,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ // 100-109, 110-119, ..., 190-199
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ // 200-209, 210-219, ..., 290-299
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ ], [
+ // 3: Latvian 0-9, 10-19, ..., 90-99
+ 1,2,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ // 100-109, 110-119, ..., 190-199
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ // 200-209, 210-219, ..., 290-299
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ 3,2,3,3,3,3,3,3,3,3,
+ ], [
+ // 4: Scottish Gaelic 0-9, 10-19, ..., 90-99
+ 4,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ // 100-109, 110-119, ..., 190-199
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ // 200-209, 210-219, ..., 290-299
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ ], [
+ // 5: Romanian 0-9, 10-19, ..., 90-99
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ // 100-109, 110-119, ..., 190-199
+ 3,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ // 200-209, 210-219, ..., 290-299
+ 3,2,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ ], [
+ // 6: Lithuanian 0-9, 10-19, ..., 90-99
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ // 100-109, 110-119, ..., 190-199
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ // 200-209, 210-219, ..., 290-299
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ 2,1,3,3,3,3,3,3,3,3,
+ ], [
+ // 7: Russian 0-9, 10-19, ..., 90-99
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ // 100-109, 110-119, ..., 190-199
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ // 200-209, 210-219, ..., 290-299
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,1,2,2,2,3,3,3,3,3,
+ ], [
+ // 8: Slovak 0-9, 10-19, ..., 90-99
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ // 100-109, 110-119, ..., 190-199
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ // 200-209, 210-219, ..., 290-299
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ ], [
+ // 9: Polish 0-9, 10-19, ..., 90-99
+ 3,1,2,2,2,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ // 100-109, 110-119, ..., 190-199
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ // 200-209, 210-219, ..., 290-299
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,3,3,3,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ 3,3,2,2,2,3,3,3,3,3,
+ ], [
+ // 10: Slovenian 0-9, 10-19, ..., 90-99
+ 4,1,2,3,3,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ // 100-109, 110-119, ..., 190-199
+ 4,1,2,3,3,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ // 200-209, 210-219, ..., 290-299
+ 4,1,2,3,3,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ ], [
+ // 11: Irish Gaeilge 0-9, 10-19, ..., 90-99
+ 5,1,2,3,3,3,3,4,4,4,
+ 4,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ // 100-109, 110-119, ..., 190-199
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ // 200-209, 210-219, ..., 290-299
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,5,5,5,5,5,5,5,5,5,
+ ], [
+ // 12: Arabic 0-9, 10-19, ..., 90-99
+ 6,1,2,3,3,3,3,3,3,3,
+ 3,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ // 100-109, 110-119, ..., 190-199
+ 5,5,5,3,3,3,3,3,3,3,
+ 3,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ // 200-209, 210-219, ..., 290-299
+ 5,5,5,3,3,3,3,3,3,3,
+ 3,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ ], [
+ // 13: Maltese 0-9, 10-19, ..., 90-99
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,3,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ // 100-109, 110-119, ..., 190-199
+ 4,2,2,2,2,2,2,2,2,2,
+ 2,3,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ // 200-209, 210-219, ..., 290-299
+ 4,2,2,2,2,2,2,2,2,2,
+ 2,3,3,3,3,3,3,3,3,3,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ 4,4,4,4,4,4,4,4,4,4,
+ ], [
+ // 14: Macedonian 0-9, 10-19, ..., 90-99
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ // 100-109, 110-119, ..., 190-199
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ // 200-209, 210-219, ..., 290-299
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ 3,1,2,3,3,3,3,3,3,3,
+ ], [
+ // 15: Icelandic 0-9, 10-19, ..., 90-99
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ // 100-109, 110-119, ..., 190-199
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ // 200-209, 210-219, ..., 290-299
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,2,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ 2,1,2,2,2,2,2,2,2,2,
+ ], [
+ // 16: Breton 0-9, 10-19, ..., 90-99
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ // 100-109, 110-119, ..., 190-199
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ // 200-209, 210-219, ..., 290-299
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ 5,1,2,3,3,5,5,5,5,3,
+ 5,5,5,5,5,5,5,5,5,5,
+ ]];
+
+ for (let [rule, expect] in Iterator(allExpect)) {
+ print("\nTesting rule #" + rule);
+
+ let [get, numForms] = PluralForm.makeGetter(rule);
+
+ // Make sure the largest value expected matches the number of plural forms
+ let maxExpect = Math.max.apply(this, expect);
+ do_check_eq(maxExpect, numForms());
+
+ // Make a string of numbers, e.g., 1;2;3;4;5
+ let words = [];
+ for (let i = 1; i <= maxExpect; i++)
+ words.push(i);
+ words = words.join(";");
+
+ // Make sure we get the expected number
+ for (let [index, number] in Iterator(expect)) {
+ print(["Plural form of ", index, " should be ", number, " (", words, ")"].join(""));
+ do_check_eq(get(index, words), number);
+ }
+ }
+}
diff --git a/intl/locale/tests/unit/test_pluralForm_english.js b/intl/locale/tests/unit/test_pluralForm_english.js
new file mode 100644
index 000000000..bdd7d2749
--- /dev/null
+++ b/intl/locale/tests/unit/test_pluralForm_english.js
@@ -0,0 +1,26 @@
+/* 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/. */
+
+/**
+ * This unit test makes sure the plural form for the default language (by
+ * development), English, is working for the PluralForm javascript module.
+ */
+
+Components.utils.import("resource://gre/modules/PluralForm.jsm");
+
+function run_test()
+{
+ // English has 2 plural forms
+ do_check_eq(2, PluralForm.numForms());
+
+ // Make sure for good inputs, things work as expected
+ for (var num = 0; num <= 200; num++)
+ do_check_eq(num == 1 ? "word" : "words", PluralForm.get(num, "word;words"));
+
+ // Not having enough plural forms defaults to the first form
+ do_check_eq("word", PluralForm.get(2, "word"));
+
+ // Empty forms defaults to the first form
+ do_check_eq("word", PluralForm.get(2, "word;"));
+}
diff --git a/intl/locale/tests/unit/test_pluralForm_makeGetter.js b/intl/locale/tests/unit/test_pluralForm_makeGetter.js
new file mode 100644
index 000000000..4d0928ae4
--- /dev/null
+++ b/intl/locale/tests/unit/test_pluralForm_makeGetter.js
@@ -0,0 +1,36 @@
+/* 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/. */
+
+/**
+ * This unit test makes sure the plural form for Irish Gaeilge is working by
+ * using the makeGetter method instead of using the default language (by
+ * development), English.
+ */
+
+Components.utils.import("resource://gre/modules/PluralForm.jsm");
+
+function run_test()
+{
+ // Irish is plural rule #11
+ let [get, numForms] = PluralForm.makeGetter(11);
+
+ // Irish has 5 plural forms
+ do_check_eq(5, numForms());
+
+ // I don't really know Irish, so I'll stick in some dummy text
+ let words = "is 1;is 2;is 3-6;is 7-10;everything else";
+
+ let test = function(text, low, high) {
+ for (let num = low; num <= high; num++)
+ do_check_eq(text, get(num, words));
+ };
+
+ // Make sure for good inputs, things work as expected
+ test("everything else", 0, 0);
+ test("is 1", 1, 1);
+ test("is 2", 2, 2);
+ test("is 3-6", 3, 6);
+ test("is 7-10", 7, 10);
+ test("everything else", 11, 200);
+}
diff --git a/intl/locale/tests/unit/xpcshell.ini b/intl/locale/tests/unit/xpcshell.ini
new file mode 100644
index 000000000..f794fd9f4
--- /dev/null
+++ b/intl/locale/tests/unit/xpcshell.ini
@@ -0,0 +1,22 @@
+[DEFAULT]
+head =
+tail =
+support-files =
+ data/intl_on_workers_worker.js
+ data/chrome.manifest
+
+[test_bug22310.js]
+skip-if = toolkit != "windows" && toolkit != "cocoa"
+
+[test_bug371611.js]
+[test_bug374040.js]
+skip-if = toolkit == "windows" || toolkit == "cocoa"
+
+[test_collation_mac_icu.js]
+skip-if = toolkit != "cocoa"
+
+[test_bug1086527.js]
+[test_intl_on_workers.js]
+[test_pluralForm.js]
+[test_pluralForm_english.js]
+[test_pluralForm_makeGetter.js]
diff --git a/intl/locale/unix/moz.build b/intl/locale/unix/moz.build
new file mode 100644
index 000000000..7685d0a01
--- /dev/null
+++ b/intl/locale/unix/moz.build
@@ -0,0 +1,38 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SOURCES += [
+ 'nsCollationUnix.cpp',
+ 'nsDateTimeFormatUnix.cpp',
+ 'nsPosixLocale.cpp',
+]
+
+if CONFIG['OS_TARGET'] == 'Android':
+ SOURCES += [
+ 'nsAndroidCharset.cpp',
+ ]
+else:
+ SOURCES += [
+ 'nsUNIXCharset.cpp',
+ ]
+ GENERATED_FILES = [
+ 'unixcharset.properties.h',
+ ]
+ unixcharset = GENERATED_FILES['unixcharset.properties.h']
+ unixcharset.script = '../props2arrays.py'
+ unixcharset.inputs = ['unixcharset.properties']
+
+FINAL_LIBRARY = 'xul'
+
+LOCAL_INCLUDES += [
+ '..',
+]
+
+# CODESET is not automatically defined on some older versions of Redhat.
+# Define _XOPEN_SOURCE so CODESET will get defined and thus allow
+# nl_langinfo(CODESET) to compile on these systems.
+if CONFIG['OS_ARCH'] == 'Linux':
+ DEFINES['_XOPEN_SOURCE'] = 500
diff --git a/intl/locale/unix/nsAndroidCharset.cpp b/intl/locale/unix/nsAndroidCharset.cpp
new file mode 100644
index 000000000..ed646039c
--- /dev/null
+++ b/intl/locale/unix/nsAndroidCharset.cpp
@@ -0,0 +1,49 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsIPlatformCharset.h"
+#include "nsPlatformCharset.h"
+
+NS_IMPL_ISUPPORTS(nsPlatformCharset, nsIPlatformCharset)
+
+nsPlatformCharset::nsPlatformCharset()
+{
+}
+
+nsPlatformCharset::~nsPlatformCharset()
+{
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::Init()
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::GetCharset(nsPlatformCharsetSel selector, nsACString& oResult)
+{
+ oResult.AssignLiteral("UTF-8");
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString &oResult)
+{
+ oResult.AssignLiteral("UTF-8");
+ return NS_OK;
+}
+
+nsresult
+nsPlatformCharset::InitGetCharset(nsACString &oString)
+{
+ return NS_OK;
+}
+
+nsresult
+nsPlatformCharset::VerifyCharset(nsCString &aCharset)
+{
+ return NS_OK;
+}
diff --git a/intl/locale/unix/nsCollationUnix.cpp b/intl/locale/unix/nsCollationUnix.cpp
new file mode 100644
index 000000000..3bc5a731c
--- /dev/null
+++ b/intl/locale/unix/nsCollationUnix.cpp
@@ -0,0 +1,189 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include <locale.h>
+#include "prmem.h"
+#include "nsCollationUnix.h"
+#include "nsIServiceManager.h"
+#include "nsIComponentManager.h"
+#include "nsILocaleService.h"
+#include "nsIPlatformCharset.h"
+#include "nsPosixLocale.h"
+#include "nsCOMPtr.h"
+#include "nsUnicharUtils.h"
+#include "nsCRT.h"
+//#define DEBUG_UNIX_COLLATION
+
+inline void nsCollationUnix::DoSetLocale()
+{
+ char *locale = setlocale(LC_COLLATE, nullptr);
+ mSavedLocale.Assign(locale ? locale : "");
+ if (!mSavedLocale.EqualsIgnoreCase(mLocale.get())) {
+ (void) setlocale(LC_COLLATE, PromiseFlatCString(Substring(mLocale,0,MAX_LOCALE_LEN)).get());
+ }
+}
+
+inline void nsCollationUnix::DoRestoreLocale()
+{
+ if (!mSavedLocale.EqualsIgnoreCase(mLocale.get())) {
+ (void) setlocale(LC_COLLATE, PromiseFlatCString(Substring(mSavedLocale,0,MAX_LOCALE_LEN)).get());
+ }
+}
+
+nsCollationUnix::nsCollationUnix() : mCollation(nullptr)
+{
+}
+
+nsCollationUnix::~nsCollationUnix()
+{
+ if (mCollation)
+ delete mCollation;
+}
+
+NS_IMPL_ISUPPORTS(nsCollationUnix, nsICollation)
+
+nsresult nsCollationUnix::Initialize(nsILocale* locale)
+{
+#define kPlatformLocaleLength 64
+ NS_ASSERTION(!mCollation, "Should only be initialized once");
+
+ nsresult res;
+
+ mCollation = new nsCollation;
+
+ // default platform locale
+ mLocale.Assign('C');
+
+ nsAutoString localeStr;
+ NS_NAMED_LITERAL_STRING(aCategory, "NSILOCALE_COLLATE##PLATFORM");
+
+ // get locale string, use app default if no locale specified
+ if (locale == nullptr) {
+ nsCOMPtr<nsILocaleService> localeService =
+ do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
+ if (NS_SUCCEEDED(res)) {
+ nsCOMPtr<nsILocale> appLocale;
+ res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
+ if (NS_SUCCEEDED(res)) {
+ res = appLocale->GetCategory(aCategory, localeStr);
+ NS_ASSERTION(NS_SUCCEEDED(res), "failed to get app locale info");
+ }
+ }
+ }
+ else {
+ res = locale->GetCategory(aCategory, localeStr);
+ NS_ASSERTION(NS_SUCCEEDED(res), "failed to get locale info");
+ }
+
+ // Get platform locale and charset name from locale, if available
+ if (NS_SUCCEEDED(res)) {
+ // keep the same behavior as 4.x as well as avoiding Linux collation key problem
+ if (localeStr.LowerCaseEqualsLiteral("en_us")) { // note: locale is in platform format
+ localeStr.Assign('C');
+ }
+
+ nsPosixLocale::GetPlatformLocale(localeStr, mLocale);
+
+ nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res);
+ if (NS_SUCCEEDED(res)) {
+ nsAutoCString mappedCharset;
+ res = platformCharset->GetDefaultCharsetForLocale(localeStr, mappedCharset);
+ if (NS_SUCCEEDED(res)) {
+ mCollation->SetCharset(mappedCharset.get());
+ }
+ }
+ }
+
+ return NS_OK;
+}
+
+
+nsresult nsCollationUnix::CompareString(int32_t strength,
+ const nsAString& string1,
+ const nsAString& string2,
+ int32_t* result)
+{
+ nsresult res = NS_OK;
+
+ nsAutoString stringNormalized1, stringNormalized2;
+ if (strength != kCollationCaseSensitive) {
+ res = mCollation->NormalizeString(string1, stringNormalized1);
+ if (NS_FAILED(res)) {
+ return res;
+ }
+ res = mCollation->NormalizeString(string2, stringNormalized2);
+ if (NS_FAILED(res)) {
+ return res;
+ }
+ } else {
+ stringNormalized1 = string1;
+ stringNormalized2 = string2;
+ }
+
+ // convert unicode to charset
+ char *str1, *str2;
+
+ res = mCollation->UnicodeToChar(stringNormalized1, &str1);
+ if (NS_SUCCEEDED(res) && str1) {
+ res = mCollation->UnicodeToChar(stringNormalized2, &str2);
+ if (NS_SUCCEEDED(res) && str2) {
+ DoSetLocale();
+ *result = strcoll(str1, str2);
+ DoRestoreLocale();
+ PR_Free(str2);
+ }
+ PR_Free(str1);
+ }
+
+ return res;
+}
+
+
+nsresult nsCollationUnix::AllocateRawSortKey(int32_t strength,
+ const nsAString& stringIn,
+ uint8_t** key, uint32_t* outLen)
+{
+ nsresult res = NS_OK;
+
+ nsAutoString stringNormalized;
+ if (strength != kCollationCaseSensitive) {
+ res = mCollation->NormalizeString(stringIn, stringNormalized);
+ if (NS_FAILED(res))
+ return res;
+ } else {
+ stringNormalized = stringIn;
+ }
+ // convert unicode to charset
+ char *str;
+
+ res = mCollation->UnicodeToChar(stringNormalized, &str);
+ if (NS_SUCCEEDED(res) && str) {
+ DoSetLocale();
+ // call strxfrm to generate a key
+ size_t len = strxfrm(nullptr, str, 0) + 1;
+ void *buffer = PR_Malloc(len);
+ if (!buffer) {
+ res = NS_ERROR_OUT_OF_MEMORY;
+ } else if (strxfrm((char *)buffer, str, len) >= len) {
+ PR_Free(buffer);
+ res = NS_ERROR_FAILURE;
+ } else {
+ *key = (uint8_t *)buffer;
+ *outLen = len;
+ }
+ DoRestoreLocale();
+ PR_Free(str);
+ }
+
+ return res;
+}
+
+nsresult nsCollationUnix::CompareRawSortKey(const uint8_t* key1, uint32_t len1,
+ const uint8_t* key2, uint32_t len2,
+ int32_t* result)
+{
+ *result = PL_strcmp((const char *)key1, (const char *)key2);
+ return NS_OK;
+}
diff --git a/intl/locale/unix/nsCollationUnix.h b/intl/locale/unix/nsCollationUnix.h
new file mode 100644
index 000000000..dd2126b44
--- /dev/null
+++ b/intl/locale/unix/nsCollationUnix.h
@@ -0,0 +1,43 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+#ifndef nsCollationUnix_h__
+#define nsCollationUnix_h__
+
+
+#include "nsICollation.h"
+#include "nsCollation.h" // static library
+#include "plstr.h"
+#include "mozilla/Attributes.h"
+#include "nsString.h"
+
+
+
+class nsCollationUnix final : public nsICollation {
+
+protected:
+ nsCollation *mCollation;
+ nsCString mLocale;
+ nsCString mSavedLocale;
+ bool mUseCodePointOrder;
+
+ void DoSetLocale();
+ void DoRestoreLocale();
+
+ ~nsCollationUnix();
+
+public:
+ nsCollationUnix();
+
+ // nsISupports interface
+ NS_DECL_ISUPPORTS
+
+ // nsICollation interface
+ NS_DECL_NSICOLLATION
+
+};
+
+#endif /* nsCollationUnix_h__ */
diff --git a/intl/locale/unix/nsDateTimeFormatUnix.cpp b/intl/locale/unix/nsDateTimeFormatUnix.cpp
new file mode 100644
index 000000000..a70b54102
--- /dev/null
+++ b/intl/locale/unix/nsDateTimeFormatUnix.cpp
@@ -0,0 +1,284 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include <locale.h>
+#include "plstr.h"
+#include "nsIServiceManager.h"
+#include "nsDateTimeFormatUnix.h"
+#include "nsIComponentManager.h"
+#include "nsILocaleService.h"
+#include "nsIPlatformCharset.h"
+#include "nsPosixLocale.h"
+#include "nsCRT.h"
+#include "nsReadableUtils.h"
+#include "nsUnicharUtils.h"
+#include "mozilla/dom/EncodingUtils.h"
+
+using mozilla::dom::EncodingUtils;
+
+NS_IMPL_ISUPPORTS(nsDateTimeFormatUnix, nsIDateTimeFormat)
+
+// init this interface to a specified locale
+nsresult nsDateTimeFormatUnix::Initialize(nsILocale* locale)
+{
+ nsAutoString localeStr;
+ NS_NAMED_LITERAL_STRING(aCategory, "NSILOCALE_TIME##PLATFORM");
+ nsresult res = NS_OK;
+
+ // use cached info if match with stored locale
+ if (!locale) {
+ if (!mLocale.IsEmpty() &&
+ mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) {
+ return NS_OK;
+ }
+ }
+ else {
+ res = locale->GetCategory(aCategory, localeStr);
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ if (!mLocale.IsEmpty() &&
+ mLocale.Equals(localeStr,
+ nsCaseInsensitiveStringComparator())) {
+ return NS_OK;
+ }
+ }
+ }
+
+ mCharset.AssignLiteral("windows-1252");
+ mPlatformLocale.AssignLiteral("en_US");
+
+ // get locale name string, use app default if no locale specified
+ if (!locale) {
+ nsCOMPtr<nsILocaleService> localeService =
+ do_GetService(NS_LOCALESERVICE_CONTRACTID, &res);
+ if (NS_SUCCEEDED(res)) {
+ nsCOMPtr<nsILocale> appLocale;
+ res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
+ if (NS_SUCCEEDED(res)) {
+ res = appLocale->GetCategory(aCategory, localeStr);
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ NS_ASSERTION(NS_SUCCEEDED(res), "failed to get app locale info");
+ mAppLocale = localeStr; // cache app locale name
+ }
+ }
+ }
+ }
+ else {
+ res = locale->GetCategory(aCategory, localeStr);
+ NS_ASSERTION(NS_SUCCEEDED(res), "failed to get locale info");
+ }
+
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ mLocale = localeStr; // cache locale name
+
+ nsPosixLocale::GetPlatformLocale(mLocale, mPlatformLocale);
+
+ nsCOMPtr <nsIPlatformCharset> platformCharset = do_GetService(NS_PLATFORMCHARSET_CONTRACTID, &res);
+ if (NS_SUCCEEDED(res)) {
+ nsAutoCString mappedCharset;
+ res = platformCharset->GetDefaultCharsetForLocale(mLocale, mappedCharset);
+ if (NS_SUCCEEDED(res)) {
+ mCharset = mappedCharset;
+ }
+ }
+ }
+
+ mDecoder = EncodingUtils::DecoderForEncoding(mCharset);
+
+ LocalePreferred24hour();
+
+ return res;
+}
+
+void nsDateTimeFormatUnix::LocalePreferred24hour()
+{
+ char str[100];
+ time_t tt;
+ struct tm *tmc;
+ int i;
+
+ tt = time(nullptr);
+ tmc = localtime(&tt);
+
+ tmc->tm_hour=22; // put the test sample hour to 22:00 which is 10PM
+ tmc->tm_min=0; // set the min & sec other number than '2'
+ tmc->tm_sec=0;
+
+ char *temp = setlocale(LC_TIME, mPlatformLocale.get());
+ strftime(str, (size_t)99, "%X", (struct tm *)tmc);
+
+ (void) setlocale(LC_TIME, temp);
+
+ mLocalePreferred24hour = false;
+ for (i=0; str[i]; i++) {
+ if (str[i] == '2') { // if there is any '2', that locale use 0-23 time format
+ mLocalePreferred24hour = true;
+ break;
+ }
+ }
+
+ mLocaleAMPMfirst = true;
+ if (mLocalePreferred24hour == false) {
+ if (str[0] && str[0] == '1') { // if the first character is '1' of 10:00,
+ // AMPM string is located after 10:00
+ mLocaleAMPMfirst = false;
+ }
+ }
+}
+
+nsresult nsDateTimeFormatUnix::FormatTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const time_t timetTime,
+ nsAString& stringOut)
+{
+ struct tm tmTime;
+ memcpy(&tmTime, localtime(&timetTime), sizeof(struct tm));
+ return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
+}
+
+// performs a locale sensitive date formatting operation on the struct tm parameter
+nsresult nsDateTimeFormatUnix::FormatTMTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const struct tm* tmTime,
+ nsAString& stringOut)
+{
+#define NSDATETIME_FORMAT_BUFFER_LEN 80
+ char strOut[NSDATETIME_FORMAT_BUFFER_LEN*2]; // buffer for date and time
+ char fmtD[NSDATETIME_FORMAT_BUFFER_LEN], fmtT[NSDATETIME_FORMAT_BUFFER_LEN];
+ nsresult rv;
+
+
+ // set up locale data
+ (void) Initialize(locale);
+ NS_ENSURE_TRUE(mDecoder, NS_ERROR_NOT_INITIALIZED);
+
+ // set date format
+ if (dateFormatSelector == kDateFormatLong && timeFormatSelector == kTimeFormatSeconds) {
+ PL_strncpy(fmtD, "%c", NSDATETIME_FORMAT_BUFFER_LEN);
+ PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN);
+ } else {
+
+ switch (dateFormatSelector) {
+ case kDateFormatNone:
+ PL_strncpy(fmtD, "", NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ case kDateFormatLong:
+ case kDateFormatShort:
+ PL_strncpy(fmtD, "%x", NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ case kDateFormatYearMonth:
+ PL_strncpy(fmtD, "%Y/%m", NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ case kDateFormatWeekday:
+ PL_strncpy(fmtD, "%a", NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ default:
+ PL_strncpy(fmtD, "", NSDATETIME_FORMAT_BUFFER_LEN);
+ }
+
+ // set time format
+ switch (timeFormatSelector) {
+ case kTimeFormatNone:
+ PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ case kTimeFormatSeconds:
+ PL_strncpy(fmtT, "%X", NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ case kTimeFormatNoSeconds:
+ PL_strncpy(fmtT,
+ mLocalePreferred24hour ? "%H:%M" : mLocaleAMPMfirst ? "%p %I:%M" : "%I:%M %p",
+ NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ case kTimeFormatSecondsForce24Hour:
+ PL_strncpy(fmtT, "%H:%M:%S", NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ case kTimeFormatNoSecondsForce24Hour:
+ PL_strncpy(fmtT, "%H:%M", NSDATETIME_FORMAT_BUFFER_LEN);
+ break;
+ default:
+ PL_strncpy(fmtT, "", NSDATETIME_FORMAT_BUFFER_LEN);
+ }
+ }
+
+ // generate data/time string
+ char *old_locale = setlocale(LC_TIME, nullptr);
+ (void) setlocale(LC_TIME, mPlatformLocale.get());
+ if (strlen(fmtD) && strlen(fmtT)) {
+ PL_strncat(fmtD, " ", NSDATETIME_FORMAT_BUFFER_LEN);
+ PL_strncat(fmtD, fmtT, NSDATETIME_FORMAT_BUFFER_LEN);
+ strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtD, tmTime);
+ }
+ else if (strlen(fmtD) && !strlen(fmtT)) {
+ strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtD, tmTime);
+ }
+ else if (!strlen(fmtD) && strlen(fmtT)) {
+ strftime(strOut, NSDATETIME_FORMAT_BUFFER_LEN, fmtT, tmTime);
+ }
+ else {
+ PL_strncpy(strOut, "", NSDATETIME_FORMAT_BUFFER_LEN);
+ }
+ (void) setlocale(LC_TIME, old_locale);
+
+ // convert result to unicode
+ int32_t srcLength = (int32_t) strlen(strOut);
+ int32_t unicharLength = NSDATETIME_FORMAT_BUFFER_LEN*2;
+ char16_t unichars[NSDATETIME_FORMAT_BUFFER_LEN*2]; // buffer for date and time
+
+ rv = mDecoder->Convert(strOut, &srcLength, unichars, &unicharLength);
+ if (NS_FAILED(rv))
+ return rv;
+ stringOut.Assign(unichars, unicharLength);
+
+ return rv;
+}
+
+// performs a locale sensitive date formatting operation on the PRTime parameter
+nsresult nsDateTimeFormatUnix::FormatPRTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRTime prTime,
+ nsAString& stringOut)
+{
+ PRExplodedTime explodedTime;
+ PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime);
+
+ return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut);
+}
+
+// performs a locale sensitive date formatting operation on the PRExplodedTime parameter
+nsresult nsDateTimeFormatUnix::FormatPRExplodedTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRExplodedTime* explodedTime,
+ nsAString& stringOut)
+{
+ struct tm tmTime;
+ /* be safe and set all members of struct tm to zero
+ *
+ * there are other fields in the tm struct that we aren't setting
+ * (tm_isdst, tm_gmtoff, tm_zone, should we set these?) and since
+ * tmTime is on the stack, it may be filled with garbage, but
+ * the garbage may vary. (this may explain why some saw bug #10412, and
+ * others did not.
+ *
+ * when tmTime is passed to strftime() with garbage bad things may happen.
+ * see bug #10412
+ */
+ memset( &tmTime, 0, sizeof(tmTime) );
+
+ tmTime.tm_yday = explodedTime->tm_yday;
+ tmTime.tm_wday = explodedTime->tm_wday;
+ tmTime.tm_year = explodedTime->tm_year;
+ tmTime.tm_year -= 1900;
+ tmTime.tm_mon = explodedTime->tm_month;
+ tmTime.tm_mday = explodedTime->tm_mday;
+ tmTime.tm_hour = explodedTime->tm_hour;
+ tmTime.tm_min = explodedTime->tm_min;
+ tmTime.tm_sec = explodedTime->tm_sec;
+
+ return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
+}
+
diff --git a/intl/locale/unix/nsDateTimeFormatUnix.h b/intl/locale/unix/nsDateTimeFormatUnix.h
new file mode 100644
index 000000000..6c305556f
--- /dev/null
+++ b/intl/locale/unix/nsDateTimeFormatUnix.h
@@ -0,0 +1,70 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+#ifndef nsDateTimeFormatUnix_h__
+#define nsDateTimeFormatUnix_h__
+
+
+#include "nsCOMPtr.h"
+#include "nsIDateTimeFormat.h"
+#include "nsIUnicodeDecoder.h"
+
+#define kPlatformLocaleLength 64
+
+class nsDateTimeFormatUnix : public nsIDateTimeFormat {
+
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ // performs a locale sensitive date formatting operation on the time_t parameter
+ NS_IMETHOD FormatTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const time_t timetTime,
+ nsAString& stringOut) override;
+
+ // performs a locale sensitive date formatting operation on the struct tm parameter
+ NS_IMETHOD FormatTMTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const struct tm* tmTime,
+ nsAString& stringOut) override;
+
+ // performs a locale sensitive date formatting operation on the PRTime parameter
+ NS_IMETHOD FormatPRTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRTime prTime,
+ nsAString& stringOut) override;
+
+ // performs a locale sensitive date formatting operation on the PRExplodedTime parameter
+ NS_IMETHOD FormatPRExplodedTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRExplodedTime* explodedTime,
+ nsAString& stringOut) override;
+
+
+ nsDateTimeFormatUnix() {mLocale.Truncate();mAppLocale.Truncate();}
+
+private:
+ virtual ~nsDateTimeFormatUnix() {}
+
+ // init this interface to a specified locale
+ NS_IMETHOD Initialize(nsILocale* locale);
+
+ void LocalePreferred24hour();
+
+ nsString mLocale;
+ nsString mAppLocale;
+ nsCString mCharset; // in order to convert API result to unicode
+ nsCString mPlatformLocale; // for setlocale
+ bool mLocalePreferred24hour; // true if 24 hour format is preferred by current locale
+ bool mLocaleAMPMfirst; // true if AM/PM string is preferred before the time
+ nsCOMPtr <nsIUnicodeDecoder> mDecoder;
+};
+
+#endif /* nsDateTimeFormatUnix_h__ */
diff --git a/intl/locale/unix/nsPosixLocale.cpp b/intl/locale/unix/nsPosixLocale.cpp
new file mode 100644
index 000000000..16299afed
--- /dev/null
+++ b/intl/locale/unix/nsPosixLocale.cpp
@@ -0,0 +1,243 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nscore.h"
+#include "nsString.h"
+#include "nsPosixLocale.h"
+#include "mozilla/Sprintf.h"
+#include "plstr.h"
+#include "nsReadableUtils.h"
+
+static bool
+ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator);
+
+nsresult
+nsPosixLocale::GetPlatformLocale(const nsAString& locale, nsACString& posixLocale)
+{
+ char country_code[MAX_COUNTRY_CODE_LEN+1];
+ char lang_code[MAX_LANGUAGE_CODE_LEN+1];
+ char extra[MAX_EXTRA_LEN+1];
+ char posix_locale[MAX_LOCALE_LEN+1];
+ NS_LossyConvertUTF16toASCII xp_locale(locale);
+
+ if (!xp_locale.IsEmpty()) {
+ if (!ParseLocaleString(xp_locale.get(),lang_code,country_code,extra,'-')) {
+// strncpy(posixLocale,"C",length);
+ posixLocale = xp_locale; // use xp locale if parse failed
+ return NS_OK;
+ }
+
+ if (*country_code) {
+ if (*extra) {
+ SprintfLiteral(posix_locale,"%s_%s.%s",lang_code,country_code,extra);
+ }
+ else {
+ SprintfLiteral(posix_locale,"%s_%s",lang_code,country_code);
+ }
+ }
+ else {
+ if (*extra) {
+ SprintfLiteral(posix_locale,"%s.%s",lang_code,extra);
+ }
+ else {
+ SprintfLiteral(posix_locale,"%s",lang_code);
+ }
+ }
+
+ posixLocale = posix_locale;
+ return NS_OK;
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+nsresult
+nsPosixLocale::GetXPLocale(const char* posixLocale, nsAString& locale)
+{
+ char country_code[MAX_COUNTRY_CODE_LEN+1];
+ char lang_code[MAX_LANGUAGE_CODE_LEN+1];
+ char extra[MAX_EXTRA_LEN+1];
+ char posix_locale[MAX_LOCALE_LEN+1];
+
+ if (posixLocale!=nullptr) {
+ if (strcmp(posixLocale,"C")==0 || strcmp(posixLocale,"POSIX")==0) {
+ locale.AssignLiteral("en-US");
+ return NS_OK;
+ }
+ if (strcmp(posixLocale,"C.UTF-8")==0) {
+ locale.AssignLiteral("en-US.UTF-8");
+ return NS_OK;
+ }
+ if (!ParseLocaleString(posixLocale,lang_code,country_code,extra,'_')) {
+// * locale = "x-user-defined";
+ // use posix if parse failed
+ CopyASCIItoUTF16(nsDependentCString(posixLocale), locale);
+ return NS_OK;
+ }
+
+ // Special case: substitute "nb" (Norwegian Bokmal) for macrolanguage
+ // code "no" (Norwegian)
+ if (nsDependentCString(lang_code).LowerCaseEqualsLiteral("no")) {
+ lang_code[1] = 'b';
+ }
+
+ if (*country_code) {
+ SprintfLiteral(posix_locale,"%s-%s",lang_code,country_code);
+ }
+ else {
+ SprintfLiteral(posix_locale,"%s",lang_code);
+ }
+
+ CopyASCIItoUTF16(nsDependentCString(posix_locale), locale);
+ return NS_OK;
+
+ }
+
+ return NS_ERROR_FAILURE;
+
+}
+
+//
+// returns false/true depending on if it was of the form LL-CC.Extra
+static bool
+ParseLocaleString(const char* locale_string, char* language, char* country, char* extra, char separator)
+{
+ const char *src = locale_string;
+ char modifier[MAX_EXTRA_LEN+1];
+ char *dest;
+ int dest_space, len;
+
+ *language = '\0';
+ *country = '\0';
+ *extra = '\0';
+ if (strlen(locale_string) < 2) {
+ return(false);
+ }
+
+ //
+ // parse the language part
+ //
+ dest = language;
+ dest_space = MAX_LANGUAGE_CODE_LEN;
+ while ((*src) && (isalpha(*src)) && (dest_space--)) {
+ *dest++ = tolower(*src++);
+ }
+ *dest = '\0';
+ len = dest - language;
+ if ((len != 2) && (len != 3)) {
+ NS_ASSERTION((len == 2) || (len == 3), "language code too short");
+ NS_ASSERTION(len < 3, "reminder: verify we can handle 3+ character language code in all parts of the system; eg: language packs");
+ *language = '\0';
+ return(false);
+ }
+
+ // check if all done
+ if (*src == '\0') {
+ return(true);
+ }
+
+ if ((*src != '_') && (*src != '-') && (*src != '.') && (*src != '@')) {
+ NS_ASSERTION(isalpha(*src), "language code too long");
+ NS_ASSERTION(!isalpha(*src), "unexpected language/country separator");
+ *language = '\0';
+ return(false);
+ }
+
+ //
+ // parse the country part
+ //
+ if ((*src == '_') || (*src == '-')) {
+ src++;
+ dest = country;
+ dest_space = MAX_COUNTRY_CODE_LEN;
+ while ((*src) && (isalpha(*src)) && (dest_space--)) {
+ *dest++ = toupper(*src++);
+ }
+ *dest = '\0';
+ len = dest - country;
+ if (len != 2) {
+ NS_ASSERTION(len == 2, "unexpected country code length");
+ *language = '\0';
+ *country = '\0';
+ return(false);
+ }
+ }
+
+ // check if all done
+ if (*src == '\0') {
+ return(true);
+ }
+
+ if ((*src != '.') && (*src != '@')) {
+ NS_ASSERTION(isalpha(*src), "country code too long");
+ NS_ASSERTION(!isalpha(*src), "unexpected country/extra separator");
+ *language = '\0';
+ *country = '\0';
+ return(false);
+ }
+
+ //
+ // handle the extra part
+ //
+ if (*src == '.') {
+ src++; // move past the extra part separator
+ dest = extra;
+ dest_space = MAX_EXTRA_LEN;
+ while ((*src) && (*src != '@') && (dest_space--)) {
+ *dest++ = *src++;
+ }
+ *dest = '\0';
+ len = dest - extra;
+ if (len < 1) {
+ NS_ASSERTION(len > 0, "found country/extra separator but no extra code");
+ *language = '\0';
+ *country = '\0';
+ *extra = '\0';
+ return(false);
+ }
+ }
+
+ // check if all done
+ if (*src == '\0') {
+ return(true);
+ }
+
+ //
+ // handle the modifier part
+ //
+
+ if (*src == '@') {
+ src++; // move past the modifier separator
+ NS_ASSERTION(strcmp("euro",src) == 0, "found non euro modifier");
+ dest = modifier;
+ dest_space = MAX_EXTRA_LEN;
+ while ((*src) && (dest_space--)) {
+ *dest++ = *src++;
+ }
+ *dest = '\0';
+ len = dest - modifier;
+ if (len < 1) {
+ NS_ASSERTION(len > 0, "found modifier separator but no modifier code");
+ *language = '\0';
+ *country = '\0';
+ *extra = '\0';
+ *modifier = '\0';
+ return(false);
+ }
+ }
+
+ // check if all done
+ if (*src == '\0') {
+ return(true);
+ }
+
+ NS_ASSERTION(*src == '\0', "extra/modifier code too long");
+ *language = '\0';
+ *country = '\0';
+ *extra = '\0';
+
+ return(false);
+}
+
diff --git a/intl/locale/unix/nsUNIXCharset.cpp b/intl/locale/unix/nsUNIXCharset.cpp
new file mode 100644
index 000000000..d72305e55
--- /dev/null
+++ b/intl/locale/unix/nsUNIXCharset.cpp
@@ -0,0 +1,185 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include <locale.h>
+
+#include "mozilla/ArrayUtils.h"
+
+#include "nsIPlatformCharset.h"
+#include "nsUConvPropertySearch.h"
+#include "nsCOMPtr.h"
+#include "nsReadableUtils.h"
+#include "nsEncoderDecoderUtils.h"
+#if HAVE_GNU_LIBC_VERSION_H
+#include <gnu/libc-version.h>
+#endif
+#ifdef HAVE_NL_TYPES_H
+#include <nl_types.h>
+#endif
+#if HAVE_LANGINFO_CODESET
+#include <langinfo.h>
+#endif
+#include "nsPlatformCharset.h"
+#include "prinit.h"
+#include "nsUnicharUtils.h"
+#include "mozilla/dom/EncodingUtils.h"
+
+using mozilla::dom::EncodingUtils;
+using namespace mozilla;
+
+static const nsUConvProp kUnixCharsets[] = {
+#include "unixcharset.properties.h"
+};
+
+NS_IMPL_ISUPPORTS(nsPlatformCharset, nsIPlatformCharset)
+
+nsPlatformCharset::nsPlatformCharset()
+{
+}
+
+static nsresult
+ConvertLocaleToCharsetUsingDeprecatedConfig(const nsACString& locale,
+ nsACString& oResult)
+{
+ if (!(locale.IsEmpty())) {
+ if (NS_SUCCEEDED(nsUConvPropertySearch::SearchPropertyValue(kUnixCharsets,
+ ArrayLength(kUnixCharsets), locale, oResult))) {
+ return NS_OK;
+ }
+ }
+ NS_ERROR("unable to convert locale to charset using deprecated config");
+ oResult.AssignLiteral("ISO-8859-1");
+ return NS_SUCCESS_USING_FALLBACK_LOCALE;
+}
+
+nsPlatformCharset::~nsPlatformCharset()
+{
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::GetCharset(nsPlatformCharsetSel selector, nsACString& oResult)
+{
+ oResult = mCharset;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString &oResult)
+{
+ //
+ // if this locale is the user's locale then use the charset
+ // we already determined at initialization
+ //
+ if (mLocale.Equals(localeName) ||
+ // support the 4.x behavior
+ (mLocale.LowerCaseEqualsLiteral("en_us") &&
+ localeName.LowerCaseEqualsLiteral("c"))) {
+ oResult = mCharset;
+ return NS_OK;
+ }
+
+#if HAVE_LANGINFO_CODESET
+ //
+ // This locale appears to be a different locale from the user's locale.
+ // To do this we would need to lock the global resource we are currently
+ // using or use a library that provides multi locale support.
+ // ICU is a possible example of a multi locale library.
+ // http://oss.software.ibm.com/icu/
+ //
+ // A more common cause of hitting this warning than the above is that
+ // Mozilla is launched under an ll_CC.UTF-8 locale. In xpLocale,
+ // we only store the language and the region (ll-CC) losing 'UTF-8', which
+ // leads |mLocale| to be different from |localeName|. Although we lose
+ // 'UTF-8', we init'd |mCharset| with the value obtained via
+ // |nl_langinfo(CODESET)| so that we're all right here.
+ //
+ NS_WARNING("GetDefaultCharsetForLocale: need to add multi locale support");
+#ifdef DEBUG_jungshik
+ printf("localeName=%s mCharset=%s\n", NS_ConvertUTF16toUTF8(localeName).get(),
+ mCharset.get());
+#endif
+ // until we add multi locale support: use the the charset of the user's locale
+ oResult = mCharset;
+ return NS_SUCCESS_USING_FALLBACK_LOCALE;
+#else
+ //
+ // convert from locale to charset
+ // using the deprecated locale to charset mapping
+ //
+ NS_LossyConvertUTF16toASCII localeStr(localeName);
+ return ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oResult);
+#endif
+}
+
+nsresult
+nsPlatformCharset::InitGetCharset(nsACString &oString)
+{
+#if HAVE_LANGINFO_CODESET
+ char* nl_langinfo_codeset = nullptr;
+ nsCString aCharset;
+ nsresult res;
+
+ nl_langinfo_codeset = nl_langinfo(CODESET);
+ NS_ASSERTION(nl_langinfo_codeset, "cannot get nl_langinfo(CODESET)");
+
+ //
+ // see if we can use nl_langinfo(CODESET) directly
+ //
+ if (nl_langinfo_codeset) {
+ aCharset.Assign(nl_langinfo_codeset);
+ res = VerifyCharset(aCharset);
+ if (NS_SUCCEEDED(res)) {
+ oString = aCharset;
+ return res;
+ }
+ }
+
+ NS_ERROR("unable to use nl_langinfo(CODESET)");
+#endif
+
+ //
+ // try falling back on a deprecated (locale based) name
+ //
+ char* locale = setlocale(LC_CTYPE, nullptr);
+ nsAutoCString localeStr;
+ localeStr.Assign(locale);
+ return ConvertLocaleToCharsetUsingDeprecatedConfig(localeStr, oString);
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::Init()
+{
+ //
+ // remember default locale so we can use the
+ // same charset when asked for the same locale
+ //
+ char* locale = setlocale(LC_CTYPE, nullptr);
+ NS_ASSERTION(locale, "cannot setlocale");
+ if (locale) {
+ CopyASCIItoUTF16(locale, mLocale);
+ } else {
+ mLocale.AssignLiteral("en_US");
+ }
+
+ // InitGetCharset only returns NS_OK or NS_SUCESS_USING_FALLBACK_LOCALE
+ return InitGetCharset(mCharset);
+}
+
+nsresult
+nsPlatformCharset::VerifyCharset(nsCString &aCharset)
+{
+ // fast path for UTF-8. Most platform uses UTF-8 as charset now.
+ if (aCharset.EqualsLiteral("UTF-8")) {
+ return NS_OK;
+ }
+
+ nsAutoCString encoding;
+ if (!EncodingUtils::FindEncodingForLabelNoReplacement(aCharset, encoding)) {
+ return NS_ERROR_UCONV_NOCONV;
+ }
+
+ aCharset.Assign(encoding);
+ return NS_OK;
+}
diff --git a/intl/locale/unix/unixcharset.properties b/intl/locale/unix/unixcharset.properties
new file mode 100644
index 000000000..1376b49d6
--- /dev/null
+++ b/intl/locale/unix/unixcharset.properties
@@ -0,0 +1,536 @@
+# 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/.
+
+##
+## NOTE: THIS FILE IS DEPRECATED
+## except for those *nix systems that do not support
+## nl_langinfo(CODESET) this file should not be used
+##
+## All platform section
+## Put the general locale to charset mapping here.
+## If somehow two platform use the same locale name with different
+## charset, put the least common one in the platform specific section
+## This section have lower priority than the platform specific section
+##
+## The key is the locale name
+# AIX
+ar_AA=ISO-8859-6
+# Solaris
+Ar_ARM=ISO-8859-6
+american.iso88591=ISO-8859-1
+bulgarian=ISO-8859-2
+bg_BG.ISO8859-5=ISO-8859-5
+# AIX
+bg_BG=ISO-8859-5
+C=ISO-8859-1
+# HP
+C.iso885915=ISO-8859-15
+c-french.iso88591=ISO-8859-1
+chinese=gb18030
+chinese-s=gb18030
+chinese-t.big5=Big5
+cs=ISO-8859-2
+cs_CZ=ISO-8859-2
+cs_CZ.ISO8859-2=ISO-8859-2
+cs_CZ.88592=ISO-8859-2
+czech=ISO-8859-2
+da=ISO-8859-1
+# Solaris
+da.ISO8859-15=ISO-8859-15
+da_DK.ISO8859-15=ISO-8859-15
+da_DK.ISO8859-15@euro=ISO-8859-15
+# Solaris
+da.ISO8859-15@euro=ISO-8859-15
+da_DK.88591=ISO-8859-1
+# HP
+da_DK.iso885915@euro=ISO-8859-15
+da_DK.ISO8859-1=ISO-8859-1
+da_DK=ISO-8859-1
+# AIX
+#Da_DK=IBM-850
+danish.iso88591=ISO-8859-1
+dutch.iso88591=ISO-8859-1
+de=ISO-8859-1
+# Solaris
+de.ISO8859-15=ISO-8859-15
+# Solaris
+de.ISO8859-15@euro=ISO-8859-15
+# Solaris
+de.UTF-8=UTF-8
+# Solaris
+de.UTF-8@euro=UTF-8
+de_AT=ISO-8859-1
+# Solaris
+de_AT.ISO8859-15=ISO-8859-15
+# Solaris
+de_AT.ISO8859-15@euro=ISO-8859-15
+de_CH=ISO-8859-1
+de_CH.88591=ISO-8859-1
+de_CH.ISO8859-1=ISO-8859-1
+de_DE.ISO8859-15=ISO-8859-15
+de_DE.ISO8859-15@euro=ISO-8859-15
+# AIX
+#De_CH=IBM-850
+de_DE=ISO-8859-1
+de_DE.88591=ISO-8859-1
+# HP
+de_DE.iso885915=ISO-8859-15
+# HP
+de_DE.iso885915@euro=ISO-8859-15
+de_DE.ISO8859-1=ISO-8859-1
+# AIX
+#De_DE=IBM-850
+# Solaris
+el_GR.ISO8859-7=ISO-8859-7
+el_GR.ISO8859-7@euro=ISO-8859-7
+en_AU.ISO8859-1=ISO-8859-1
+en_CA.ISO8859-1=ISO-8859-1
+# AIX
+el_GR=ISO-8859-7
+en=ISO-8859-1
+en_AU=ISO-8859-1
+en_CA=ISO-8859-1
+en_GB=ISO-8859-1
+# Solaris
+en_GB.ISO8859-15=ISO-8859-15
+# Solaris
+en_GB.ISO8859-15@euro=ISO-8859-15
+en_GB.88591=ISO-8859-1
+en_GB.ISO8859-1=ISO-8859-1
+# HP
+en_GB.iso885915@euro=ISO-8859-15
+# AIX
+#En_GB=IBM-850
+# Solaris
+en_IE.ISO8859-1=ISO-8859-1
+en_IE.ISO8859-15=ISO-8859-15
+# Solaris
+en_IE.ISO8859-15@euro=ISO-8859-15
+en_JP=EUC-JP
+en_JP.IBM-eucJP=EUC-JP
+En_JP.IBM-932=Shift_JIS
+En_JP=Shift_JIS
+en_KR=EUC-KR
+en_KR.IBM-eucKR=EUC-KR
+en_TH=ISO-8859-1
+en_US=ISO-8859-1
+en_US.88591=ISO-8859-1
+en_US.ISO8859-1=ISO-8859-1
+#FreeBSD
+en_US.ISO_8859-1=ISO-8859-1
+da_DK.ISO_8859-1=ISO-8859-1
+de_AT.ISO_8859-1=ISO-8859-1
+de_CH.ISO_8859-1=ISO-8859-1
+de_DE.ISO_8859-1=ISO-8859-1
+en_AU.ISO_8859-1=ISO-8859-1
+en_CA.ISO_8859-1=ISO-8859-1
+en_GB.ISO_8859-1=ISO-8859-1
+es_ES.ISO_8859-1=ISO-8859-1
+fi_FI.ISO_8859-1=ISO-8859-1
+fr_BE.ISO_8859-1=ISO-8859-1
+fr_CA.ISO_8859-1=ISO-8859-1
+fr_CH.ISO_8859-1=ISO-8859-1
+fr_FR.ISO_8859-1=ISO-8859-1
+is_IS.ISO_8859-1=ISO-8859-1
+it_CH.ISO_8859-1=ISO-8859-1
+it_IT.ISO_8859-1=ISO-8859-1
+la_LN.ISO_8859-1=ISO-8859-1
+nl_BE.ISO_8859-1=ISO-8859-1
+nl_NL.ISO_8859-1=ISO-8859-1
+no_NO.ISO_8859-1=ISO-8859-1
+pt_PT.ISO_8859-1=ISO-8859-1
+sv_SE.ISO_8859-1=ISO-8859-1
+# FreeBSD 8859-15
+da_DK.DIS_8859-15=ISO-8859-15
+de_AT.DIS_8859-15=ISO-8859-15
+de_CH.DIS_8859-15=ISO-8859-15
+de_DE.DIS_8859-15=ISO-8859-15
+en_AU.DIS_8859-15=ISO-8859-15
+en_CA.DIS_8859-15=ISO-8859-15
+en_GB.DIS_8859-15=ISO-8859-15
+en_US.DIS_8859-15=ISO-8859-15
+es_ES.DIS_8859-15=ISO-8859-15
+fi_FI.DIS_8859-15=ISO-8859-15
+fr_BE.DIS_8859-15=ISO-8859-15
+fr_CA.DIS_8859-15=ISO-8859-15
+fr_CH.DIS_8859-15=ISO-8859-15
+fr_FR.DIS_8859-15=ISO-8859-15
+is_IS.DIS_8859-15=ISO-8859-15
+it_CH.DIS_8859-15=ISO-8859-15
+it_IT.DIS_8859-15=ISO-8859-15
+la_LN.DIS_8859-15=ISO-8859-15
+nl_BE.DIS_8859-15=ISO-8859-15
+nl_NL.DIS_8859-15=ISO-8859-15
+no_NO.DIS_8859-15=ISO-8859-15
+pt_PT.DIS_8859-15=ISO-8859-15
+sv_SE.DIS_8859-15=ISO-8859-15
+# FreeBSD 8859-2
+cs_CZ.ISO_8859-2=ISO-8859-2
+hr_HR.ISO_8859-2=ISO-8859-2
+hu_HU.ISO_8859-2=ISO-8859-2
+la_LN.ISO_8859-2=ISO-8859-2
+pl_PL.ISO_8859-2=ISO-8859-2
+sl_SI.ISO_8859-2=ISO-8859-2
+# FreeBSD 8859-4
+la_LN.ISO_8859-4=ISO-8859-4
+lt_LT.ISO_8859-4=ISO-8859-4
+# FreeBSD 8859-5
+ru_RU.ISO_8859-5=ISO-8859-5
+ru_SU.ISO_8859-5=ISO-8859-5
+# FreeBSD Russian
+ru_SU.KOI8-R=KOI8-R
+# FreeBSD Ukrainian
+uk_UA.KOI8-U=KOI8-U
+# Solaris
+en_US.UTF-8=UTF-8
+# Solaris
+en_US.UTF-8@euro=UTF-8
+# AIX
+#En_US=IBM-850
+english.iso88591=ISO-8859-1
+es=ISO-8859-1
+# Solaris
+es.ISO8859-15=ISO-8859-15
+# Solaris
+es.ISO8859-15@euro=ISO-8859-15
+# Solaris
+es.UTF-8=UTF-8
+# Solaris
+es.UTF-8@euro=UTF-8
+es_ES=ISO-8859-1
+es_ES.ISO8859-15=ISO-8859-15
+es_ES.ISO8859-15@euro=ISO-8859-15
+es_AR.ISO8859-1=ISO-8859-1
+es_BO.ISO8859-1=ISO-8859-1
+es_CL.ISO8859-1=ISO-8859-1
+es_CO.ISO8859-1=ISO-8859-1
+es_CR.ISO8859-1=ISO-8859-1
+es_EC.ISO8859-1=ISO-8859-1
+es_GT.ISO8859-1=ISO-8859-1
+es_MX.ISO8859-1=ISO-8859-1
+es_NI.ISO8859-1=ISO-8859-1
+es_PA.ISO8859-1=ISO-8859-1
+es_PE.ISO8859-1=ISO-8859-1
+es_PY.ISO8859-1=ISO-8859-1
+es_SV.ISO8859-1=ISO-8859-1
+es_UY.ISO8859-1=ISO-8859-1
+es_VE.ISO8859-1=ISO-8859-1
+# HP
+es_ES.iso885915=ISO-8859-15
+# HP
+es_ES.iso885915@euro=ISO-8859-15
+es_ES.88591=ISO-8859-1
+es_ES.ISO8859-1=ISO-8859-1
+# AIX
+#En_ES=IBM-850
+# Solaris
+et_EE.ISO8859-15=ISO-8859-15
+# AIX
+#Et_ET=IBM-922
+# AIX
+ET_ET=UTF-8
+fi=ISO-8859-1
+# Solaris
+fi.ISO8859-15=ISO-8859-15
+# Solaris
+fi.ISO8859-15@euro=ISO-8859-15
+fi_FI=ISO-8859-1
+fi_FI.88591=ISO-8859-1
+fi_FI.ISO8859-1=ISO-8859-1
+fi_FI.ISO8859-15=ISO-8859-15
+fi_FI.ISO8859-15@euro=ISO-8859-15
+# HP
+fi_FI.iso885915@euro=ISO-8859-15
+# AIX
+#Fi_ES=IBM-850
+finnish.iso88591=ISO-8859-1
+fr=ISO-8859-1
+# Solaris
+fr.ISO8859-15=ISO-8859-15
+# Solaris
+fr.ISO8859-15@euro=ISO-8859-15
+# Solaris
+fr.UTF-8=UTF-8
+# Solaris
+fr.UTF-8@euro=UTF-8
+fr_BE=ISO-8859-1
+# Solaris
+fr_BE.ISO8859-15=ISO-8859-15
+# Solaris
+fr_BE.ISO8859-15@euro=ISO-8859-15
+fr_BE.88591=ISO-8859-1
+fr_BE.ISO8859-1=ISO-8859-1
+fr_BE.iso8859=ISO-8859-1
+# AIX
+#Fr_BE=IBM-850
+fr_CA=ISO-8859-1
+fr_CA.88591=ISO-8859-1
+fr_CA.iso8859=ISO-8859-1
+# HP
+fr_CA.iso885915@euro=ISO-8859-15
+fr_CA.ISO8859-1=ISO-8859-1
+# AIX
+#Fr_CA=IBM-850
+fr_CH=ISO-8859-1
+fr_CH.88591=ISO-8859-1
+fr_CH.iso8859=ISO-8859-1
+fr_CH.ISO8859-1=ISO-8859-1
+# Solaris
+fr_FR.ISO8859-15=ISO-8859-15
+fr_FR.ISO8859-15@euro=ISO-8859-15
+# AIX
+#Fr_CH=IBM-850
+fr_FR=ISO-8859-1
+fr_FR.88591=ISO-8859-1
+fr_FR.iso8859=ISO-8859-1
+# HP
+fr_FR.iso885915=ISO-8859-15
+# HP
+fr_FR.iso885915@euro=ISO-8859-15
+fr_FR.ISO8859-1=ISO-8859-1
+# AIX
+#Fr_FR=IBM-850
+french.iso88591=ISO-8859-1
+german.iso88591=ISO-8859-1
+# Solaris
+he_HE=ISO-8859-8
+he_IL=ISO-8859-8
+hr_HR.ISO8859-2=ISO-8859-2
+# AIX
+hr_HR=ISO-8859-2
+hu_HU=ISO-8859-2
+hu_HU.88592=ISO-8859-2
+hu_HU.ISO8859-2=ISO-8859-2
+hungarian=ISO-8859-2
+icelandic.iso88591=ISO-8859-1
+iso_8859_1=ISO-8859-1
+is=ISO-8859-1
+is_IS=ISO-8859-1
+is_IS.88591=ISO-8859-1
+is_IS.ISO8859-1=ISO-8859-1
+# HP
+is_IS.iso885915@euro=ISO-8859-15
+# AIX
+#Is_IS=IBM-850
+it=ISO-8859-1
+# Solaris
+it.ISO8859-15=ISO-8859-15
+# Solaris
+it.ISO8859-15@euro=ISO-8859-15
+# Solaris
+it.UTF-8=UTF-8
+# Solaris
+it.UTF-8@euro=UTF-8
+it_IT.ISO8859-15=ISO-8859-15
+it_IT.ISO8859-15@euro=ISO-8859-15
+# AIX
+#It_IT=IBM-850
+italian.iso8859-1=ISO-8859-1
+it_CH=ISO-8859-1
+it_IT=ISO-8859-1
+it_IT.88591=ISO-8859-1
+it_IT.ISO8859-1=ISO-8859-1
+# HP
+it_IT.iso885915=ISO-8859-15
+# HP
+it_IT.iso885915@euro=ISO-8859-15
+# AIX
+iw_IL=ISO-8859-8
+# AIX
+#Iw_IL=IBM-856
+ja=EUC-JP
+Ja_JP.IBM-932=Shift_JIS
+Ja_JP=Shift_JIS
+japanese=EUC-JP
+japanese.euc=EUC-JP
+ja_JP=EUC-JP
+# Solaris
+ja_JP.UTF-8=UTF-8
+# Solaris
+ja_JP.UTF-8@euro=UTF-8
+ja_JP.EUC=EUC-JP
+ja_JP.eucJP=EUC-JP
+ja_JP.SJIS=Shift_JIS
+ja_JP.PCK=Shift_JIS
+ja_JP.IBM-eucJP=EUC-JP
+ja_JP.mscode=Shift_JIS
+ja_JP.ujis=EUC-JP
+katakana=Shift_JIS
+ko=EUC-KR
+ko_KR=EUC-KR
+# Solaris
+ko_KR.UTF-8=UTF-8
+# Solaris
+ko_KR.UTF-8@euro=UTF-8
+ko_KR.euc=EUC-KR
+ko_KR.euckr=EUC-KR
+ko_KR.eucKR=EUC-KR
+ko_KR.IBM-eucKR=EUC-KR
+ko_KR.EUC=EUC-KR
+ko.UTF-8=UTF-8
+korean=EUC-KR
+# Solaris
+lt_LT.ISO8859-13=ISO-8859-13
+# AIX
+#Lt_LT=IBM-921
+# AIX
+LT_LT=UTF-8
+# Solaris
+lv_LV.ISO8859-13=ISO-8859-13
+# AIX
+#Lt_LV=IBM-921
+# AIX
+LT_LV=UTF-8
+# Solaris
+mk_MK.ISO8859-5=ISO-8859-5
+# AIX
+mk_MK=ISO-8859-5
+nl=ISO-8859-1
+# Solaris
+nl.ISO8859-15=ISO-8859-15
+# Solaris
+nl.ISO8859-15@euro=ISO-8859-15
+nl_BE=ISO-8859-1
+# Solaris
+nl_BE.ISO8859-15=ISO-8859-15
+# Solaris
+nl_BE.ISO8859-15@euro=ISO-8859-15
+nl_BE.88591=ISO-8859-1
+nl_BE.ISO8859-1=ISO-8859-1
+# Solaris
+nl_NL.ISO8859-15=ISO-8859-15
+nl_NL.ISO8859-15@euro=ISO-8859-15
+# AIX
+#NL_BE=IBM-850
+nl_NL=ISO-8859-1
+nl_NL.88591=ISO-8859-1
+nl_NL.ISO8859-1=ISO-8859-1
+# HP
+nl_NL.iso885915@euro=ISO-8859-15
+# AIX
+#NL_NL=IBM-850
+no=ISO-8859-1
+no_NO=ISO-8859-1
+no_NO.88591=ISO-8859-1
+no_NO.ISO8859-1=ISO-8859-1
+# Solaris
+no_NO.ISO8859-1@bokmal=ISO-8859-1
+no_NO.ISO8859-1@nynorsk=ISO-8859-1
+# HP
+no_NO.iso885915@euro=ISO-8859-15
+# AIX
+#No_NO=IBM-850
+norwegian.iso88591=ISO-8859-1
+pl=ISO-8859-2
+pl_PL=ISO-8859-2
+pl_PL.88592=ISO-8859-2
+pl_PL.ISO8859-2=ISO-8859-2
+polish=ISO-8859-2
+portuguese.iso88591=ISO-8859-1
+pt=ISO-8859-1
+# Solaris
+pt.ISO8859-15=ISO-8859-15
+# Solaris
+pt.ISO8859-15@euro=ISO-8859-15
+# Solaris
+pt_BR.ISO8859-1=ISO-8859-1
+pt_PT.ISO8859-15=ISO-8859-15
+pt_PT.ISO8859-15@euro=ISO-8859-15
+# AIX
+#Pt.PT=IBM-850
+pt_PT=ISO-8859-1
+pt_PT.88591=ISO-8859-1
+# HP
+pt_PT.iso885915@euro=ISO-8859-15
+pt_PT.ISO8859-1=ISO-8859-1
+# Solaris
+ro_RO.ISO8859-2=ISO-8859-2
+# AIX
+ro_RO=ISO-8859-5
+# Solaris
+#ru_RU.ANSI1251= ??? ANSI-1251 ???
+ru_RU.ISO8859-5=ISO-8859-5
+# AIX
+ru_RU=ISO-8859-5
+ru_RU.KOI8-R=KOI8-R
+# RedHat 7 reported by Garaschenko Slava <slava@maze.ambernet.kiev.ua bug 70601
+ru_RU.koi8r=KOI8-R
+# RedHat 7 reported by Garaschenko Slava <slava@maze.ambernet.kiev.ua bug 70601
+ru_UA=KOI8-U
+rumanian=ISO-8859-2
+serbocroatian=ISO-8859-2
+sh=ISO-8859-2
+# Solaris
+sh_BA.ISO8859-2@bosnia=ISO-8859-2
+sl_SI.ISO8859-2=ISO-8859-2
+sq_AL.ISO8859-2=ISO-8859-2
+# AIX
+sh_SP=ISO-8859-2
+sk=ISO-8859-2
+sk_SK=ISO-8859-2
+sk_SK.88592=ISO-8859-2
+sk_SK.ISO8859-2=ISO-8859-2
+slovene=ISO-8859-2
+spanish.iso88591=ISO-8859-1
+# AIX
+sq_AL=ISO-8859-1
+# Solaris
+sr_YU.ISO8859-5=ISO-8859-5
+# AIX
+sr_SP=ISO-8859-5
+sv=ISO-8859-1
+# Solaris
+sv.ISO8859-15=ISO-8859-15
+# Solaris
+sv.ISO8859-15@euro=ISO-8859-15
+# Solaris
+sv.UTF-8=UTF-8
+# Solaris
+sv.UTF-8@euro=UTF-8
+sv_SE=ISO-8859-1
+sv_SE.88591=ISO-8859-1
+sv_SE.ISO8859-15=ISO-8859-15
+sv_SE.ISO8859-15@euro=ISO-8859-15
+# HP
+sv_SE.iso885915=ISO-8859-15
+# HP
+sv_SE.iso885915@euro=ISO-8859-15
+sv_SE.ISO8859-1=ISO-8859-1
+# AIX
+swedish.iso88591=ISO-8859-1
+# Solaris
+tr_TR.ISO8859-9=windows-1254
+# AIX
+tr_TR=windows-1254
+# Solaris
+th_TH=windows-874
+th_TH.TIS620=windows-874
+th=windows-874
+th_TH.UTF-8=UTF-8
+# RedHat 7 reported by Garaschenko Slava <slava@maze.ambernet.kiev.ua bug 70601
+uk_UA=KOI8-U
+zh=gb18030
+zh_CN=gb18030
+zh_CN.EUC=gb18030
+zh.GBK=gbk
+zh_CN.UTF-8=UTF-8
+zh.UTF-8=UTF-8
+zh_TW.BIG5=Big5
+# saw the following name from news://xcin.linux.org.tw/tlug.cle-devel
+zh_CN.gb18030=gb18030
+# AIX
+ZH_CN=UTF-8
+zh_CN.ugb=gb18030
+zh_CN.GBK=gbk
+zh_HK.big5=Big5
+zh_TW.big5=Big5
+zh_TW.big5@chuyin=Big5
+zh_TW.big5@radical=Big5
+zh_TW.big5@stroke=Big5
+# AIX
+Zh_TW.big5=Big5
+# CLE 0.8
+zh_TW.Big5=Big5
+# SunOS 5.7 according to pofeng@linux.org.tw (already above)
+# zh_TW.BIG5=Big5
diff --git a/intl/locale/windows/moz.build b/intl/locale/windows/moz.build
new file mode 100644
index 000000000..5bde38b89
--- /dev/null
+++ b/intl/locale/windows/moz.build
@@ -0,0 +1,26 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SOURCES += [
+ 'nsCollationWin.cpp',
+ 'nsDateTimeFormatWin.cpp',
+ 'nsWin32Locale.cpp',
+ 'nsWinCharset.cpp',
+]
+
+FINAL_LIBRARY = 'xul'
+
+GENERATED_FILES = [
+ 'wincharset.properties.h',
+]
+wincharset = GENERATED_FILES['wincharset.properties.h']
+wincharset.script = '../props2arrays.py'
+wincharset.inputs = ['wincharset.properties']
+
+LOCAL_INCLUDES += [
+ '..',
+]
+
diff --git a/intl/locale/windows/nsCollationWin.cpp b/intl/locale/windows/nsCollationWin.cpp
new file mode 100644
index 000000000..8dcdb8f07
--- /dev/null
+++ b/intl/locale/windows/nsCollationWin.cpp
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+
+#include "nsCollationWin.h"
+#include "nsIServiceManager.h"
+#include "nsIComponentManager.h"
+#include "nsILocaleService.h"
+#include "nsIPlatformCharset.h"
+#include "nsWin32Locale.h"
+#include "nsCOMPtr.h"
+#include "prmem.h"
+#include "plstr.h"
+#include <windows.h>
+
+#undef CompareString
+
+NS_IMPL_ISUPPORTS(nsCollationWin, nsICollation)
+
+
+nsCollationWin::nsCollationWin() : mCollation(nullptr)
+{
+}
+
+nsCollationWin::~nsCollationWin()
+{
+ if (mCollation)
+ delete mCollation;
+}
+
+nsresult nsCollationWin::Initialize(nsILocale* locale)
+{
+ NS_ASSERTION(!mCollation, "Should only be initialized once.");
+
+ nsresult res;
+
+ mCollation = new nsCollation;
+
+ // default LCID (en-US)
+ mLCID = 1033;
+
+ nsAutoString localeStr;
+
+ // get locale string, use app default if no locale specified
+ if (!locale) {
+ nsCOMPtr<nsILocaleService> localeService =
+ do_GetService(NS_LOCALESERVICE_CONTRACTID);
+ if (localeService) {
+ nsCOMPtr<nsILocale> appLocale;
+ res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
+ if (NS_SUCCEEDED(res)) {
+ res = appLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"),
+ localeStr);
+ }
+ }
+ }
+ else {
+ res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_COLLATE"),
+ localeStr);
+ }
+
+ // Get LCID and charset name from locale, if available
+ LCID lcid;
+ res = nsWin32Locale::GetPlatformLocale(localeStr, &lcid);
+ if (NS_SUCCEEDED(res)) {
+ mLCID = lcid;
+ }
+
+ nsCOMPtr <nsIPlatformCharset> platformCharset =
+ do_GetService(NS_PLATFORMCHARSET_CONTRACTID);
+ if (platformCharset) {
+ nsAutoCString mappedCharset;
+ res = platformCharset->GetDefaultCharsetForLocale(localeStr, mappedCharset);
+ if (NS_SUCCEEDED(res)) {
+ mCollation->SetCharset(mappedCharset.get());
+ }
+ }
+
+ return NS_OK;
+}
+
+
+NS_IMETHODIMP nsCollationWin::CompareString(int32_t strength,
+ const nsAString & string1,
+ const nsAString & string2,
+ int32_t *result)
+{
+ int retval;
+ nsresult res;
+ DWORD dwMapFlags = 0;
+
+ if (strength == kCollationCaseInSensitive)
+ dwMapFlags |= NORM_IGNORECASE;
+
+ retval = ::CompareStringW(mLCID,
+ dwMapFlags,
+ (LPCWSTR) PromiseFlatString(string1).get(),
+ -1,
+ (LPCWSTR) PromiseFlatString(string2).get(),
+ -1);
+ if (retval) {
+ res = NS_OK;
+ *result = retval - 2;
+ } else {
+ res = NS_ERROR_FAILURE;
+ }
+
+ return res;
+}
+
+
+nsresult nsCollationWin::AllocateRawSortKey(int32_t strength,
+ const nsAString& stringIn, uint8_t** key, uint32_t* outLen)
+{
+ int byteLen;
+ void *buffer;
+ nsresult res = NS_OK;
+ DWORD dwMapFlags = LCMAP_SORTKEY;
+
+ if (strength == kCollationCaseInSensitive)
+ dwMapFlags |= NORM_IGNORECASE;
+
+ byteLen = LCMapStringW(mLCID, dwMapFlags,
+ (LPCWSTR) PromiseFlatString(stringIn).get(),
+ -1, nullptr, 0);
+ buffer = PR_Malloc(byteLen);
+ if (!buffer) {
+ res = NS_ERROR_OUT_OF_MEMORY;
+ } else {
+ *key = (uint8_t *)buffer;
+ *outLen = LCMapStringW(mLCID, dwMapFlags,
+ (LPCWSTR) PromiseFlatString(stringIn).get(),
+ -1, (LPWSTR) buffer, byteLen);
+ }
+ return res;
+}
+
+nsresult nsCollationWin::CompareRawSortKey(const uint8_t* key1, uint32_t len1,
+ const uint8_t* key2, uint32_t len2,
+ int32_t* result)
+{
+ *result = PL_strcmp((const char *)key1, (const char *)key2);
+ return NS_OK;
+}
diff --git a/intl/locale/windows/nsCollationWin.h b/intl/locale/windows/nsCollationWin.h
new file mode 100644
index 000000000..901211344
--- /dev/null
+++ b/intl/locale/windows/nsCollationWin.h
@@ -0,0 +1,35 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+#ifndef nsCollationWin_h__
+#define nsCollationWin_h__
+
+
+#include "nsICollation.h"
+#include "nsCollation.h" // static library
+#include "plstr.h"
+
+
+
+class nsCollationWin final : public nsICollation {
+ ~nsCollationWin();
+
+protected:
+ nsCollation *mCollation; // XP collation class
+ uint32_t mLCID; // Windows platform locale ID
+
+public:
+ nsCollationWin();
+
+ // nsISupports interface
+ NS_DECL_ISUPPORTS
+
+ // nsICollation interface
+ NS_DECL_NSICOLLATION
+
+};
+
+#endif /* nsCollationWin_h__ */
diff --git a/intl/locale/windows/nsDateTimeFormatWin.cpp b/intl/locale/windows/nsDateTimeFormatWin.cpp
new file mode 100644
index 000000000..f65868e1b
--- /dev/null
+++ b/intl/locale/windows/nsDateTimeFormatWin.cpp
@@ -0,0 +1,253 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "nsDateTimeFormatWin.h"
+#include "nsIServiceManager.h"
+#include "nsIComponentManager.h"
+#include "nsILocaleService.h"
+#include "nsWin32Locale.h"
+#include "nsUnicharUtils.h"
+#include "nsCRT.h"
+#include "nsCOMPtr.h"
+
+
+#define NSDATETIMEFORMAT_BUFFER_LEN 80
+
+NS_IMPL_ISUPPORTS(nsDateTimeFormatWin, nsIDateTimeFormat)
+
+
+// init this interface to a specified locale
+nsresult nsDateTimeFormatWin::Initialize(nsILocale* locale)
+{
+ nsAutoString localeStr;
+ nsresult res = NS_OK;
+
+ // use cached info if match with stored locale
+ if (!locale) {
+ if (!mLocale.IsEmpty() &&
+ mLocale.Equals(mAppLocale, nsCaseInsensitiveStringComparator())) {
+ return NS_OK;
+ }
+ }
+ else {
+ res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), localeStr);
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ if (!mLocale.IsEmpty() &&
+ mLocale.Equals(localeStr, nsCaseInsensitiveStringComparator())) {
+ return NS_OK;
+ }
+ }
+ }
+
+ // default LCID (en-US)
+ mLCID = 1033;
+
+ // get locale string, use app default if no locale specified
+ if (!locale) {
+ nsCOMPtr<nsILocaleService> localeService =
+ do_GetService(NS_LOCALESERVICE_CONTRACTID);
+ if (localeService) {
+ nsCOMPtr<nsILocale> appLocale;
+ res = localeService->GetApplicationLocale(getter_AddRefs(appLocale));
+ if (NS_SUCCEEDED(res)) {
+ res = appLocale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"),
+ localeStr);
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ mAppLocale.Assign(localeStr); // cache app locale name
+ }
+ }
+ }
+ }
+ else {
+ res = locale->GetCategory(NS_LITERAL_STRING("NSILOCALE_TIME"), localeStr);
+ }
+
+ // Get LCID and charset name from locale, if available
+ if (NS_SUCCEEDED(res) && !localeStr.IsEmpty()) {
+ mLocale.Assign(localeStr); // cache locale name
+ res = nsWin32Locale::GetPlatformLocale(mLocale, (LCID *) &mLCID);
+ }
+
+ return res;
+}
+
+// performs a locale sensitive date formatting operation on the time_t parameter
+nsresult nsDateTimeFormatWin::FormatTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const time_t timetTime,
+ nsAString& stringOut)
+{
+ return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, localtime( &timetTime ), stringOut);
+}
+
+// performs a locale sensitive date formatting operation on the struct tm parameter
+nsresult nsDateTimeFormatWin::FormatTMTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const struct tm* tmTime,
+ nsAString& stringOut)
+{
+ SYSTEMTIME system_time;
+ DWORD dwFlags_Date = 0, dwFlags_Time = 0;
+ int dateLen, timeLen;
+ char16_t dateBuffer[NSDATETIMEFORMAT_BUFFER_LEN], timeBuffer[NSDATETIMEFORMAT_BUFFER_LEN];
+
+ // set up locale data
+ (void) Initialize(locale);
+
+ // Map tm to SYSTEMTIME
+ system_time.wYear = 1900 + tmTime->tm_year;
+ system_time.wMonth = tmTime->tm_mon + 1;
+ system_time.wDayOfWeek = tmTime->tm_wday;
+ system_time.wDay = tmTime->tm_mday;
+ system_time.wHour = tmTime->tm_hour;
+ system_time.wMinute = tmTime->tm_min;
+ system_time.wSecond = tmTime->tm_sec;
+ system_time.wMilliseconds = 0;
+
+ // Map to WinAPI date format
+ switch (dateFormatSelector) {
+ case kDateFormatLong:
+ dwFlags_Date = DATE_LONGDATE;
+ break;
+ case kDateFormatShort:
+ dwFlags_Date = DATE_SHORTDATE;
+ break;
+ case kDateFormatWeekday:
+ dwFlags_Date = 0;
+ break;
+ case kDateFormatYearMonth:
+ dwFlags_Date = 0; // TODO:only availabe NT5
+ break;
+ }
+
+ // Map to WinAPI time format
+ switch (timeFormatSelector) {
+ case kTimeFormatSeconds:
+ dwFlags_Time = 0;
+ break;
+ case kTimeFormatNoSeconds:
+ dwFlags_Time = TIME_NOSECONDS;
+ break;
+ case kTimeFormatSecondsForce24Hour:
+ dwFlags_Time = TIME_FORCE24HOURFORMAT;
+ break;
+ case kTimeFormatNoSecondsForce24Hour:
+ dwFlags_Time = TIME_NOSECONDS + TIME_FORCE24HOURFORMAT;
+ break;
+ }
+
+ // Call GetDateFormatW
+ if (dateFormatSelector == kDateFormatNone) {
+ dateLen = 0;
+ }
+ else {
+ if (dateFormatSelector == kDateFormatYearMonth) {
+ dateLen = nsGetDateFormatW(0, &system_time, "yyyy/MM",
+ dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN);
+ }
+ else if (dateFormatSelector == kDateFormatWeekday) {
+ dateLen = nsGetDateFormatW(0, &system_time, "ddd",
+ dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN);
+ }
+ else {
+ dateLen = nsGetDateFormatW(dwFlags_Date, &system_time, nullptr,
+ dateBuffer, NSDATETIMEFORMAT_BUFFER_LEN);
+ }
+ if (dateLen != 0) {
+ dateLen--; // Since the count includes the terminating null.
+ }
+ }
+
+ // Call GetTimeFormatW
+ if (timeFormatSelector == kTimeFormatNone) {
+ timeLen = 0;
+ }
+ else {
+ timeLen = nsGetTimeFormatW(dwFlags_Time, &system_time, nullptr,
+ timeBuffer, NSDATETIMEFORMAT_BUFFER_LEN);
+ if (timeLen != 0) {
+ timeLen--; // Since the count includes the terminating null.
+ }
+ }
+
+ NS_ASSERTION(NSDATETIMEFORMAT_BUFFER_LEN >= (uint32_t) (dateLen + 1), "internal date buffer is not large enough");
+ NS_ASSERTION(NSDATETIMEFORMAT_BUFFER_LEN >= (uint32_t) (timeLen + 1), "internal time buffer is not large enough");
+
+ // Copy the result
+ stringOut.Truncate();
+ if (dateLen != 0 && timeLen != 0) {
+ stringOut.Assign(dateBuffer, dateLen);
+ stringOut.Append((char16_t *)(L" "), 1);
+ stringOut.Append(timeBuffer, timeLen);
+ }
+ else if (dateLen != 0 && timeLen == 0) {
+ stringOut.Assign(dateBuffer, dateLen);
+ }
+ else if (dateLen == 0 && timeLen != 0) {
+ stringOut.Assign(timeBuffer, timeLen);
+ }
+
+ return NS_OK;
+}
+
+// performs a locale sensitive date formatting operation on the PRTime parameter
+nsresult nsDateTimeFormatWin::FormatPRTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRTime prTime,
+ nsAString& stringOut)
+{
+ PRExplodedTime explodedTime;
+ PR_ExplodeTime(prTime, PR_LocalTimeParameters, &explodedTime);
+
+ return FormatPRExplodedTime(locale, dateFormatSelector, timeFormatSelector, &explodedTime, stringOut);
+}
+
+// performs a locale sensitive date formatting operation on the PRExplodedTime parameter
+nsresult nsDateTimeFormatWin::FormatPRExplodedTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRExplodedTime* explodedTime,
+ nsAString& stringOut)
+{
+ struct tm tmTime;
+ memset( &tmTime, 0, sizeof(tmTime) );
+
+ tmTime.tm_yday = explodedTime->tm_yday;
+ tmTime.tm_wday = explodedTime->tm_wday;
+ tmTime.tm_year = explodedTime->tm_year;
+ tmTime.tm_year -= 1900;
+ tmTime.tm_mon = explodedTime->tm_month;
+ tmTime.tm_mday = explodedTime->tm_mday;
+ tmTime.tm_hour = explodedTime->tm_hour;
+ tmTime.tm_min = explodedTime->tm_min;
+ tmTime.tm_sec = explodedTime->tm_sec;
+
+ return FormatTMTime(locale, dateFormatSelector, timeFormatSelector, &tmTime, stringOut);
+}
+
+int nsDateTimeFormatWin::nsGetTimeFormatW(DWORD dwFlags, const SYSTEMTIME *lpTime,
+ const char* format, char16_t *timeStr, int cchTime)
+{
+ int len = 0;
+ len = GetTimeFormatW(mLCID, dwFlags, lpTime,
+ format ?
+ NS_ConvertASCIItoUTF16(format).get() :
+ nullptr,
+ (LPWSTR) timeStr, cchTime);
+ return len;
+}
+
+int nsDateTimeFormatWin::nsGetDateFormatW(DWORD dwFlags, const SYSTEMTIME *lpDate,
+ const char* format, char16_t *dateStr, int cchDate)
+{
+ int len = 0;
+ len = GetDateFormatW(mLCID, dwFlags, lpDate,
+ format ? NS_ConvertASCIItoUTF16(format).get() : nullptr,
+ (LPWSTR) dateStr, cchDate);
+ return len;
+}
diff --git a/intl/locale/windows/nsDateTimeFormatWin.h b/intl/locale/windows/nsDateTimeFormatWin.h
new file mode 100644
index 000000000..1c84492ee
--- /dev/null
+++ b/intl/locale/windows/nsDateTimeFormatWin.h
@@ -0,0 +1,71 @@
+
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * 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/. */
+#ifndef nsDateTimeFormatWin_h__
+#define nsDateTimeFormatWin_h__
+
+
+#include "nsIDateTimeFormat.h"
+#include <windows.h>
+
+
+// Locale sensitive date and time format interface
+//
+class nsDateTimeFormatWin : public nsIDateTimeFormat {
+ virtual ~nsDateTimeFormatWin() {}
+
+public:
+ NS_DECL_THREADSAFE_ISUPPORTS
+
+ // performs a locale sensitive date formatting operation on the time_t parameter
+ NS_IMETHOD FormatTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const time_t timetTime,
+ nsAString& stringOut);
+
+ // performs a locale sensitive date formatting operation on the struct tm parameter
+ NS_IMETHOD FormatTMTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const struct tm* tmTime,
+ nsAString& stringOut);
+
+ // performs a locale sensitive date formatting operation on the PRTime parameter
+ NS_IMETHOD FormatPRTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRTime prTime,
+ nsAString& stringOut);
+
+ // performs a locale sensitive date formatting operation on the PRExplodedTime parameter
+ NS_IMETHOD FormatPRExplodedTime(nsILocale* locale,
+ const nsDateFormatSelector dateFormatSelector,
+ const nsTimeFormatSelector timeFormatSelector,
+ const PRExplodedTime* explodedTime,
+ nsAString& stringOut);
+
+ nsDateTimeFormatWin() {mLocale.SetLength(0);mAppLocale.SetLength(0);}
+
+
+private:
+ // init this interface to a specified locale
+ NS_IMETHOD Initialize(nsILocale* locale);
+
+ // call GetTimeFormatW or TimeFormatA
+ int nsGetTimeFormatW(DWORD dwFlags, const SYSTEMTIME *lpTime,
+ const char* format, char16_t *timeStr, int cchTime);
+
+ // call GetDateFormatW or GetDateFormatA
+ int nsGetDateFormatW(DWORD dwFlags, const SYSTEMTIME *lpDate,
+ const char* format, char16_t *dateStr, int cchDate);
+
+ nsString mLocale;
+ nsString mAppLocale;
+ uint32_t mLCID; // Windows platform locale ID
+};
+
+#endif /* nsDateTimeFormatWin_h__ */
diff --git a/intl/locale/windows/nsWin32Locale.cpp b/intl/locale/windows/nsWin32Locale.cpp
new file mode 100644
index 000000000..8a66d2c64
--- /dev/null
+++ b/intl/locale/windows/nsWin32Locale.cpp
@@ -0,0 +1,748 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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/. */
+
+#include "mozilla/ArrayUtils.h"
+
+#include "nscore.h"
+#include "nsString.h"
+#include "nsXPCOMStrings.h"
+#include "nsReadableUtils.h"
+#include "nsWin32Locale.h"
+#include "prprf.h"
+#include <windows.h>
+#include "nsCRT.h"
+
+using namespace mozilla;
+
+struct iso_pair
+{
+ const char* iso_code;
+ DWORD win_code;
+};
+
+struct iso_map
+{
+ const char* iso_code;
+ DWORD win_code;
+ iso_pair sublang_list[20];
+};
+
+nsWin32Locale::LocaleNameToLCIDPtr nsWin32Locale::localeNameToLCID = nullptr;
+nsWin32Locale::LCIDToLocaleNamePtr nsWin32Locale::lcidToLocaleName = nullptr;
+
+// Older versions of VC++ and Win32 SDK and mingw don't have
+// macros for languages and sublanguages recently added to Win32.
+// see http://www.tug.org/ftp/tex/texinfo/intl/localename.c
+
+#ifndef LANG_URDU
+#define LANG_URDU 0x20
+#endif
+#ifndef LANG_ARMENIAN
+#define LANG_ARMENIAN 0x2b
+#endif
+#ifndef LANG_AZERI
+#define LANG_AZERI 0x2c
+#endif
+#ifndef LANG_MACEDONIAN
+#define LANG_MACEDONIAN 0x2f
+#endif
+#ifndef LANG_GEORGIAN
+#define LANG_GEORGIAN 0x37
+#endif
+#ifndef LANG_HINDI
+#define LANG_HINDI 0x39
+#endif
+#ifndef LANG_MALAY
+#define LANG_MALAY 0x3e
+#endif
+#ifndef LANG_KAZAK
+#define LANG_KAZAK 0x3f
+#endif
+#ifndef LANG_KYRGYZ
+#define LANG_KYRGYZ 0x40
+#endif
+#ifndef LANG_SWAHILI
+#define LANG_SWAHILI 0x41
+#endif
+#ifndef LANG_UZBEK
+#define LANG_UZBEK 0x43
+#endif
+#ifndef LANG_TATAR
+#define LANG_TATAR 0x44
+#endif
+#ifndef LANG_PUNJABI
+#define LANG_PUNJABI 0x46
+#endif
+#ifndef LANG_GUJARAT
+#define LANG_GUJARAT 0x47
+#endif
+#ifndef LANG_TAMIL
+#define LANG_TAMIL 0x49
+#endif
+#ifndef LANG_TELUGU
+#define LANG_TELUGU 0x4a
+#endif
+#ifndef LANG_KANNADA
+#define LANG_KANNADA 0x4b
+#endif
+#ifndef LANG_MARATHI
+#define LANG_MARATHI 0x4e
+#endif
+#ifndef LANG_SANSKRIT
+#define LANG_SANSKRIT 0x4f
+#endif
+#ifndef LANG_MONGOLIAN
+#define LANG_MONGOLIAN 0x50
+#endif
+#ifndef LANG_GALICIAN
+#define LANG_GALICIAN 0x56
+#endif
+#ifndef LANG_KONKANI
+#define LANG_KONKANI 0x57
+#endif
+#ifndef LANG_DIVEHI
+#define LANG_DIVEHI 0x65
+#endif
+
+#ifndef SUBLANG_MALAY_MALAYSIA
+#define SUBLANG_MALAY_MALAYSIA 0x01
+#endif
+#ifndef SUBLANG_MALAY_BRUNEI_DARUSSALAM
+#define SUBLANG_MALAY_BRUNEI_DARUSSALAM 0x02
+#endif
+#ifndef SUBLANG_CHINESE_MACAU
+#define SUBLANG_CHINESE_MACAU 0x05
+#endif
+#ifndef SUBLANG_FRENCH_MONACO
+#define SUBLANG_FRENCH_MONACO 0x06
+#endif
+#ifndef SUBLANG_ENGLISH_ZIMBABWE
+#define SUBLANG_ENGLISH_ZIMBABWE 0x0c
+#endif
+#ifndef SUBLANG_ENGLISH_PHILIPPINES
+#define SUBLANG_ENGLISH_PHILIPPINES 0x0d
+#endif
+
+
+//
+// This list is used to map between ISO language
+// References :
+// http://www.iso.ch/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html
+// http://www.loc.gov/standards/iso639-2/
+// http://www.ethnologue.com/
+// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_19ir.asp
+// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/intl/nls_61df.asp
+
+static const
+iso_map iso_list[] =
+{
+ {"af", LANG_AFRIKAANS, {
+ { "ZA", SUBLANG_DEFAULT },
+ { "",0}}
+ },
+ { "ar", LANG_ARABIC, {
+ { "SA", SUBLANG_ARABIC_SAUDI_ARABIA },
+ { "IQ", SUBLANG_ARABIC_IRAQ },
+ { "EG", SUBLANG_ARABIC_EGYPT },
+ { "LY", SUBLANG_ARABIC_LIBYA },
+ { "DZ", SUBLANG_ARABIC_ALGERIA },
+ { "MA", SUBLANG_ARABIC_MOROCCO },
+ { "TN", SUBLANG_ARABIC_TUNISIA },
+ { "OM", SUBLANG_ARABIC_OMAN },
+ { "YE", SUBLANG_ARABIC_YEMEN },
+ { "SY", SUBLANG_ARABIC_SYRIA },
+ { "JO", SUBLANG_ARABIC_JORDAN },
+ { "LB", SUBLANG_ARABIC_LEBANON },
+ { "KW", SUBLANG_ARABIC_KUWAIT },
+ { "AE", SUBLANG_ARABIC_UAE },
+ { "BH", SUBLANG_ARABIC_BAHRAIN },
+ { "QA", SUBLANG_ARABIC_QATAR },
+ {"",0}}
+ },
+ {"az", LANG_AZERI, {
+ { "AZ",SUBLANG_DEFAULT }, // XXX Latin vs Cyrillic vs Arabic
+ { "",0}}
+ },
+ {"be", LANG_BELARUSIAN, {
+ { "BY",SUBLANG_DEFAULT },
+ { "",0}}
+ },
+ {"bg", LANG_BULGARIAN, {
+ { "BG", SUBLANG_DEFAULT },
+ { "",0}}
+ },
+ {"ca", LANG_CATALAN, {
+ { "ES", SUBLANG_DEFAULT},
+ { "",0}}
+ },
+ {"cs", LANG_CZECH, {
+ { "CZ", SUBLANG_DEFAULT},
+ {"",0}}
+ },
+ { "da", LANG_DANISH, {
+ { "DK", SUBLANG_DEFAULT },
+ { "",0}}
+ },
+ { "de", LANG_GERMAN, {
+ { "DE", SUBLANG_GERMAN },
+ { "CH", SUBLANG_GERMAN_SWISS },
+ { "AT", SUBLANG_GERMAN_AUSTRIAN },
+ { "LU", SUBLANG_GERMAN_LUXEMBOURG },
+ { "LI", SUBLANG_GERMAN_LIECHTENSTEIN },
+ { "" , 0}}
+ },
+ {"dv", LANG_DIVEHI, {
+ { "MV", SUBLANG_DEFAULT},
+ { "", 0}}
+ },
+ {"el", LANG_GREEK, {
+ { "GR", SUBLANG_DEFAULT},
+ { "", 0}}
+ },
+ { "en", LANG_ENGLISH, {
+ { "US", SUBLANG_ENGLISH_US },
+ { "GB", SUBLANG_ENGLISH_UK },
+ { "AU", SUBLANG_ENGLISH_AUS },
+ { "CA", SUBLANG_ENGLISH_CAN },
+ { "NZ", SUBLANG_ENGLISH_NZ },
+ { "IE", SUBLANG_ENGLISH_EIRE },
+ { "ZA", SUBLANG_ENGLISH_SOUTH_AFRICA },
+ { "JM", SUBLANG_ENGLISH_JAMAICA },
+ { "BZ", SUBLANG_ENGLISH_BELIZE },
+ { "TT", SUBLANG_ENGLISH_TRINIDAD },
+ { "ZW", SUBLANG_ENGLISH_ZIMBABWE },
+ { "PH", SUBLANG_ENGLISH_PHILIPPINES },
+ { "",0}}
+ },
+ { "es", LANG_SPANISH, { // XXX : SUBLANG_SPANISH_MODERN
+ { "ES", SUBLANG_SPANISH },
+ { "MX", SUBLANG_SPANISH_MEXICAN },
+ { "GT", SUBLANG_SPANISH_GUATEMALA },
+ { "CR", SUBLANG_SPANISH_COSTA_RICA },
+ { "PA", SUBLANG_SPANISH_PANAMA },
+ { "DO", SUBLANG_SPANISH_DOMINICAN_REPUBLIC },
+ { "VE", SUBLANG_SPANISH_VENEZUELA },
+ { "CO", SUBLANG_SPANISH_COLOMBIA },
+ { "PE", SUBLANG_SPANISH_PERU },
+ { "AR", SUBLANG_SPANISH_ARGENTINA },
+ { "EC", SUBLANG_SPANISH_ECUADOR },
+ { "CL", SUBLANG_SPANISH_CHILE },
+ { "UY", SUBLANG_SPANISH_URUGUAY },
+ { "PY", SUBLANG_SPANISH_PARAGUAY },
+ { "BO", SUBLANG_SPANISH_BOLIVIA },
+ { "SV", SUBLANG_SPANISH_EL_SALVADOR },
+ { "HN", SUBLANG_SPANISH_HONDURAS },
+ { "NI", SUBLANG_SPANISH_NICARAGUA },
+ { "PR", SUBLANG_SPANISH_PUERTO_RICO },
+ { "", 0 }}
+ },
+ {"et", LANG_ESTONIAN, {
+ { "EE", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"eu", LANG_BASQUE, {
+ { "ES" , SUBLANG_DEFAULT },
+ { "" , 0 }}
+ },
+ {"fa", LANG_FARSI, {
+ { "IR", SUBLANG_DEFAULT},
+ { "", 0}}
+ },
+ {"fi", LANG_FINNISH, {
+ { "FI", SUBLANG_DEFAULT },
+ { "",0}}
+ },
+ {"fo", LANG_FAEROESE, {
+ { "FO", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "fr", LANG_FRENCH, {
+ { "FR", SUBLANG_FRENCH },
+ { "BE", SUBLANG_FRENCH_BELGIAN },
+ { "CA", SUBLANG_FRENCH_CANADIAN },
+ { "CH", SUBLANG_FRENCH_SWISS },
+ { "LU", SUBLANG_FRENCH_LUXEMBOURG },
+ { "MC", SUBLANG_FRENCH_MONACO },
+ {"",0}}
+ },
+ { "gl", LANG_GALICIAN, {
+ { "ES", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "gu", LANG_GUJARATI, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"he", LANG_HEBREW, {
+ { "IL", SUBLANG_DEFAULT},
+ { "", 0}}
+ },
+ {"hi", LANG_HINDI, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ /* Duplicate the SUBLANG codes for Croatian and Serbian, because the Windows
+ LANG code is the same for both */
+ {"hr", LANG_CROATIAN, {
+ { "CS", SUBLANG_SERBIAN_LATIN },
+ { "SP", SUBLANG_SERBIAN_CYRILLIC },
+ { "HR", SUBLANG_DEFAULT},
+ { "" ,0 }}
+ },
+ {"hu", LANG_HUNGARIAN, {
+ { "HU", SUBLANG_DEFAULT },
+ { "" , 0 }}
+ },
+ {"hy", LANG_ARMENIAN, {
+ { "AM", SUBLANG_DEFAULT},
+ { "" ,0 }}
+ },
+ {"id", LANG_INDONESIAN, {
+ { "ID", SUBLANG_DEFAULT },
+ {"", 0}}
+ },
+ {"is", LANG_ICELANDIC, {
+ { "IS", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "it", LANG_ITALIAN, {
+ { "IT", SUBLANG_ITALIAN },
+ { "CH", SUBLANG_ITALIAN_SWISS },
+ { "", 0}}
+ },
+ {"iw", LANG_HEBREW, {
+ { "IL", SUBLANG_DEFAULT},
+ { "", 0}}
+ },
+ {"ja", LANG_JAPANESE, {
+ { "JP", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "ka", LANG_GEORGIAN, {
+ { "GE", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "kk", LANG_KAZAK, {
+ { "KZ", SUBLANG_DEFAULT }, // KAZAKHSTAN
+ { "", 0}}
+ },
+ { "kn", LANG_KANNADA, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "ko", LANG_KOREAN, {
+ { "KR", SUBLANG_KOREAN },
+ { "", 0}}
+ },
+ { "kok", LANG_KONKANI, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "ky", LANG_KYRGYZ, {
+ { "KG", SUBLANG_DEFAULT }, // Kygyzstan
+ { "", 0}}
+ },
+ {"lt", LANG_LITHUANIAN, {
+ { "LT", SUBLANG_DEFAULT },
+ { "" ,0 }}
+ },
+ {"lv", LANG_LATVIAN, {
+ { "LV", SUBLANG_DEFAULT},
+ { "", 0}}
+ },
+ {"mk", LANG_MACEDONIAN, {
+ { "MK", SUBLANG_DEFAULT },
+ { "", 0 }}
+ },
+ { "mn", LANG_MONGOLIAN, {
+ { "MN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "mr", LANG_MARATHI, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"ms", LANG_MALAY, {
+ { "MY", SUBLANG_MALAY_MALAYSIA },
+ { "BN", SUBLANG_MALAY_BRUNEI_DARUSSALAM }, // XXX
+ { "", 0}}
+ },
+ {"nb", LANG_NORWEGIAN, {
+ { "NO", SUBLANG_NORWEGIAN_BOKMAL },
+ { "", SUBLANG_NORWEGIAN_BOKMAL}}
+ },
+ {"nl", LANG_DUTCH, {
+ {"NL", SUBLANG_DUTCH },
+ {"BE", SUBLANG_DUTCH_BELGIAN },
+ { "", 0}}
+ },
+ {"nn", LANG_NORWEGIAN, {
+ { "NO", SUBLANG_NORWEGIAN_NYNORSK },
+ { "", SUBLANG_NORWEGIAN_NYNORSK}}
+ },
+ {"no", LANG_NORWEGIAN, {
+ { "NO", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "pa", LANG_PUNJABI, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"pl", LANG_POLISH, {
+ { "PL", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "pt", LANG_PORTUGUESE, {
+ { "PT", SUBLANG_PORTUGUESE },
+ { "BR", SUBLANG_PORTUGUESE_BRAZILIAN },
+ {"",0}}
+ },
+ {"ro", LANG_ROMANIAN, {
+ { "RO", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"ru", LANG_RUSSIAN, {
+ { "RU", SUBLANG_DEFAULT },
+ { "", 0 }}
+ },
+ { "sa", LANG_SANSKRIT, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"sk", LANG_SLOVAK, {
+ { "SK", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"sl", LANG_SLOVENIAN, {
+ { "SI", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"sq", LANG_ALBANIAN, {
+ { "AL", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ /* Duplicate the SUBLANG codes for Croatian and Serbian, because the Windows
+ LANG code is the same for both */
+ {"sr", LANG_SERBIAN, {
+ { "CS", SUBLANG_SERBIAN_LATIN },
+ { "SP", SUBLANG_SERBIAN_CYRILLIC },
+ { "HR", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "sv", LANG_SWEDISH, {
+ { "SE", SUBLANG_SWEDISH },
+ { "FI", SUBLANG_SWEDISH_FINLAND },
+ { "", 0 }}
+ },
+ {"sw", LANG_SWAHILI, {
+ { "KE", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "ta", LANG_TAMIL, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "te", LANG_TELUGU, {
+ { "IN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"th", LANG_THAI, {
+ {"TH", SUBLANG_DEFAULT},
+ {"",0}}
+ },
+ {"tr", LANG_TURKISH, {
+ { "TR", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "tt", LANG_TATAR, {
+ { "RU", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"uk", LANG_UKRAINIAN, {
+ { "UA", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"ur", LANG_URDU, {
+ { "PK", SUBLANG_URDU_PAKISTAN },
+ { "IN", SUBLANG_URDU_INDIA },
+ { "", 0}}
+ },
+ {"uz", LANG_UZBEK, { // XXX : Cyrillic, Latin
+ { "UZ", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ {"vi", LANG_VIETNAMESE, {
+ { "VN", SUBLANG_DEFAULT },
+ { "", 0}}
+ },
+ { "zh", LANG_CHINESE, {
+ { "TW", SUBLANG_CHINESE_TRADITIONAL },
+ { "CN", SUBLANG_CHINESE_SIMPLIFIED },
+ { "HK", SUBLANG_CHINESE_HONGKONG },
+ { "SG", SUBLANG_CHINESE_SINGAPORE },
+ { "MO", SUBLANG_CHINESE_MACAU },
+ { "",0}}
+ }
+};
+
+#define LENGTH_MAPPING_LIST ArrayLength(iso_list)
+
+//
+// This list maps ISO 2 digit country codes to Win32 country codes.
+// This list must be kept in alphabetic (by iso code) order and synchronized
+// with the list above. This is only used in debug builds to check the consistentcy
+// of the internal tables.
+//
+#ifdef DEBUG
+static const
+iso_pair dbg_list[] =
+{
+ {"af", LANG_AFRIKAANS},
+ {"ar", LANG_ARABIC},
+ {"az", LANG_AZERI},
+ {"be", LANG_BELARUSIAN},
+ {"bg", LANG_BULGARIAN},
+ {"ca", LANG_CATALAN},
+ {"cs", LANG_CZECH},
+ {"da", LANG_DANISH},
+ {"de", LANG_GERMAN},
+ {"dv", LANG_DIVEHI},
+ {"el", LANG_GREEK},
+ {"en", LANG_ENGLISH},
+ {"es", LANG_SPANISH},
+ {"et", LANG_ESTONIAN},
+ {"eu", LANG_BASQUE},
+ {"fa", LANG_FARSI},
+ {"fi", LANG_FINNISH},
+ {"fo", LANG_FAEROESE},
+ {"fr", LANG_FRENCH},
+ {"gl", LANG_GALICIAN},
+ {"gu", LANG_GUJARATI},
+ {"he", LANG_HEBREW},
+ {"hi", LANG_HINDI},
+ {"hr", LANG_CROATIAN},
+ {"hu", LANG_HUNGARIAN},
+ {"hy", LANG_ARMENIAN},
+ {"id", LANG_INDONESIAN},
+ {"in", LANG_INDONESIAN},
+ {"is", LANG_ICELANDIC},
+ {"it", LANG_ITALIAN},
+ {"iw", LANG_HEBREW},
+ {"ja", LANG_JAPANESE},
+ {"ka", LANG_GEORGIAN},
+ {"kn", LANG_KANNADA},
+ {"ko", LANG_KOREAN},
+ {"kok", LANG_KONKANI},
+ {"lt", LANG_LITHUANIAN},
+ {"lv", LANG_LATVIAN},
+ {"mk", LANG_MACEDONIAN},
+ {"mn", LANG_MONGOLIAN},
+ {"mr", LANG_MARATHI},
+ {"ms", LANG_MALAY},
+ {"nb", LANG_NORWEGIAN},
+ {"nl", LANG_DUTCH},
+ {"nn", LANG_NORWEGIAN},
+ {"no", LANG_NORWEGIAN},
+ {"pa", LANG_PUNJABI},
+ {"pl", LANG_POLISH},
+ {"pt", LANG_PORTUGUESE},
+ {"ro", LANG_ROMANIAN},
+ {"ru", LANG_RUSSIAN},
+ {"sa", LANG_SANSKRIT},
+ {"sk", LANG_SLOVAK},
+ {"sl", LANG_SLOVENIAN},
+ {"sq", LANG_ALBANIAN},
+ {"sr", LANG_SERBIAN},
+ {"sv", LANG_SWEDISH},
+ {"sw", LANG_SWAHILI},
+ {"ta", LANG_TAMIL},
+ {"te", LANG_TELUGU},
+ {"th", LANG_THAI},
+ {"tr", LANG_TURKISH},
+ {"tt", LANG_TATAR},
+ {"uk", LANG_UKRAINIAN},
+ {"ur", LANG_URDU},
+ {"uz", LANG_UZBEK},
+ {"vi", LANG_VIETNAMESE},
+ {"zh", LANG_CHINESE},
+ {"",0}
+};
+#endif
+
+#define CROATIAN_ISO_CODE "hr"
+#define SERBIAN_ISO_CODE "sr"
+
+void
+nsWin32Locale::initFunctionPointers(void)
+{
+ static bool sInitialized = false;
+ // We use the Vista and above functions if we have them
+ if (!sInitialized) {
+ HMODULE kernelDLL = GetModuleHandleW(L"kernel32.dll");
+ if (kernelDLL) {
+ localeNameToLCID = (LocaleNameToLCIDPtr) GetProcAddress(kernelDLL, "LocaleNameToLCID");
+ lcidToLocaleName = (LCIDToLocaleNamePtr) GetProcAddress(kernelDLL, "LCIDToLocaleName");
+ }
+ sInitialized = true;
+ }
+}
+
+//
+// the mapping routines are a first approximation to get us going on
+// the tier-1 languages. we are making an assumption that we can map
+// language and country codes separately on Windows, which isn't true
+//
+nsresult
+nsWin32Locale::GetPlatformLocale(const nsAString& locale, LCID* winLCID)
+{
+ initFunctionPointers ();
+
+ if (localeNameToLCID) {
+ nsAutoString locale_autostr(locale);
+ LCID lcid = localeNameToLCID(locale_autostr.get(), 0);
+ // The function returning 0 means that the locale name couldn't be matched,
+ // so we fallback to the old function
+ if (lcid != 0)
+ {
+ *winLCID = lcid;
+ return NS_OK;
+ }
+ }
+
+ char locale_string[9] = {'\0','\0','\0','\0','\0','\0','\0','\0','\0'};
+ char* language_code;
+ char* country_code;
+ size_t i, j;
+
+ // parse the locale
+ const char16_t* data;
+ j = NS_StringGetData(locale, &data);
+ for (i = 0; i < 7 && i < j; i++) {
+ locale_string[i] = data[i] == '-' ? '\0' : data[i];
+ }
+
+ language_code = locale_string;
+ country_code = locale_string + strlen(locale_string) + 1;
+
+ // convert parsed locale to Windows LCID
+ for(i=0;i<LENGTH_MAPPING_LIST;i++) {
+ if (strcmp(language_code,iso_list[i].iso_code)==0) {
+ for(j=0;iso_list[i].sublang_list[j].win_code;j++) {
+ if (strcmp(country_code,iso_list[i].sublang_list[j].iso_code)==0) {
+ *winLCID = MAKELCID(MAKELANGID(iso_list[i].win_code,iso_list[i].sublang_list[j].win_code),SORT_DEFAULT);
+ return NS_OK;
+ }
+ }
+ // here we have a language match but no country match
+ *winLCID = MAKELCID(MAKELANGID(iso_list[i].win_code,SUBLANG_DEFAULT),SORT_DEFAULT);
+ return NS_OK;
+ }
+ }
+
+ return NS_ERROR_FAILURE;
+}
+
+#ifndef LOCALE_NAME_MAX_LENGTH
+#define LOCALE_NAME_MAX_LENGTH 85
+#endif
+
+void
+nsWin32Locale::GetXPLocale(LCID winLCID, nsAString& locale)
+{
+ initFunctionPointers ();
+
+ if (lcidToLocaleName)
+ {
+ WCHAR ret_locale[LOCALE_NAME_MAX_LENGTH];
+ int rv = lcidToLocaleName(winLCID, ret_locale, LOCALE_NAME_MAX_LENGTH, 0);
+ // rv 0 means that the function failed to match up the LCID, so we fallback
+ // to the old function
+ if (rv != 0)
+ {
+ locale.Assign(ret_locale);
+ return;
+ }
+ }
+
+ DWORD lang_id, sublang_id;
+ size_t i, j;
+
+ lang_id = PRIMARYLANGID(LANGIDFROMLCID(winLCID));
+ sublang_id = SUBLANGID(LANGIDFROMLCID(winLCID));
+
+ /* Special-case Norwegian Bokmal and Norwegian Nynorsk, which have the same
+ LANG_ID on Windows, but have separate ISO-639-2 codes */
+ if (lang_id == LANG_NORWEGIAN) {
+ if (sublang_id == SUBLANG_NORWEGIAN_BOKMAL) {
+ locale.AssignASCII("nb-NO");
+ } else if (sublang_id == SUBLANG_NORWEGIAN_NYNORSK) {
+ locale.AssignASCII("nn-NO");
+ } else {
+ locale.AssignASCII("no-NO");
+ }
+ return;
+ }
+
+ for(i=0;i<LENGTH_MAPPING_LIST;i++) {
+ if (lang_id==iso_list[i].win_code) {
+ /* Special-case Croatian and Serbian, which have the same LANG_ID on
+ Windows, but have been split into separate ISO-639-2 codes */
+ if (lang_id == LANG_CROATIAN) {
+ if (sublang_id == SUBLANG_DEFAULT) {
+ locale.AssignLiteral(CROATIAN_ISO_CODE);
+ } else {
+ locale.AssignLiteral(SERBIAN_ISO_CODE);
+ }
+ } else {
+ locale.AssignASCII(iso_list[i].iso_code);
+ }
+ for(j=0;iso_list[i].sublang_list[j].win_code;j++) {
+ if (sublang_id == iso_list[i].sublang_list[j].win_code) {
+ locale.Append(char16_t('-'));
+ locale.AppendASCII(iso_list[i].sublang_list[j].iso_code);
+ break;
+ }
+ }
+ return;
+ }
+ }
+
+ //
+ // didn't find any match. fall back to en-US, which is better
+ // than unusable buttons without 'OK', 'Cancel', etc (bug 224546)
+ //
+ locale.AssignLiteral("en-US");
+ return;
+}
+
+#ifdef DEBUG
+void
+test_internal_tables(void)
+{
+ size_t i;
+
+ for(i=1;i<LENGTH_MAPPING_LIST;i++) {
+ if (strcmp(dbg_list[i-1].iso_code,dbg_list[i].iso_code)>=0)
+ fprintf(stderr,"nsLocale: language_list %s and %s are not ordered\n",dbg_list[i-1].iso_code,dbg_list[i].iso_code);
+ }
+
+ i=0;
+ while(strlen(dbg_list[i].iso_code)!=0) {
+ i++;
+ }
+ if (i!=LENGTH_MAPPING_LIST)
+ fprintf(stderr,"nsLocale: language_list length is %u, reported length is %u\n",
+ unsigned(i), unsigned(LENGTH_MAPPING_LIST));
+
+ for(i=0;i<LENGTH_MAPPING_LIST;i++) {
+ if (strcmp(iso_list[i].iso_code,dbg_list[i].iso_code)!=0) {
+ fprintf(stderr,"nsLocale: iso_list and dbg_list different at item: %u\n",
+ unsigned(i));
+ }
+ }
+}
+
+#endif
+
diff --git a/intl/locale/windows/nsWinCharset.cpp b/intl/locale/windows/nsWinCharset.cpp
new file mode 100644
index 000000000..c84307267
--- /dev/null
+++ b/intl/locale/windows/nsWinCharset.cpp
@@ -0,0 +1,101 @@
+
+/* 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/. */
+
+#include "mozilla/ArrayUtils.h"
+
+#include "nsIPlatformCharset.h"
+#include "nsUConvPropertySearch.h"
+#include <windows.h>
+#include "nsWin32Locale.h"
+#include "nsCOMPtr.h"
+#include "nsReadableUtils.h"
+#include "nsServiceManagerUtils.h"
+#include "nsPlatformCharset.h"
+#include "nsEncoderDecoderUtils.h"
+
+using namespace mozilla;
+
+static const nsUConvProp kWinCharsets[] = {
+#include "wincharset.properties.h"
+};
+
+NS_IMPL_ISUPPORTS(nsPlatformCharset, nsIPlatformCharset)
+
+nsPlatformCharset::nsPlatformCharset()
+{
+ nsAutoString acpKey(NS_LITERAL_STRING("acp."));
+ acpKey.AppendInt(int32_t(::GetACP() & 0x00FFFF), 10);
+ MapToCharset(acpKey, mCharset);
+}
+
+nsPlatformCharset::~nsPlatformCharset()
+{
+}
+
+nsresult
+nsPlatformCharset::MapToCharset(nsAString& inANSICodePage, nsACString& outCharset)
+{
+ nsAutoCString key;
+ LossyCopyUTF16toASCII(inANSICodePage, key);
+
+ nsresult rv = nsUConvPropertySearch::SearchPropertyValue(kWinCharsets,
+ ArrayLength(kWinCharsets), key, outCharset);
+ if (NS_FAILED(rv)) {
+ outCharset.AssignLiteral("windows-1252");
+ return NS_SUCCESS_USING_FALLBACK_LOCALE;
+ }
+ return rv;
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::GetCharset(nsPlatformCharsetSel selector,
+ nsACString& oResult)
+{
+ oResult = mCharset;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::GetDefaultCharsetForLocale(const nsAString& localeName, nsACString& oResult)
+{
+ LCID localeAsLCID;
+
+ //
+ // convert locale name to a code page (through the LCID)
+ //
+ nsresult rv;
+ oResult.Truncate();
+
+ rv = nsWin32Locale::GetPlatformLocale(localeName, &localeAsLCID);
+ if (NS_FAILED(rv)) { return rv; }
+
+ wchar_t acp_name[6];
+ if (GetLocaleInfoW(localeAsLCID, LOCALE_IDEFAULTANSICODEPAGE, acp_name,
+ ArrayLength(acp_name))==0) {
+ return NS_ERROR_FAILURE;
+ }
+ nsAutoString acp_key(NS_LITERAL_STRING("acp."));
+ acp_key.Append(acp_name);
+
+ return MapToCharset(acp_key, oResult);
+}
+
+NS_IMETHODIMP
+nsPlatformCharset::Init()
+{
+ return NS_OK;
+}
+
+nsresult
+nsPlatformCharset::InitGetCharset(nsACString &oString)
+{
+ return NS_OK;
+}
+
+nsresult
+nsPlatformCharset::VerifyCharset(nsCString &aCharset)
+{
+ return NS_OK;
+}
diff --git a/intl/locale/windows/wincharset.properties b/intl/locale/windows/wincharset.properties
new file mode 100644
index 000000000..79a802492
--- /dev/null
+++ b/intl/locale/windows/wincharset.properties
@@ -0,0 +1,23 @@
+# 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/.
+#
+# This file map a ACP to a charset name
+# We use this to figure out the charset of file system, clipboard, etc
+#
+
+acp.874=windows-874
+acp.932=Shift_JIS
+acp.936=gb18030
+acp.949=EUC-KR
+acp.950=Big5
+acp.951=Big5
+acp.1250=windows-1250
+acp.1251=windows-1251
+acp.1252=windows-1252
+acp.1253=windows-1253
+acp.1254=windows-1254
+acp.1255=windows-1255
+acp.1256=windows-1256
+acp.1257=windows-1257
+acp.1258=windows-1258