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/. */
8 #include <QtCore/QLocale>
12 #include "nsAutoPtr.h"
13 #include "nsILocale.h"
14 #include "nsILocaleService.h"
24 # include "nsWin32Locale.h"
25 #elif defined(XP_MACOSX)
26 # include <Carbon/Carbon.h>
27 #elif defined(XP_UNIX)
30 # include "nsPosixLocale.h"
34 // implementation constants
35 const int LocaleListLength
= 6;
36 const char* LocaleList
[LocaleListLength
] =
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
] =
57 #ifdef HAVE_I18N_LC_MESSAGES
66 // nsILocaleService implementation
68 class nsLocaleService
: public nsILocaleService
{
75 NS_DECL_THREADSAFE_ISUPPORTS
80 NS_DECL_NSILOCALESERVICE
83 nsLocaleService(void);
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)
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
);
121 #if defined(XP_UNIX) && !defined(XP_MACOSX)
122 nsRefPtr
<nsLocale
> resultLocale(new nsLocale());
123 NS_ENSURE_TRUE_VOID(resultLocale
);
126 const char* lang
= QLocale::system().name().toUtf8();
128 // Get system configuration
129 const char* lang
= getenv("LANG");
132 nsAutoString xpLocale
, platformLocale
;
133 nsAutoString category
, category_platform
;
136 for( i
= 0; i
< LocaleListLength
; i
++ ) {
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;
152 result
= nsPosixLocale::GetXPLocale(lc_temp
, xpLocale
);
153 CopyASCIItoUTF16(lc_temp
, platformLocale
);
155 if ( lang
== nullptr ) {
156 platformLocale
.AssignLiteral("en_US");
157 result
= nsPosixLocale::GetXPLocale("en-US", xpLocale
);
159 CopyASCIItoUTF16(lang
, platformLocale
);
160 result
= nsPosixLocale::GetXPLocale(lang
, xpLocale
);
163 if (NS_FAILED(result
)) {
166 resultLocale
->AddCategory(category
, xpLocale
);
167 resultLocale
->AddCategory(category_platform
, platformLocale
);
169 mSystemLocale
= do_QueryInterface(resultLocale
);
170 mApplicationLocale
= do_QueryInterface(resultLocale
);
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());
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");
203 nsLocaleService::~nsLocaleService(void)
207 NS_IMPL_ISUPPORTS(nsLocaleService
, nsILocaleService
)
210 nsLocaleService::NewLocale(const nsAString
&aLocale
, nsILocale
**_retval
)
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
;
230 NS_ADDREF(*_retval
= resultLocale
);
236 nsLocaleService::GetSystemLocale(nsILocale
**_retval
)
239 NS_ADDREF(*_retval
= mSystemLocale
);
243 *_retval
= (nsILocale
*)nullptr;
244 return NS_ERROR_FAILURE
;
248 nsLocaleService::GetApplicationLocale(nsILocale
**_retval
)
250 if (mApplicationLocale
) {
251 NS_ADDREF(*_retval
= mApplicationLocale
);
255 *_retval
=(nsILocale
*)nullptr;
256 return NS_ERROR_FAILURE
;
260 nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage
, nsILocale
**_retval
)
268 char acceptLanguageList
[NSILOCALE_MAX_ACCEPT_LANGUAGE
][NSILOCALE_MAX_ACCEPT_LENGTH
];
271 nsAutoArrayPtr
<char> input(new char[strlen(acceptLanguage
)+1]);
273 strcpy(input
, acceptLanguage
);
277 /* put in standard form */
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 */
289 if (strchr(input
,';')) {
290 /* deal with the quality values */
292 float qvalue
[NSILOCALE_MAX_ACCEPT_LANGUAGE
];
295 char* ptrLanguage
[NSILOCALE_MAX_ACCEPT_LANGUAGE
];
298 cPtr
= nsCRT::strtok(input
,",",&cPtr2
);
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
]);
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
]) {
320 qvalue
[i
] = qvalue
[j
];
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
);
333 /* simple case: no quality values */
335 cPtr
= nsCRT::strtok(input
,",",&cPtr2
);
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
;
350 result
= NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList
[0]), _retval
);
361 nsLocaleService::GetLocaleComponentForUserAgent(nsAString
& retval
)
363 nsCOMPtr
<nsILocale
> system_locale
;
366 result
= GetSystemLocale(getter_AddRefs(system_locale
));
367 if (NS_SUCCEEDED(result
))
369 result
= system_locale
->
370 GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE
), retval
);
380 NS_NewLocaleService(nsILocaleService
** result
)
383 return NS_ERROR_NULL_POINTER
;
384 *result
= new nsLocaleService();
386 return NS_ERROR_OUT_OF_MEMORY
;