diff options
Diffstat (limited to 'intl/locale')
71 files changed, 7945 insertions, 0 deletions
diff --git a/intl/locale/PluralForm.jsm b/intl/locale/PluralForm.jsm new file mode 100644 index 0000000000..9f249fce56 --- /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 0000000000..dd573bd75b --- /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 0000000000..75179063cb --- /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 0000000000..beda4fa260 --- /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 0000000000..d230f4d771 --- /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 0000000000..46bb0145de --- /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 0000000000..6ee73292d7 --- /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 0000000000..dfdf703780 --- /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 0000000000..956560fba8 --- /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 0000000000..2da1c2dd54 --- /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 0000000000..f6fa544715 --- /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 0000000000..4d93668226 --- /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 0000000000..d71db33871 --- /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 0000000000..31115bc4d2 --- /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 0000000000..bbcfb395bb --- /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 0000000000..263b3abb4e --- /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 0000000000..37ee9de461 --- /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 0000000000..656102ffeb --- /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 0000000000..e0449d777e --- /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 0000000000..477470a865 --- /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 0000000000..1cc889bb67 --- /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 0000000000..04dcbe333f --- /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 0000000000..9002a03f78 --- /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 0000000000..83f6e70961 --- /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 0000000000..5cf9018662 --- /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 0000000000..168f0614a3 --- /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 0000000000..2d2e579740 --- /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 0000000000..6d45ec9afa --- /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 0000000000..6af995f46a --- /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 0000000000..b3a6808420 --- /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 0000000000..a75cdaf29f --- /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 0000000000..934244516a --- /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 0000000000..b27faa85b9 --- /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 0000000000..a7a8b589d1 --- /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 0000000000..510e0d51a0 --- /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 0000000000..5b7aa415bf --- /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 0000000000..3bc7fbc7be --- /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 0000000000..3e526d226b --- /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 0000000000..2d18096db5 --- /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 0000000000..b6962f8de8 --- /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 0000000000..2720a83426 --- /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 0000000000..fa3426d4e9 --- /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 0000000000..a8678deef3 --- /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 0000000000..98aeeb5c0b --- /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 0000000000..ae0c5b17a2 --- /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 0000000000..d0877db5dc --- /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 0000000000..807c9ecc59 --- /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 0000000000..f662c235db --- /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 0000000000..32ebc60ebc --- /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 0000000000..899e39d389 --- /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 0000000000..834605b1f9 --- /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 0000000000..bdd7d27494 --- /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 0000000000..4d0928ae41 --- /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 0000000000..f794fd9f48 --- /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 0000000000..7685d0a01c --- /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 0000000000..ed646039c6 --- /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 0000000000..3bc5a731c1 --- /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 0000000000..dd2126b445 --- /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 0000000000..a70b54102c --- /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 0000000000..6c305556f6 --- /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 0000000000..16299afed5 --- /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 0000000000..d72305e55a --- /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 0000000000..1376b49d6a --- /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 0000000000..5bde38b89c --- /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 0000000000..8dcdb8f071 --- /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 0000000000..901211344c --- /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 0000000000..f65868e1bc --- /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 0000000000..1c84492ee5 --- /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 0000000000..8a66d2c640 --- /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 0000000000..c843072672 --- /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 0000000000..79a802492a --- /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 |