1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 : #ifdef MOZ_WIDGET_QT
39 : #include <QString>
40 : #include <QtCore/QLocale>
41 : #endif
42 :
43 : #include "nsCOMPtr.h"
44 : #include "nsAutoPtr.h"
45 : #include "nsILocale.h"
46 : #include "nsILocaleService.h"
47 : #include "nsLocale.h"
48 : #include "nsLocaleCID.h"
49 : #include "nsServiceManagerUtils.h"
50 : #include "nsReadableUtils.h"
51 : #include "nsCRT.h"
52 : #include "prprf.h"
53 : #include "nsTArray.h"
54 :
55 : #include <ctype.h>
56 :
57 : #if defined(XP_WIN)
58 : # include "nsWin32Locale.h"
59 : #elif defined(XP_OS2)
60 : # include "unidef.h"
61 : # include "nsIOS2Locale.h"
62 : #elif defined(XP_MACOSX)
63 : # include <Carbon/Carbon.h>
64 : #elif defined(XP_UNIX)
65 : # include <locale.h>
66 : # include <stdlib.h>
67 : # include "nsPosixLocale.h"
68 : #endif
69 :
70 : //
71 : // implementation constants
72 : const int LocaleListLength = 6;
73 : const char* LocaleList[LocaleListLength] =
74 : {
75 : NSILOCALE_COLLATE,
76 : NSILOCALE_CTYPE,
77 : NSILOCALE_MONETARY,
78 : NSILOCALE_NUMERIC,
79 : NSILOCALE_TIME,
80 : NSILOCALE_MESSAGE
81 : };
82 :
83 : #define NSILOCALE_MAX_ACCEPT_LANGUAGE 16
84 : #define NSILOCALE_MAX_ACCEPT_LENGTH 18
85 :
86 : #if (defined(XP_UNIX) && !defined(XP_MACOSX)) || defined(XP_OS2)
87 : static int posix_locale_category[LocaleListLength] =
88 : {
89 : LC_COLLATE,
90 : LC_CTYPE,
91 : LC_MONETARY,
92 : LC_NUMERIC,
93 : LC_TIME,
94 : #ifdef HAVE_I18N_LC_MESSAGES
95 : LC_MESSAGES
96 : #else
97 : LC_CTYPE
98 : #endif
99 : };
100 : #endif
101 :
102 : //
103 : // nsILocaleService implementation
104 : //
105 : class nsLocaleService: public nsILocaleService {
106 :
107 : public:
108 :
109 : //
110 : // nsISupports
111 : //
112 : NS_DECL_ISUPPORTS
113 :
114 : //
115 : // nsILocaleService
116 : //
117 : NS_DECL_NSILOCALESERVICE
118 :
119 :
120 : nsLocaleService(void);
121 : virtual ~nsLocaleService(void);
122 :
123 : protected:
124 :
125 : nsresult SetSystemLocale(void);
126 : nsresult SetApplicationLocale(void);
127 :
128 : nsCOMPtr<nsILocale> mSystemLocale;
129 : nsCOMPtr<nsILocale> mApplicationLocale;
130 :
131 : };
132 :
133 : //
134 : // nsLocaleService methods
135 : //
136 83 : nsLocaleService::nsLocaleService(void)
137 83 : : mSystemLocale(0), mApplicationLocale(0)
138 : {
139 : #ifdef XP_WIN
140 : nsAutoString xpLocale;
141 : //
142 : // get the system LCID
143 : //
144 : LCID win_lcid = GetSystemDefaultLCID();
145 : NS_ENSURE_TRUE(win_lcid, );
146 : nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
147 : nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
148 : NS_ENSURE_SUCCESS(rv, );
149 :
150 : //
151 : // get the application LCID
152 : //
153 : win_lcid = GetUserDefaultLCID();
154 : NS_ENSURE_TRUE(win_lcid, );
155 : nsWin32Locale::GetXPLocale(win_lcid, xpLocale);
156 : rv = NewLocale(xpLocale, getter_AddRefs(mApplicationLocale));
157 : NS_ENSURE_SUCCESS(rv, );
158 : #endif
159 : #if defined(XP_UNIX) && !defined(XP_MACOSX)
160 166 : nsRefPtr<nsLocale> resultLocale(new nsLocale());
161 83 : NS_ENSURE_TRUE(resultLocale, );
162 :
163 : #ifdef MOZ_WIDGET_QT
164 : const char* lang = QLocale::system().name().toAscii();
165 : #else
166 : // Get system configuration
167 83 : const char* lang = getenv("LANG");
168 : #endif
169 :
170 166 : nsAutoString xpLocale, platformLocale;
171 249 : nsAutoString category, category_platform;
172 : int i;
173 :
174 581 : for( i = 0; i < LocaleListLength; i++ ) {
175 : nsresult result;
176 : // setlocale( , "") evaluates LC_* and LANG
177 498 : char* lc_temp = setlocale(posix_locale_category[i], "");
178 498 : CopyASCIItoUTF16(LocaleList[i], category);
179 498 : category_platform = category;
180 498 : category_platform.AppendLiteral("##PLATFORM");
181 498 : if (lc_temp != nsnull) {
182 498 : result = nsPosixLocale::GetXPLocale(lc_temp, xpLocale);
183 498 : CopyASCIItoUTF16(lc_temp, platformLocale);
184 : } else {
185 0 : if ( lang == nsnull ) {
186 0 : platformLocale.AssignLiteral("en_US");
187 0 : result = nsPosixLocale::GetXPLocale("en-US", xpLocale);
188 : } else {
189 0 : CopyASCIItoUTF16(lang, platformLocale);
190 0 : result = nsPosixLocale::GetXPLocale(lang, xpLocale);
191 : }
192 : }
193 498 : if (NS_FAILED(result)) {
194 : return;
195 : }
196 498 : resultLocale->AddCategory(category, xpLocale);
197 498 : resultLocale->AddCategory(category_platform, platformLocale);
198 : }
199 83 : mSystemLocale = do_QueryInterface(resultLocale);
200 166 : mApplicationLocale = do_QueryInterface(resultLocale);
201 :
202 : #endif // XP_UNIX
203 : #ifdef XP_OS2
204 : nsCOMPtr<nsIOS2Locale> os2Converter = do_GetService(NS_OS2LOCALE_CONTRACTID);
205 : nsAutoString xpLocale;
206 : if (os2Converter) {
207 : nsAutoString category;
208 : int i;
209 :
210 : nsRefPtr<nsLocale> resultLocale(new nsLocale());
211 : if ( resultLocale == NULL ) {
212 : return;
213 : }
214 :
215 : LocaleObject locale_object = NULL;
216 : int result = UniCreateLocaleObject(UNI_UCS_STRING_POINTER,
217 : (UniChar *)L"", &locale_object);
218 : if (result != ULS_SUCCESS) {
219 : int result = UniCreateLocaleObject(UNI_UCS_STRING_POINTER,
220 : (UniChar *)L"en_US", &locale_object);
221 : }
222 : char* lc_temp;
223 : for( i = 0; i < LocaleListLength; i++ ) {
224 : lc_temp = nsnull;
225 : UniQueryLocaleObject(locale_object,
226 : posix_locale_category[i],
227 : UNI_MBS_STRING_POINTER,
228 : (void **)&lc_temp);
229 : category.AssignASCII(LocaleList[i]);
230 : nsresult result;
231 : if (lc_temp != nsnull)
232 : result = os2Converter->GetXPLocale(lc_temp, xpLocale);
233 : else {
234 : char* lang = getenv("LANG");
235 : if ( lang == nsnull ) {
236 : result = os2Converter->GetXPLocale("en-US", xpLocale);
237 : }
238 : else
239 : result = os2Converter->GetXPLocale(lang, xpLocale);
240 : }
241 : if (NS_FAILED(result)) {
242 : UniFreeMem(lc_temp);
243 : UniFreeLocaleObject(locale_object);
244 : return;
245 : }
246 : resultLocale->AddCategory(category, xpLocale);
247 : UniFreeMem(lc_temp);
248 : }
249 : UniFreeLocaleObject(locale_object);
250 : mSystemLocale = do_QueryInterface(resultLocale);
251 : mApplicationLocale = do_QueryInterface(resultLocale);
252 : } // if ( NS_SUCCEEDED )...
253 : #endif // XP_OS2
254 :
255 : #ifdef XP_MACOSX
256 : // Get string representation of user's current locale
257 : CFLocaleRef userLocaleRef = ::CFLocaleCopyCurrent();
258 : CFStringRef userLocaleStr = ::CFLocaleGetIdentifier(userLocaleRef);
259 : ::CFRetain(userLocaleStr);
260 :
261 : nsAutoTArray<UniChar, 32> buffer;
262 : int size = ::CFStringGetLength(userLocaleStr);
263 : if (buffer.SetLength(size + 1))
264 : {
265 : CFRange range = ::CFRangeMake(0, size);
266 : ::CFStringGetCharacters(userLocaleStr, range, buffer.Elements());
267 : buffer[size] = 0;
268 :
269 : // Convert the locale string to the format that Mozilla expects
270 : nsAutoString xpLocale(buffer.Elements());
271 : xpLocale.ReplaceChar('_', '-');
272 :
273 : nsresult rv = NewLocale(xpLocale, getter_AddRefs(mSystemLocale));
274 : if (NS_SUCCEEDED(rv)) {
275 : mApplicationLocale = mSystemLocale;
276 : }
277 : }
278 :
279 : ::CFRelease(userLocaleStr);
280 : ::CFRelease(userLocaleRef);
281 :
282 : NS_ASSERTION(mApplicationLocale, "Failed to create locale objects");
283 : #endif // XP_MACOSX
284 : }
285 :
286 166 : nsLocaleService::~nsLocaleService(void)
287 : {
288 332 : }
289 :
290 2335 : NS_IMPL_THREADSAFE_ISUPPORTS1(nsLocaleService, nsILocaleService)
291 :
292 : NS_IMETHODIMP
293 0 : nsLocaleService::NewLocale(const nsAString &aLocale, nsILocale **_retval)
294 : {
295 : nsresult result;
296 :
297 0 : *_retval = nsnull;
298 :
299 0 : nsRefPtr<nsLocale> resultLocale(new nsLocale());
300 0 : if (!resultLocale) return NS_ERROR_OUT_OF_MEMORY;
301 :
302 0 : for (PRInt32 i = 0; i < LocaleListLength; i++) {
303 0 : NS_ConvertASCIItoUTF16 category(LocaleList[i]);
304 0 : result = resultLocale->AddCategory(category, aLocale);
305 0 : if (NS_FAILED(result)) return result;
306 : #if defined(XP_UNIX) && !defined(XP_MACOSX)
307 0 : category.AppendLiteral("##PLATFORM");
308 0 : result = resultLocale->AddCategory(category, aLocale);
309 0 : if (NS_FAILED(result)) return result;
310 : #endif
311 : }
312 :
313 0 : NS_ADDREF(*_retval = resultLocale);
314 0 : return NS_OK;
315 : }
316 :
317 :
318 : NS_IMETHODIMP
319 12 : nsLocaleService::GetSystemLocale(nsILocale **_retval)
320 : {
321 12 : if (mSystemLocale) {
322 12 : NS_ADDREF(*_retval = mSystemLocale);
323 12 : return NS_OK;
324 : }
325 :
326 0 : *_retval = (nsILocale*)nsnull;
327 0 : return NS_ERROR_FAILURE;
328 : }
329 :
330 : NS_IMETHODIMP
331 195 : nsLocaleService::GetApplicationLocale(nsILocale **_retval)
332 : {
333 195 : if (mApplicationLocale) {
334 195 : NS_ADDREF(*_retval = mApplicationLocale);
335 195 : return NS_OK;
336 : }
337 :
338 0 : *_retval=(nsILocale*)nsnull;
339 0 : return NS_ERROR_FAILURE;
340 : }
341 :
342 : NS_IMETHODIMP
343 0 : nsLocaleService::GetLocaleFromAcceptLanguage(const char *acceptLanguage, nsILocale **_retval)
344 : {
345 : char* input;
346 : char* cPtr;
347 : char* cPtr1;
348 : char* cPtr2;
349 : int i;
350 : int j;
351 0 : int countLang = 0;
352 : char acceptLanguageList[NSILOCALE_MAX_ACCEPT_LANGUAGE][NSILOCALE_MAX_ACCEPT_LENGTH];
353 : nsresult result;
354 :
355 0 : input = new char[strlen(acceptLanguage)+1];
356 0 : NS_ASSERTION(input!=nsnull,"nsLocaleFactory::GetLocaleFromAcceptLanguage: memory allocation failed.");
357 0 : if (input == (char*)NULL){ return NS_ERROR_OUT_OF_MEMORY; }
358 :
359 0 : strcpy(input, acceptLanguage);
360 0 : cPtr1 = input-1;
361 0 : cPtr2 = input;
362 :
363 : /* put in standard form */
364 0 : while (*(++cPtr1)) {
365 0 : if (isalpha(*cPtr1)) *cPtr2++ = tolower(*cPtr1); /* force lower case */
366 0 : else if (isspace(*cPtr1)) ; /* ignore any space */
367 0 : else if (*cPtr1=='-') *cPtr2++ = '_'; /* "-" -> "_" */
368 0 : else if (*cPtr1=='*') ; /* ignore "*" */
369 0 : else *cPtr2++ = *cPtr1; /* else unchanged */
370 : }
371 0 : *cPtr2 = '\0';
372 :
373 0 : countLang = 0;
374 :
375 0 : if (strchr(input,';')) {
376 : /* deal with the quality values */
377 :
378 : float qvalue[NSILOCALE_MAX_ACCEPT_LANGUAGE];
379 : float qSwap;
380 0 : float bias = 0.0f;
381 : char* ptrLanguage[NSILOCALE_MAX_ACCEPT_LANGUAGE];
382 : char* ptrSwap;
383 :
384 0 : cPtr = nsCRT::strtok(input,",",&cPtr2);
385 0 : while (cPtr) {
386 0 : qvalue[countLang] = 1.0f;
387 : /* add extra parens to get rid of warning */
388 0 : if ((cPtr1 = strchr(cPtr,';')) != nsnull) {
389 0 : PR_sscanf(cPtr1,";q=%f",&qvalue[countLang]);
390 0 : *cPtr1 = '\0';
391 : }
392 0 : if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LANGUAGE) { /* ignore if too long */
393 0 : qvalue[countLang] -= (bias += 0.0001f); /* to insure original order */
394 0 : ptrLanguage[countLang++] = cPtr;
395 0 : if (countLang>=NSILOCALE_MAX_ACCEPT_LANGUAGE) break; /* quit if too many */
396 : }
397 0 : cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
398 : }
399 :
400 : /* sort according to decending qvalue */
401 : /* not a very good algorithm, but count is not likely large */
402 0 : for ( i=0 ; i<countLang-1 ; i++ ) {
403 0 : for ( j=i+1 ; j<countLang ; j++ ) {
404 0 : if (qvalue[i]<qvalue[j]) {
405 0 : qSwap = qvalue[i];
406 0 : qvalue[i] = qvalue[j];
407 0 : qvalue[j] = qSwap;
408 0 : ptrSwap = ptrLanguage[i];
409 0 : ptrLanguage[i] = ptrLanguage[j];
410 0 : ptrLanguage[j] = ptrSwap;
411 : }
412 : }
413 : }
414 0 : for ( i=0 ; i<countLang ; i++ ) {
415 0 : PL_strncpyz(acceptLanguageList[i],ptrLanguage[i],NSILOCALE_MAX_ACCEPT_LENGTH);
416 : }
417 :
418 : } else {
419 : /* simple case: no quality values */
420 :
421 0 : cPtr = nsCRT::strtok(input,",",&cPtr2);
422 0 : while (cPtr) {
423 0 : if (strlen(cPtr)<NSILOCALE_MAX_ACCEPT_LENGTH) { /* ignore if too long */
424 0 : PL_strncpyz(acceptLanguageList[countLang++],cPtr,NSILOCALE_MAX_ACCEPT_LENGTH);
425 0 : if (countLang>=NSILOCALE_MAX_ACCEPT_LENGTH) break; /* quit if too many */
426 : }
427 0 : cPtr = nsCRT::strtok(cPtr2,",",&cPtr2);
428 : }
429 : }
430 :
431 : //
432 : // now create the locale
433 : //
434 0 : result = NS_ERROR_FAILURE;
435 0 : if (countLang>0) {
436 0 : result = NewLocale(NS_ConvertASCIItoUTF16(acceptLanguageList[0]), _retval);
437 : }
438 :
439 : //
440 : // clean up
441 : //
442 0 : delete[] input;
443 0 : return result;
444 : }
445 :
446 :
447 : nsresult
448 12 : nsLocaleService::GetLocaleComponentForUserAgent(nsAString& retval)
449 : {
450 24 : nsCOMPtr<nsILocale> system_locale;
451 : nsresult result;
452 :
453 12 : result = GetSystemLocale(getter_AddRefs(system_locale));
454 12 : if (NS_SUCCEEDED(result))
455 : {
456 12 : result = system_locale->
457 12 : GetCategory(NS_LITERAL_STRING(NSILOCALE_MESSAGE), retval);
458 12 : return result;
459 : }
460 :
461 0 : return result;
462 : }
463 :
464 :
465 :
466 : nsresult
467 83 : NS_NewLocaleService(nsILocaleService** result)
468 : {
469 83 : if(!result)
470 0 : return NS_ERROR_NULL_POINTER;
471 83 : *result = new nsLocaleService();
472 83 : if (! *result)
473 0 : return NS_ERROR_OUT_OF_MEMORY;
474 83 : NS_ADDREF(*result);
475 83 : return NS_OK;
476 : }
|