Bumping gaia.json for 1 gaia revision(s) a=gaia-bump
[gecko.git] / intl / locale / nsLocaleService.cpp
blobcb571e33ca39beba568907de4e745eccc05a595e
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifdef MOZ_WIDGET_QT
7 #include <QString>
8 #include <QtCore/QLocale>
9 #endif
11 #include "nsCOMPtr.h"
12 #include "nsAutoPtr.h"
13 #include "nsILocale.h"
14 #include "nsILocaleService.h"
15 #include "nsLocale.h"
16 #include "nsCRT.h"
17 #include "prprf.h"
18 #include "nsTArray.h"
19 #include "nsString.h"
21 #include <ctype.h>
23 #if defined(XP_WIN)
24 # include "nsWin32Locale.h"
25 #elif defined(XP_MACOSX)
26 # include <Carbon/Carbon.h>
27 #elif defined(XP_UNIX)
28 # include <locale.h>
29 # include <stdlib.h>
30 # include "nsPosixLocale.h"
31 #endif
34 // implementation constants
35 const int LocaleListLength = 6;
36 const char* LocaleList[LocaleListLength] =
38 NSILOCALE_COLLATE,
39 NSILOCALE_CTYPE,
40 NSILOCALE_MONETARY,
41 NSILOCALE_NUMERIC,
42 NSILOCALE_TIME,
43 NSILOCALE_MESSAGE
46 #define NSILOCALE_MAX_ACCEPT_LANGUAGE 16
47 #define NSILOCALE_MAX_ACCEPT_LENGTH 18
49 #if (defined(XP_UNIX) && !defined(XP_MACOSX))
50 static int posix_locale_category[LocaleListLength] =
52 LC_COLLATE,
53 LC_CTYPE,
54 LC_MONETARY,
55 LC_NUMERIC,
56 LC_TIME,
57 #ifdef HAVE_I18N_LC_MESSAGES
58 LC_MESSAGES
59 #else
60 LC_CTYPE
61 #endif
63 #endif
66 // nsILocaleService implementation
68 class nsLocaleService: public nsILocaleService {
70 public:
73 // nsISupports
75 NS_DECL_THREADSAFE_ISUPPORTS
78 // nsILocaleService
80 NS_DECL_NSILOCALESERVICE
83 nsLocaleService(void);
85 protected:
87 nsresult SetSystemLocale(void);
88 nsresult SetApplicationLocale(void);
90 nsCOMPtr<nsILocale> mSystemLocale;
91 nsCOMPtr<nsILocale> mApplicationLocale;
93 virtual ~nsLocaleService(void);
97 // nsLocaleService methods
99 nsLocaleService::nsLocaleService(void)
101 #ifdef XP_WIN
102 nsAutoString xpLocale;
104 // get the system LCID
106 LCID win_lcid = GetSystemDefaultLCID();
107 NS_ENSURE_TRUE_VOID(win_lcid);
108 nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
109 nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
110 NS_ENSURE_SUCCESS_VOID(rv);
113 // get the application LCID
115 win_lcid = GetUserDefaultLCID();
116 NS_ENSURE_TRUE_VOID(win_lcid);
117 nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
118 rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
119 NS_ENSURE_SUCCESS_VOID(rv);
120 #endif
121 #if defined(XP_UNIX) && !defined(XP_MACOSX)
122 nsRefPtr<nsLocale> resultLocale(new nsLocale());
123 NS_ENSURE_TRUE_VOID(resultLocale);
125 #ifdef MOZ_WIDGET_QT
126 const char* lang = QLocale::system().name().toUtf8();
127 #else
128 // Get system configuration
129 const char* lang = getenv("LANG");
130 #endif
132 nsAutoString xpLocale, platformLocale;
133 nsAutoString category, category_platform;
134 int i;
136 for( i = 0; i < LocaleListLength; i++ ) {
137 nsresult result;
138 // setlocale( , "") evaluates LC_* and LANG
139 char* lc_temp = setlocale(posix_locale_category[i], "");
140 CopyASCIItoUTF16(LocaleList[i], category);
141 category_platform = category;
142 category_platform.AppendLiteral("##PLATFORM");
144 bool lc_temp_valid = lc_temp != nullptr;
146 #if defined(MOZ_WIDGET_ANDROID)
147 // Treat the "C" env as nothing useful. See Bug 1095298.
148 lc_temp_valid = lc_temp_valid && strcmp(lc_temp, "C") != 0;
149 #endif
151 if (lc_temp_valid) {
152 result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale);
153 CopyASCIItoUTF16(lc_temp, platformLocale);
154 } else {
155 if ( lang == nullptr ) {
156 platformLocale.AssignLiteral("en_US");
157 result = nsPosixLocale::GetXPLocale("en-US", xpLocale);
158 } else {
159 CopyASCIItoUTF16(lang, platformLocale);
160 result = nsPosixLocale::GetXPLocale(lang, xpLocale);
163 if (NS_FAILED(result)) {
164 return;
166 resultLocale->AddCategory(category, xpLocale);
167 resultLocale->AddCategory(category_platform, platformLocale);
169 mSystemLocale = do_QueryInterface(resultLocale);
170 mApplicationLocale = do_QueryInterface(resultLocale);
172 #endif // XP_UNIX
174 #ifdef XP_MACOSX
175 // Get string representation of user's current locale
176 CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
177 CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
178 ::CFRetain(userLocaleStr);
180 nsAutoTArray<UniChar, 32> buffer;
181 int size = ::CFStringGetLength(userLocaleStr);
182 buffer.SetLength(size + 1);
183 CFRange range = ::CFRangeMake(0, size);
184 ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
185 buffer[size] = 0;
187 // Convert the locale string to the format that Mozilla expects
188 nsAutoString xpLocale(reinterpret_cast<char16_t*>(buffer.Elements()));
189 xpLocale.ReplaceChar('_', '-');
191 nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
192 if (NS_SUCCEEDED(rv)) {
193 mApplicationLocale = mSystemLocale;
196 ::CFRelease(userLocaleStr);
197 ::CFRelease(userLocaleRef);
199 NS_ASSERTION(mApplicationLocale, "Failed to create locale objects");
200 #endif // XP_MACOSX
203 nsLocaleService::~nsLocaleService(void)
207 NS_IMPL_ISUPPORTS(nsLocaleService, nsILocaleService)
209 NS_IMETHODIMP
210 nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
212 nsresult result;
214 *_retval = nullptr;
216 nsRefPtr<nsLocale> resultLocale(new nsLocale());
217 if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
219 for (int32_t i = 0; i < LocaleListLength; i++) {
220 NS_ConvertASCIItoUTF16 category(LocaleList[i]);
221 result = resultLocale->AddCategory(category, aLocale);
222 if (NS_FAILED(result)) return result;
223 #if defined(XP_UNIX) && !defined(XP_MACOSX)
224 category.AppendLiteral("##PLATFORM");
225 result = resultLocale->AddCategory(category, aLocale);
226 if (NS_FAILED(result)) return result;
227 #endif
230 NS_ADDREF(*_retval = resultLocale);
231 return NS_OK;
235 NS_IMETHODIMP
236 nsLocaleService::GetSystemLocale(nsILocale **_retval)
238 if (mSystemLocale) {
239 NS_ADDREF(*_retval = mSystemLocale);
240 return NS_OK;
243 *_retval = (nsILocale*)nullptr;
244 return NS_ERROR_FAILURE;
247 NS_IMETHODIMP
248 nsLocaleService::GetApplicationLocale(nsILocale **_retval)
250 if (mApplicationLocale) {
251 NS_ADDREF(*_retval = mApplicationLocale);
252 return NS_OK;
255 *_retval=(nsILocale*)nullptr;
256 return NS_ERROR_FAILURE;
259 NS_IMETHODIMP
260 nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval)
262 char* cPtr;
263 char* cPtr1;
264 char* cPtr2;
265 int i;
266 int j;
267 int countLang = 0;
268 char acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];
269 nsresult result;
271 nsAutoArrayPtr<char> input(new char[strlen(acceptLanguage)+1]);
273 strcpy(input, acceptLanguage);
274 cPtr1 = input-1;
275 cPtr2 = input;
277 /* put in standard form */
278 while (*(++cPtr1)) {
279 if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
280 else if (isspace(*cPtr1)) ; /* ignore any space */
281 else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
282 else if (*cPtr1=='*') ; /* ignore "*" */
283 else *cPtr2++ = *cPtr1; /* else unchanged */
285 *cPtr2 = '\0';
287 countLang = 0;
289 if (strchr(input,';')) {
290 /* deal with the quality values */
292 float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];
293 float qSwap;
294 float bias = 0.0f;
295 char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE];
296 char* ptrSwap;
298 cPtr = nsCRT::strtok(input,",",&cPtr2);
299 while (cPtr) {
300 qvalue[countLang] = 1.0f;
301 /* add extra parens to get rid of warning */
302 if ((cPtr1 = strchr(cPtr,';')) != nullptr) {
303 PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]);
304 *cPtr1 = '\0';
306 if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LANGUAGE) { /* ignore if too long */
307 qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
308 ptrLanguage[countLang++] = cPtr;
309 if (countLang>=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
311 cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
314 /* sort according to decending qvalue */
315 /* not a very good algorithm, but count is not likely large */
316 for ( i=0 ; i<countLang-1 ; i++ ) {
317 for ( j=i+1 ; j<countLang ; j++ ) {
318 if (qvalue[i]<qvalue[j]) {
319 qSwap = qvalue[i];
320 qvalue[i] = qvalue[j];
321 qvalue[j] = qSwap;
322 ptrSwap = ptrLanguage[i];
323 ptrLanguage[i] = ptrLanguage[j];
324 ptrLanguage[j] = ptrSwap;
328 for ( i=0 ; i<countLang ; i++ ) {
329 PL_strncpyz(acceptLanguageList[i],ptrLanguage[i],NSILOCALE_MAX_ACCEPT_LENGTH);
332 } else {
333 /* simple case: no quality values */
335 cPtr = nsCRT::strtok(input,",",&cPtr2);
336 while (cPtr) {
337 if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LENGTH) { /* ignore if too long */
338 PL_strncpyz(acceptLanguageList[countLang++],cPtr,NSILOCALE_MAX_ACCEPT_LENGTH);
339 if (countLang>=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */
341 cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
346 // now create the locale
348 result = NS_ERROR_FAILURE;
349 if (countLang>0) {
350 result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval);
354 // clean up
356 return result;
360 nsresult
361 nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval)
363 nsCOMPtr<nsILocale> system_locale;
364 nsresult result;
366 result = GetSystemLocale(getter_AddRefs(system_locale));
367 if (NS_SUCCEEDED(result))
369 result = system_locale->
370 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval);
371 return result;
374 return result;
379 nsresult
380 NS_NewLocaleService(nsILocaleService** result)
382 if(!result)
383 return NS_ERROR_NULL_POINTER;
384 *result = new nsLocaleService();
385 if (! *result)
386 return NS_ERROR_OUT_OF_MEMORY;
387 NS_ADDREF(*result);
388 return NS_OK;