michael@0: /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifdef MOZ_WIDGET_QT michael@0: #include michael@0: #include michael@0: #endif michael@0: michael@0: #include "nsCOMPtr.h" michael@0: #include "nsAutoPtr.h" michael@0: #include "nsILocale.h" michael@0: #include "nsILocaleService.h" michael@0: #include "nsLocale.h" michael@0: #include "nsCRT.h" michael@0: #include "prprf.h" michael@0: #include "nsTArray.h" michael@0: #include "nsString.h" michael@0: michael@0: #include michael@0: michael@0: #if defined(XP_WIN) michael@0: # include "nsWin32Locale.h" michael@0: #elif defined(XP_MACOSX) michael@0: # include michael@0: #elif defined(XP_UNIX) michael@0: # include michael@0: # include michael@0: # include "nsPosixLocale.h" michael@0: #endif michael@0: michael@0: // michael@0: // implementation constants michael@0: const int LocaleListLength = 6; michael@0: const char* LocaleList[LocaleListLength] = michael@0: { michael@0: NSILOCALE_COLLATE, michael@0: NSILOCALE_CTYPE, michael@0: NSILOCALE_MONETARY, michael@0: NSILOCALE_NUMERIC, michael@0: NSILOCALE_TIME, michael@0: NSILOCALE_MESSAGE michael@0: }; michael@0: michael@0: #define NSILOCALE_MAX_ACCEPT_LANGUAGE 16 michael@0: #define NSILOCALE_MAX_ACCEPT_LENGTH 18 michael@0: michael@0: #if (defined(XP_UNIX) && !defined(XP_MACOSX)) michael@0: static int posix_locale_category[LocaleListLength] = michael@0: { michael@0: LC_COLLATE, michael@0: LC_CTYPE, michael@0: LC_MONETARY, michael@0: LC_NUMERIC, michael@0: LC_TIME, michael@0: #ifdef HAVE_I18N_LC_MESSAGES michael@0: LC_MESSAGES michael@0: #else michael@0: LC_CTYPE michael@0: #endif michael@0: }; michael@0: #endif michael@0: michael@0: // michael@0: // nsILocaleService implementation michael@0: // michael@0: class nsLocaleService: public nsILocaleService { michael@0: michael@0: public: michael@0: michael@0: // michael@0: // nsISupports michael@0: // michael@0: NS_DECL_THREADSAFE_ISUPPORTS michael@0: michael@0: // michael@0: // nsILocaleService michael@0: // michael@0: NS_DECL_NSILOCALESERVICE michael@0: michael@0: michael@0: nsLocaleService(void); michael@0: virtual ~nsLocaleService(void); michael@0: michael@0: protected: michael@0: michael@0: nsresult SetSystemLocale(void); michael@0: nsresult SetApplicationLocale(void); michael@0: michael@0: nsCOMPtr mSystemLocale; michael@0: nsCOMPtr mApplicationLocale; michael@0: michael@0: }; michael@0: michael@0: // michael@0: // nsLocaleService methods michael@0: // michael@0: nsLocaleService::nsLocaleService(void) michael@0: { michael@0: #ifdef XP_WIN michael@0: nsAutoString xpLocale; michael@0: // michael@0: // get the system LCID michael@0: // michael@0: LCID win_lcid = GetSystemDefaultLCID(); michael@0: NS_ENSURE_TRUE_VOID(win_lcid); michael@0: nsWin32Locale::GetXPLocale(win_lcid, xpLocale); michael@0: nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale)); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: michael@0: // michael@0: // get the application LCID michael@0: // michael@0: win_lcid = GetUserDefaultLCID(); michael@0: NS_ENSURE_TRUE_VOID(win_lcid); michael@0: nsWin32Locale::GetXPLocale(win_lcid, xpLocale); michael@0: rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale)); michael@0: NS_ENSURE_SUCCESS_VOID(rv); michael@0: #endif michael@0: #if defined(XP_UNIX) && !defined(XP_MACOSX) michael@0: nsRefPtr resultLocale(new nsLocale()); michael@0: NS_ENSURE_TRUE_VOID(resultLocale); michael@0: michael@0: #ifdef MOZ_WIDGET_QT michael@0: const char* lang = QLocale::system().name().toUtf8(); michael@0: #else michael@0: // Get system configuration michael@0: const char* lang = getenv("LANG"); michael@0: #endif michael@0: michael@0: nsAutoString xpLocale, platformLocale; michael@0: nsAutoString category, category_platform; michael@0: int i; michael@0: michael@0: for( i = 0; i < LocaleListLength; i++ ) { michael@0: nsresult result; michael@0: // setlocale( , "") evaluates LC_* and LANG michael@0: char* lc_temp = setlocale(posix_locale_category[i], ""); michael@0: CopyASCIItoUTF16(LocaleList[i], category); michael@0: category_platform = category; michael@0: category_platform.AppendLiteral("##PLATFORM"); michael@0: if (lc_temp != nullptr) { michael@0: result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale); michael@0: CopyASCIItoUTF16(lc_temp, platformLocale); michael@0: } else { michael@0: if ( lang == nullptr ) { michael@0: platformLocale.AssignLiteral("en_US"); michael@0: result = nsPosixLocale::GetXPLocale("en-US", xpLocale); michael@0: } else { michael@0: CopyASCIItoUTF16(lang, platformLocale); michael@0: result = nsPosixLocale::GetXPLocale(lang, xpLocale); michael@0: } michael@0: } michael@0: if (NS_FAILED(result)) { michael@0: return; michael@0: } michael@0: resultLocale->AddCategory(category, xpLocale); michael@0: resultLocale->AddCategory(category_platform, platformLocale); michael@0: } michael@0: mSystemLocale = do_QueryInterface(resultLocale); michael@0: mApplicationLocale = do_QueryInterface(resultLocale); michael@0: michael@0: #endif // XP_UNIX michael@0: michael@0: #ifdef XP_MACOSX michael@0: // Get string representation of user's current locale michael@0: CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent(); michael@0: CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef); michael@0: ::CFRetain(userLocaleStr); michael@0: michael@0: nsAutoTArray buffer; michael@0: int size = ::CFStringGetLength(userLocaleStr); michael@0: buffer.SetLength(size + 1); michael@0: CFRange range = ::CFRangeMake(0, size); michael@0: ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements()); michael@0: buffer[size] = 0; michael@0: michael@0: // Convert the locale string to the format that Mozilla expects michael@0: nsAutoString xpLocale(reinterpret_cast(buffer.Elements())); michael@0: xpLocale.ReplaceChar('_', '-'); michael@0: michael@0: nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale)); michael@0: if (NS_SUCCEEDED(rv)) { michael@0: mApplicationLocale = mSystemLocale; michael@0: } michael@0: michael@0: ::CFRelease(userLocaleStr); michael@0: ::CFRelease(userLocaleRef); michael@0: michael@0: NS_ASSERTION(mApplicationLocale, "Failed to create locale objects"); michael@0: #endif // XP_MACOSX michael@0: } michael@0: michael@0: nsLocaleService::~nsLocaleService(void) michael@0: { michael@0: } michael@0: michael@0: NS_IMPL_ISUPPORTS(nsLocaleService, nsILocaleService) michael@0: michael@0: NS_IMETHODIMP michael@0: nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval) michael@0: { michael@0: nsresult result; michael@0: michael@0: *_retval = nullptr; michael@0: michael@0: nsRefPtr resultLocale(new nsLocale()); michael@0: if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY; michael@0: michael@0: for (int32_t i = 0; i < LocaleListLength; i++) { michael@0: NS_ConvertASCIItoUTF16 category(LocaleList[i]); michael@0: result = resultLocale->AddCategory(category, aLocale); michael@0: if (NS_FAILED(result)) return result; michael@0: #if defined(XP_UNIX) && !defined(XP_MACOSX) michael@0: category.AppendLiteral("##PLATFORM"); michael@0: result = resultLocale->AddCategory(category, aLocale); michael@0: if (NS_FAILED(result)) return result; michael@0: #endif michael@0: } michael@0: michael@0: NS_ADDREF(*_retval = resultLocale); michael@0: return NS_OK; michael@0: } michael@0: michael@0: michael@0: NS_IMETHODIMP michael@0: nsLocaleService::GetSystemLocale(nsILocale **_retval) michael@0: { michael@0: if (mSystemLocale) { michael@0: NS_ADDREF(*_retval = mSystemLocale); michael@0: return NS_OK; michael@0: } michael@0: michael@0: *_retval = (nsILocale*)nullptr; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsLocaleService::GetApplicationLocale(nsILocale **_retval) michael@0: { michael@0: if (mApplicationLocale) { michael@0: NS_ADDREF(*_retval = mApplicationLocale); michael@0: return NS_OK; michael@0: } michael@0: michael@0: *_retval=(nsILocale*)nullptr; michael@0: return NS_ERROR_FAILURE; michael@0: } michael@0: michael@0: NS_IMETHODIMP michael@0: nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval) michael@0: { michael@0: char* cPtr; michael@0: char* cPtr1; michael@0: char* cPtr2; michael@0: int i; michael@0: int j; michael@0: int countLang = 0; michael@0: char acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH]; michael@0: nsresult result; michael@0: michael@0: nsAutoArrayPtr input(new char[strlen(acceptLanguage)+1]); michael@0: michael@0: strcpy(input, acceptLanguage); michael@0: cPtr1 = input-1; michael@0: cPtr2 = input; michael@0: michael@0: /* put in standard form */ michael@0: while (*(++cPtr1)) { michael@0: if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */ michael@0: else if (isspace(*cPtr1)) ; /* ignore any space */ michael@0: else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */ michael@0: else if (*cPtr1=='*') ; /* ignore "*" */ michael@0: else *cPtr2++ = *cPtr1; /* else unchanged */ michael@0: } michael@0: *cPtr2 = '\0'; michael@0: michael@0: countLang = 0; michael@0: michael@0: if (strchr(input,';')) { michael@0: /* deal with the quality values */ michael@0: michael@0: float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE]; michael@0: float qSwap; michael@0: float bias = 0.0f; michael@0: char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE]; michael@0: char* ptrSwap; michael@0: michael@0: cPtr = nsCRT::strtok(input,",",&cPtr2); michael@0: while (cPtr) { michael@0: qvalue[countLang] = 1.0f; michael@0: /* add extra parens to get rid of warning */ michael@0: if ((cPtr1 = strchr(cPtr,';')) != nullptr) { michael@0: PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]); michael@0: *cPtr1 = '\0'; michael@0: } michael@0: if (strlen(cPtr)=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */ michael@0: } michael@0: cPtr = nsCRT::strtok(cPtr2,",",&cPtr2); michael@0: } michael@0: michael@0: /* sort according to decending qvalue */ michael@0: /* not a very good algorithm, but count is not likely large */ michael@0: for ( i=0 ; i=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */ michael@0: } michael@0: cPtr = nsCRT::strtok(cPtr2,",",&cPtr2); michael@0: } michael@0: } michael@0: michael@0: // michael@0: // now create the locale michael@0: // michael@0: result = NS_ERROR_FAILURE; michael@0: if (countLang>0) { michael@0: result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval); michael@0: } michael@0: michael@0: // michael@0: // clean up michael@0: // michael@0: return result; michael@0: } michael@0: michael@0: michael@0: nsresult michael@0: nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval) michael@0: { michael@0: nsCOMPtr system_locale; michael@0: nsresult result; michael@0: michael@0: result = GetSystemLocale(getter_AddRefs(system_locale)); michael@0: if (NS_SUCCEEDED(result)) michael@0: { michael@0: result = system_locale-> michael@0: GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval); michael@0: return result; michael@0: } michael@0: michael@0: return result; michael@0: } michael@0: michael@0: michael@0: michael@0: nsresult michael@0: NS_NewLocaleService(nsILocaleService** result) michael@0: { michael@0: if(!result) michael@0: return NS_ERROR_NULL_POINTER; michael@0: *result = new nsLocaleService(); michael@0: if (! *result) michael@0: return NS_ERROR_OUT_OF_MEMORY; michael@0: NS_ADDREF(*result); michael@0: return NS_OK; michael@0: }