]> git.ipfire.org Git - thirdparty/cups.git/blob - cups/language.c
Update copyright notices, addresses, etc.
[thirdparty/cups.git] / cups / language.c
1 /*
2 * "$Id$"
3 *
4 * I18N/language support for the Common UNIX Printing System (CUPS).
5 *
6 * Copyright 1997-2005 by Easy Software Products.
7 *
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
13 * at:
14 *
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
19 *
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
23 *
24 * This file is subject to the Apple OS-Developed Software exception.
25 *
26 * Contents:
27 *
28 * cupsEncodingName() - Return the character encoding name string
29 * for the given encoding enumeration.
30 * cupsLangEncoding() - Return the character encoding (us-ascii, etc.)
31 * for the given language.
32 * cupsLangFlush() - Flush all language data out of the cache.
33 * cupsLangFree() - Free language data.
34 * cupsLangGet() - Get a language.
35 * _cupsRestoreLocale() - Restore the original locale...
36 * _cupsSaveLocale() - Set the locale and save a copy of the old locale...
37 * appleLangDefault() - Get the default locale string.
38 * cups_cache_lookup() - Lookup a language in the cache...
39 */
40
41 /*
42 * Include necessary headers...
43 */
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <ctype.h>
48 #ifdef HAVE_LANGINFO_H
49 # include <langinfo.h>
50 #endif /* HAVE_LANGINFO_H */
51 #ifdef WIN32
52 # include <io.h>
53 #else
54 # include <unistd.h>
55 #endif /* WIN32 */
56 #include "string.h"
57 #include "language.h"
58 #include "debug.h"
59
60
61 /*
62 * Local functions...
63 */
64
65 #ifdef __APPLE__
66 # include <CoreFoundation/CoreFoundation.h>
67 static const char *appleLangDefault(void);
68 #endif /* __APPLE__ */
69
70 static cups_lang_t *cups_cache_lookup(const char *name,
71 cups_encoding_t encoding);
72
73
74 /*
75 * Local globals...
76 */
77
78 static cups_lang_t *lang_cache = NULL;
79 /* Language string cache */
80 static const char *lang_blank = "";
81 /* Blank constant string */
82 static const char * const lang_encodings[] =
83 { /* Encoding strings */
84 "us-ascii", "iso-8859-1",
85 "iso-8859-2", "iso-8859-3",
86 "iso-8859-4", "iso-8859-5",
87 "iso-8859-6", "iso-8859-7",
88 "iso-8859-8", "iso-8859-9",
89 "iso-8859-10", "utf-8",
90 "iso-8859-13", "iso-8859-14",
91 "iso-8859-15", "windows-874",
92 "windows-1250", "windows-1251",
93 "windows-1252", "windows-1253",
94 "windows-1254", "windows-1255",
95 "windows-1256", "windows-1257",
96 "windows-1258", "koi8-r",
97 "koi8-u", "iso-8859-11",
98 "iso-8859-16", "unknown",
99 "unknown", "unknown",
100 "unknown", "unknown",
101 "unknown", "unknown",
102 "unknown", "unknown",
103 "unknown", "unknown",
104 "unknown", "unknown",
105 "unknown", "unknown",
106 "unknown", "unknown",
107 "unknown", "unknown",
108 "unknown", "unknown",
109 "unknown", "unknown",
110 "unknown", "unknown",
111 "unknown", "unknown",
112 "unknown", "unknown",
113 "unknown", "unknown",
114 "unknown", "unknown",
115 "unknown", "unknown",
116 "windows-932", "windows-936",
117 "windows-949", "windows-950",
118 "windows-1361", "unknown",
119 "unknown", "unknown",
120 "unknown", "unknown",
121 "unknown", "unknown",
122 "unknown", "unknown",
123 "unknown", "unknown",
124 "unknown", "unknown",
125 "unknown", "unknown",
126 "unknown", "unknown",
127 "unknown", "unknown",
128 "unknown", "unknown",
129 "unknown", "unknown",
130 "unknown", "unknown",
131 "unknown", "unknown",
132 "unknown", "unknown",
133 "unknown", "unknown",
134 "unknown", "unknown",
135 "unknown", "unknown",
136 "unknown", "unknown",
137 "unknown", "unknown",
138 "unknown", "unknown",
139 "unknown", "unknown",
140 "unknown", "unknown",
141 "unknown", "unknown",
142 "unknown", "unknown",
143 "unknown", "unknown",
144 "unknown", "unknown",
145 "unknown", "unknown",
146 "unknown", "unknown",
147 "unknown", "unknown",
148 "euc-cn", "euc-jp",
149 "euc-kr", "euc-tw"
150 };
151 static const char *const lang_default[] =
152 { /* Default POSIX locale */
153 #include "cups_C.h"
154 NULL
155 };
156
157
158 /*
159 * 'cupsEncodingName()' - Return the character encoding name string
160 * for the given encoding enumeration.
161 */
162
163 const char * /* O - Character encoding */
164 cupsEncodingName(cups_encoding_t encoding)
165 /* I - Encoding enum */
166 {
167 if (encoding < 0 ||
168 encoding >= (sizeof(lang_encodings) / sizeof(const char *)))
169 return (lang_encodings[0]);
170 else
171 return (lang_encodings[encoding]);
172 }
173
174
175 /*
176 * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
177 * for the given language.
178 */
179
180 const char * /* O - Character encoding */
181 cupsLangEncoding(cups_lang_t *lang) /* I - Language data */
182 {
183 if (lang == NULL)
184 return ((char*)lang_encodings[0]);
185 else
186 return ((char*)lang_encodings[lang->encoding]);
187 }
188
189
190 /*
191 * 'cupsLangFlush()' - Flush all language data out of the cache.
192 */
193
194 void
195 cupsLangFlush(void)
196 {
197 int i; /* Looping var */
198 cups_lang_t *lang, /* Current language */
199 *next; /* Next language */
200
201
202 /*
203 * Free all languages in the cache...
204 */
205
206 for (lang = lang_cache; lang != NULL; lang = next)
207 {
208 /*
209 * Free all messages...
210 */
211
212 for (i = 0; i < CUPS_MSG_MAX; i ++)
213 if (lang->messages[i] != NULL && lang->messages[i] != lang_blank)
214 free(lang->messages[i]);
215
216 /*
217 * Then free the language structure itself...
218 */
219
220 next = lang->next;
221 free(lang);
222 }
223
224 lang_cache = NULL;
225 }
226
227
228 /*
229 * 'cupsLangFree()' - Free language data.
230 *
231 * This does not actually free anything; use cupsLangFlush() for that.
232 */
233
234 void
235 cupsLangFree(cups_lang_t *lang) /* I - Language to free */
236 {
237 if (lang != NULL && lang->used > 0)
238 lang->used --;
239 }
240
241
242 /*
243 * 'cupsLangGet()' - Get a language.
244 */
245
246 cups_lang_t * /* O - Language data */
247 cupsLangGet(const char *language) /* I - Language or locale */
248 {
249 int i, count; /* Looping vars */
250 char locale[255], /* Copy of locale name */
251 langname[16], /* Requested language name */
252 country[16], /* Country code */
253 charset[16], /* Character set */
254 #ifdef CODESET
255 *csptr, /* Pointer to CODESET string */
256 #endif /* CODESET */
257 *ptr, /* Pointer into language/charset */
258 real[48], /* Real language name */
259 filename[1024], /* Filename for language locale file */
260 *localedir; /* Directory for locale files */
261 cups_encoding_t encoding; /* Encoding to use */
262 FILE *fp; /* Language locale file pointer */
263 char line[1024]; /* Line from file */
264 cups_msg_t msg; /* Message number */
265 char *text; /* Message text */
266 cups_lang_t *lang; /* Current language... */
267 char *oldlocale; /* Old locale name */
268 static const char * const locale_encodings[] =
269 { /* Locale charset names */
270 "ASCII", "ISO88591", "ISO88592", "ISO88593",
271 "ISO88594", "ISO88595", "ISO88596", "ISO88597",
272 "ISO88598", "ISO88599", "ISO885910", "UTF8",
273 "ISO885913", "ISO885914", "ISO885915", "CP874",
274 "CP1250", "CP1251", "CP1252", "CP1253",
275 "CP1254", "CP1255", "CP1256", "CP1257",
276 "CP1258", "KOI8R", "KOI8U", "ISO885911",
277 "ISO885916", "", "", "",
278
279 "", "", "", "",
280 "", "", "", "",
281 "", "", "", "",
282 "", "", "", "",
283 "", "", "", "",
284 "", "", "", "",
285 "", "", "", "",
286 "", "", "", "",
287
288 "CP932", "CP936", "CP949", "CP950",
289 "CP1361", "", "", "",
290 "", "", "", "",
291 "", "", "", "",
292 "", "", "", "",
293 "", "", "", "",
294 "", "", "", "",
295 "", "", "", "",
296
297 "", "", "", "",
298 "", "", "", "",
299 "", "", "", "",
300 "", "", "", "",
301 "", "", "", "",
302 "", "", "", "",
303 "", "", "", "",
304 "", "", "", "",
305
306 "EUCCN", "EUCJP", "EUCKR", "EUCTW"
307 };
308
309
310 DEBUG_printf(("cupsLangGet(language=\"%s\")\n", language ? language : "(null)"));
311
312 #ifdef __APPLE__
313 /*
314 * Apple's setlocale doesn't give us the user's localization
315 * preference so we have to look it up this way...
316 */
317
318 if (language == NULL)
319 language = appleLangDefault();
320 #else
321 if (language == NULL)
322 {
323 /*
324 * First see if the locale has been set; if it is still "C" or
325 * "POSIX", set the locale to the default...
326 */
327
328 # ifdef LC_MESSAGES
329 ptr = setlocale(LC_MESSAGES, NULL);
330 # else
331 ptr = setlocale(LC_ALL, NULL);
332 # endif /* LC_MESSAGES */
333
334 DEBUG_printf(("cupsLangGet: current locale is \"%s\"\n",
335 ptr ? ptr : "(null)"));
336
337 if (!ptr || !strcmp(ptr, "C") || !strcmp(ptr, "POSIX"))
338 # ifdef LC_MESSAGES
339 {
340 ptr = setlocale(LC_MESSAGES, "");
341 setlocale(LC_CTYPE, "");
342 }
343 # else
344 ptr = setlocale(LC_ALL, "");
345 # endif /* LC_MESSAGES */
346
347 if (ptr)
348 {
349 strlcpy(locale, ptr, sizeof(locale));
350 language = locale;
351
352 DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n",
353 language ? language : "(null)"));
354 }
355 }
356 #endif /* __APPLE__ */
357
358 /*
359 * If "language" is NULL at this point, then chances are we are using
360 * a language that is not installed for the base OS.
361 */
362
363 if (!language)
364 {
365 /*
366 * Switch to the value of the "LANG" environment variable, and if
367 * that is NULL as well, use "C".
368 */
369
370 if ((language = getenv("LANG")) == NULL)
371 language = "C";
372 }
373
374 /*
375 * Set the charset to "unknown"...
376 */
377
378 charset[0] = '\0';
379
380 #ifdef CODESET
381 /*
382 * On systems that support the nl_langinfo(CODESET) call, use
383 * this value as the character set...
384 */
385
386 if ((csptr = nl_langinfo(CODESET)) != NULL)
387 {
388 /*
389 * Copy all of the letters and numbers in the CODESET string...
390 */
391
392 for (ptr = charset; *csptr; csptr ++)
393 if (isalnum(*csptr & 255) && ptr < (charset + sizeof(charset) - 1))
394 *ptr++ = *csptr;
395
396 *ptr = '\0';
397
398 DEBUG_printf(("cupsLangGet: charset set to \"%s\" via nl_langinfo(CODESET)...\n",
399 charset));
400 }
401 #endif /* CODESET */
402
403 /*
404 * Set the locale back to POSIX while we do string ops, since
405 * apparently some buggy C libraries break ctype() for non-I18N
406 * chars...
407 */
408
409 #if defined(__APPLE__)
410 /* The ctype bug isn't in Apple's libc */
411 #elif !defined(LC_CTYPE)
412 oldlocale = _cupsSaveLocale(LC_ALL, "C");
413 #else
414 oldlocale = _cupsSaveLocale(LC_CTYPE, "C");
415 #endif /* __APPLE__ */
416
417 /*
418 * Parse the language string passed in to a locale string. "C" is the
419 * standard POSIX locale and is copied unchanged. Otherwise the
420 * language string is converted from ll-cc[.charset] (language-country)
421 * to ll_CC[.CHARSET] to match the file naming convention used by all
422 * POSIX-compliant operating systems. Invalid language names are mapped
423 * to the POSIX locale.
424 */
425
426 country[0] = '\0';
427
428 if (language == NULL || !language[0] ||
429 strcmp(language, "POSIX") == 0)
430 strcpy(langname, "C");
431 else
432 {
433 /*
434 * Copy the parts of the locale string over safely...
435 */
436
437 for (ptr = langname; *language; language ++)
438 if (*language == '_' || *language == '-' || *language == '.')
439 break;
440 else if (ptr < (langname + sizeof(langname) - 1))
441 *ptr++ = tolower(*language & 255);
442
443 *ptr = '\0';
444
445 if (*language == '_' || *language == '-')
446 {
447 /*
448 * Copy the country code...
449 */
450
451 for (language ++, ptr = country; *language; language ++)
452 if (*language == '.')
453 break;
454 else if (ptr < (country + sizeof(country) - 1))
455 *ptr++ = toupper(*language & 255);
456
457 *ptr = '\0';
458 }
459
460 if (*language == '.' && !charset[0])
461 {
462 /*
463 * Copy the encoding...
464 */
465
466 for (language ++, ptr = charset; *language; language ++)
467 if (isalnum(*language & 255) && ptr < (charset + sizeof(charset) - 1))
468 *ptr++ = toupper(*language & 255);
469
470 *ptr = '\0';
471 }
472
473 /*
474 * Force a POSIX locale for an invalid language name...
475 */
476
477 if (strlen(langname) != 2)
478 {
479 strcpy(langname, "C");
480 country[0] = '\0';
481 charset[0] = '\0';
482 }
483 }
484
485 /*
486 * Restore the locale...
487 */
488
489 #if defined(__APPLE__)
490 /* The ctype bug isn't in Apple's libc */
491 #elif !defined(LC_CTYPE)
492 _cupsRestoreLocale(LC_ALL, oldlocale);
493 #else
494 _cupsRestoreLocale(LC_CTYPE, oldlocale);
495 #endif /* __APPLE__ */
496
497 DEBUG_printf(("cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"\n",
498 langname, country, charset));
499
500 /*
501 * Figure out the desired encoding...
502 */
503
504 encoding = CUPS_AUTO_ENCODING;
505
506 if (charset[0])
507 {
508 for (i = 0; i < (int)(sizeof(locale_encodings) / sizeof(locale_encodings[0])); i ++)
509 if (!strcasecmp(charset, locale_encodings[i]))
510 {
511 encoding = (cups_encoding_t)i;
512 break;
513 }
514 }
515
516 DEBUG_printf(("cupsLangGet: encoding=%d(%s)\n", encoding,
517 encoding == CUPS_AUTO_ENCODING ? "auto" :
518 lang_encodings[encoding]));
519
520 /*
521 * Now find the message catalog for this locale...
522 */
523
524 if ((localedir = getenv("LOCALEDIR")) == NULL)
525 localedir = CUPS_LOCALEDIR;
526
527 /*
528 * See if we already have this language/country loaded...
529 */
530
531 snprintf(real, sizeof(real), "%s_%s", langname, country);
532
533 if ((lang = cups_cache_lookup(real, encoding)) != NULL)
534 return (lang);
535
536 snprintf(filename, sizeof(filename), "%s/%s/cups_%s", localedir, real, real);
537
538 if (!country[0] || access(filename, 0))
539 {
540 /*
541 * Country localization not available, look for generic localization...
542 */
543
544 if ((lang = cups_cache_lookup(langname, encoding)) != NULL)
545 return (lang);
546
547 snprintf(filename, sizeof(filename), "%s/%s/cups_%s", localedir,
548 langname, langname);
549
550 if (access(filename, 0))
551 {
552 /*
553 * No generic localization, so use POSIX...
554 */
555
556 strcpy(real, "C");
557 snprintf(filename, sizeof(filename), "%s/C/cups_C", localedir);
558 }
559 else
560 strcpy(real, langname);
561 }
562
563 /*
564 * Open the messages file; the first line contains the default
565 * language encoding (us-ascii, iso-8859-1, etc.), and the rest are
566 * messages consisting of:
567 *
568 * #### SP message text
569 *
570 * or:
571 *
572 * message text
573 *
574 * If the line starts with a number, then message processing picks up
575 * where the number indicates. Otherwise the last message number is
576 * incremented.
577 *
578 * All leading whitespace is deleted.
579 */
580
581 if (strcmp(real, "C"))
582 fp = fopen(filename, "r");
583 else
584 fp = NULL;
585
586 if (fp == NULL)
587 strlcpy(line, lang_default[0], sizeof(line));
588 else if (fgets(line, sizeof(line), fp) == NULL)
589 {
590 /*
591 * Can't read encoding!
592 */
593
594 fclose(fp);
595 return (NULL);
596 }
597
598 i = strlen(line) - 1;
599 if (line[i] == '\n')
600 line[i] = '\0'; /* Strip LF */
601
602 /*
603 * See if there is a free language available; if so, use that
604 * record...
605 */
606
607 for (lang = lang_cache; lang != NULL; lang = lang->next)
608 if (lang->used == 0)
609 break;
610
611 if (lang == NULL)
612 {
613 /*
614 * Allocate memory for the language and add it to the cache.
615 */
616
617 if ((lang = calloc(sizeof(cups_lang_t), 1)) == NULL)
618 {
619 fclose(fp);
620 return (NULL);
621 }
622
623 lang->next = lang_cache;
624 lang_cache = lang;
625 }
626
627 /*
628 * Free all old strings as needed...
629 */
630
631 for (i = 0; i < CUPS_MSG_MAX; i ++)
632 {
633 if (lang->messages[i] != NULL && lang->messages[i] != lang_blank)
634 free(lang->messages[i]);
635
636 lang->messages[i] = (char *)lang_blank;
637 }
638
639 /*
640 * Then assign the language and encoding fields...
641 */
642
643 lang->used ++;
644 strlcpy(lang->language, real, sizeof(lang->language));
645
646 if (encoding != CUPS_AUTO_ENCODING)
647 lang->encoding = encoding;
648 else
649 {
650 lang->encoding = CUPS_US_ASCII;
651
652 for (i = 0; i < (sizeof(lang_encodings) / sizeof(lang_encodings[0])); i ++)
653 if (strcmp(lang_encodings[i], line) == 0)
654 {
655 lang->encoding = (cups_encoding_t)i;
656 break;
657 }
658 }
659
660 /*
661 * Read the strings from the file...
662 */
663
664 msg = (cups_msg_t)-1;
665 count = 1;
666
667 for (;;)
668 {
669 /*
670 * Read a line from memory or from a file...
671 */
672
673 if (fp == NULL)
674 {
675 if (lang_default[count] == NULL)
676 break;
677
678 strlcpy(line, lang_default[count], sizeof(line));
679 }
680 else if (fgets(line, sizeof(line), fp) == NULL)
681 break;
682
683 count ++;
684
685 /*
686 * Ignore blank lines...
687 */
688
689 i = strlen(line) - 1;
690 if (line[i] == '\n')
691 line[i] = '\0'; /* Strip LF */
692
693 if (line[0] == '\0')
694 continue;
695
696 /*
697 * Grab the message number and text...
698 */
699
700 if (isdigit(line[0] & 255))
701 msg = (cups_msg_t)atoi(line);
702 else
703 msg ++;
704
705 if (msg < 0 || msg >= CUPS_MSG_MAX)
706 continue;
707
708 text = line;
709 while (isdigit(*text & 255))
710 text ++;
711 while (isspace(*text & 255))
712 text ++;
713
714 lang->messages[msg] = strdup(text);
715 }
716
717 /*
718 * Close the file and return...
719 */
720
721 if (fp != NULL)
722 fclose(fp);
723
724 return (lang);
725 }
726
727
728 /*
729 * '_cupsRestoreLocale()' - Restore the original locale...
730 */
731
732 void
733 _cupsRestoreLocale(int category, /* I - Category */
734 char *oldlocale) /* I - Old locale or NULL */
735 {
736 DEBUG_printf(("_cupsRestoreLocale(category=%d, oldlocale=\"%s\")\n",
737 category, oldlocale));
738
739 if (oldlocale)
740 {
741 /*
742 * Reset the locale and free the locale string...
743 */
744
745 setlocale(category, oldlocale);
746 free(oldlocale);
747 }
748 }
749
750
751 /*
752 * '_cupsSaveLocale()' - Set the locale and save a copy of the old locale...
753 */
754
755 char * /* O - Old locale or NULL */
756 _cupsSaveLocale(int category, /* I - Category */
757 const char *locale) /* I - New locale or NULL */
758 {
759 char *oldlocale; /* Old locale */
760
761
762 DEBUG_printf(("_cupsSaveLocale(category=%d, locale=\"%s\")\n",
763 category, locale));
764
765 /*
766 * Get the old locale and copy it...
767 */
768
769 if ((oldlocale = setlocale(category, NULL)) != NULL)
770 oldlocale = strdup(oldlocale);
771
772 DEBUG_printf((" oldlocale=\"%s\"\n", oldlocale ? oldlocale : "(null)"));
773
774 /*
775 * Set the new locale...
776 */
777
778 setlocale(category, locale);
779
780 /*
781 * Return a copy of the old locale...
782 */
783
784 return (oldlocale);
785 }
786
787
788 #ifdef __APPLE__
789 /*
790 * Code & data to translate OSX's language names to their ISO 639-1 locale.
791 *
792 * The first version uses the new CoreFoundation API added in 10.3 (Panther),
793 * the second is for 10.2 (Jaguar).
794 */
795
796 # ifdef HAVE_CF_LOCALE_ID
797 /*
798 * 'appleLangDefault()' - Get the default locale string.
799 */
800
801 static const char * /* O - Locale string */
802 appleLangDefault(void)
803 {
804 CFPropertyListRef localizationList;
805 /* List of localization data */
806 CFStringRef languageName; /* Current name */
807 CFStringRef localeName; /* Canonical from of name */
808 static char language[32] = "";
809 /* Cached language */
810
811
812 /*
813 * Only do the lookup and translation the first time.
814 */
815
816 if (!language[0])
817 {
818 localizationList =
819 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
820 kCFPreferencesCurrentApplication);
821
822 if (localizationList != NULL)
823 {
824 if (CFGetTypeID(localizationList) == CFArrayGetTypeID() &&
825 CFArrayGetCount(localizationList) > 0)
826 {
827 languageName = CFArrayGetValueAtIndex(localizationList, 0);
828
829 if (languageName != NULL &&
830 CFGetTypeID(languageName) == CFStringGetTypeID())
831 {
832 localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(
833 kCFAllocatorDefault, languageName);
834
835 if (localeName != NULL)
836 {
837 CFStringGetCString(localeName, language, sizeof(language),
838 kCFStringEncodingASCII);
839 CFRelease(localeName);
840
841 if (!strcmp(language, "en"))
842 strlcpy(language, "en_US.UTF-8", sizeof(language));
843 else if (strchr(language, '.') == NULL)
844 strlcat(language, ".UTF-8", sizeof(language));
845 }
846 }
847 }
848
849 CFRelease(localizationList);
850 }
851
852 /*
853 * If we didn't find the language, default to en_US...
854 */
855
856 if (!language[0])
857 strlcpy(language, "en_US.UTF-8", sizeof(language));
858 }
859
860 /*
861 * Return the cached locale...
862 */
863
864 return (language);
865 }
866 # else
867 /*
868 * Code & data to translate OSX 10.2's language names to their ISO 639-1
869 * locale.
870 */
871
872 typedef struct
873 {
874 const char * const name; /* Language name */
875 const char * const locale; /* Locale name */
876 } apple_name_locale_t;
877
878 static const apple_name_locale_t apple_name_locale[] =
879 {
880 { "English" , "en_US.UTF-8" }, { "French" , "fr.UTF-8" },
881 { "German" , "de.UTF-8" }, { "Italian" , "it.UTF-8" },
882 { "Dutch" , "nl.UTF-8" }, { "Swedish" , "sv.UTF-8" },
883 { "Spanish" , "es.UTF-8" }, { "Danish" , "da.UTF-8" },
884 { "Portuguese" , "pt.UTF-8" }, { "Norwegian" , "no.UTF-8" },
885 { "Hebrew" , "he.UTF-8" }, { "Japanese" , "ja.UTF-8" },
886 { "Arabic" , "ar.UTF-8" }, { "Finnish" , "fi.UTF-8" },
887 { "Greek" , "el.UTF-8" }, { "Icelandic" , "is.UTF-8" },
888 { "Maltese" , "mt.UTF-8" }, { "Turkish" , "tr.UTF-8" },
889 { "Croatian" , "hr.UTF-8" }, { "Chinese" , "zh.UTF-8" },
890 { "Urdu" , "ur.UTF-8" }, { "Hindi" , "hi.UTF-8" },
891 { "Thai" , "th.UTF-8" }, { "Korean" , "ko.UTF-8" },
892 { "Lithuanian" , "lt.UTF-8" }, { "Polish" , "pl.UTF-8" },
893 { "Hungarian" , "hu.UTF-8" }, { "Estonian" , "et.UTF-8" },
894 { "Latvian" , "lv.UTF-8" }, { "Sami" , "se.UTF-8" },
895 { "Faroese" , "fo.UTF-8" }, { "Farsi" , "fa.UTF-8" },
896 { "Russian" , "ru.UTF-8" }, { "Chinese" , "zh.UTF-8" },
897 { "Dutch" , "nl.UTF-8" }, { "Irish" , "ga.UTF-8" },
898 { "Albanian" , "sq.UTF-8" }, { "Romanian" , "ro.UTF-8" },
899 { "Czech" , "cs.UTF-8" }, { "Slovak" , "sk.UTF-8" },
900 { "Slovenian" , "sl.UTF-8" }, { "Yiddish" , "yi.UTF-8" },
901 { "Serbian" , "sr.UTF-8" }, { "Macedonian" , "mk.UTF-8" },
902 { "Bulgarian" , "bg.UTF-8" }, { "Ukrainian" , "uk.UTF-8" },
903 { "Byelorussian", "be.UTF-8" }, { "Uzbek" , "uz.UTF-8" },
904 { "Kazakh" , "kk.UTF-8" }, { "Azerbaijani", "az.UTF-8" },
905 { "Azerbaijani" , "az.UTF-8" }, { "Armenian" , "hy.UTF-8" },
906 { "Georgian" , "ka.UTF-8" }, { "Moldavian" , "mo.UTF-8" },
907 { "Kirghiz" , "ky.UTF-8" }, { "Tajiki" , "tg.UTF-8" },
908 { "Turkmen" , "tk.UTF-8" }, { "Mongolian" , "mn.UTF-8" },
909 { "Mongolian" , "mn.UTF-8" }, { "Pashto" , "ps.UTF-8" },
910 { "Kurdish" , "ku.UTF-8" }, { "Kashmiri" , "ks.UTF-8" },
911 { "Sindhi" , "sd.UTF-8" }, { "Tibetan" , "bo.UTF-8" },
912 { "Nepali" , "ne.UTF-8" }, { "Sanskrit" , "sa.UTF-8" },
913 { "Marathi" , "mr.UTF-8" }, { "Bengali" , "bn.UTF-8" },
914 { "Assamese" , "as.UTF-8" }, { "Gujarati" , "gu.UTF-8" },
915 { "Punjabi" , "pa.UTF-8" }, { "Oriya" , "or.UTF-8" },
916 { "Malayalam" , "ml.UTF-8" }, { "Kannada" , "kn.UTF-8" },
917 { "Tamil" , "ta.UTF-8" }, { "Telugu" , "te.UTF-8" },
918 { "Sinhalese" , "si.UTF-8" }, { "Burmese" , "my.UTF-8" },
919 { "Khmer" , "km.UTF-8" }, { "Lao" , "lo.UTF-8" },
920 { "Vietnamese" , "vi.UTF-8" }, { "Indonesian" , "id.UTF-8" },
921 { "Tagalog" , "tl.UTF-8" }, { "Malay" , "ms.UTF-8" },
922 { "Malay" , "ms.UTF-8" }, { "Amharic" , "am.UTF-8" },
923 { "Tigrinya" , "ti.UTF-8" }, { "Oromo" , "om.UTF-8" },
924 { "Somali" , "so.UTF-8" }, { "Swahili" , "sw.UTF-8" },
925 { "Kinyarwanda" , "rw.UTF-8" }, { "Rundi" , "rn.UTF-8" },
926 { "Nyanja" , "" }, { "Malagasy" , "mg.UTF-8" },
927 { "Esperanto" , "eo.UTF-8" }, { "Welsh" , "cy.UTF-8" },
928 { "Basque" , "eu.UTF-8" }, { "Catalan" , "ca.UTF-8" },
929 { "Latin" , "la.UTF-8" }, { "Quechua" , "qu.UTF-8" },
930 { "Guarani" , "gn.UTF-8" }, { "Aymara" , "ay.UTF-8" },
931 { "Tatar" , "tt.UTF-8" }, { "Uighur" , "ug.UTF-8" },
932 { "Dzongkha" , "dz.UTF-8" }, { "Javanese" , "jv.UTF-8" },
933 { "Sundanese" , "su.UTF-8" }, { "Galician" , "gl.UTF-8" },
934 { "Afrikaans" , "af.UTF-8" }, { "Breton" , "br.UTF-8" },
935 { "Inuktitut" , "iu.UTF-8" }, { "Scottish" , "gd.UTF-8" },
936 { "Manx" , "gv.UTF-8" }, { "Irish" , "ga.UTF-8" },
937 { "Tongan" , "to.UTF-8" }, { "Greek" , "el.UTF-8" },
938 { "Greenlandic" , "kl.UTF-8" }, { "Azerbaijani", "az.UTF-8" }
939 };
940
941
942 /*
943 * 'appleLangDefault()' - Get the default locale string.
944 */
945
946 static const char * /* O - Locale string */
947 appleLangDefault(void)
948 {
949 int i; /* Looping var */
950 CFPropertyListRef localizationList;
951 /* List of localization data */
952 CFStringRef localizationName;
953 /* Current name */
954 char buff[256]; /* Temporary buffer */
955 static const char *language = NULL;
956 /* Cached language */
957
958
959 /*
960 * Only do the lookup and translation the first time.
961 */
962
963 if (language == NULL)
964 {
965 localizationList =
966 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
967 kCFPreferencesCurrentApplication);
968
969 if (localizationList != NULL)
970 {
971 if (CFGetTypeID(localizationList) == CFArrayGetTypeID() &&
972 CFArrayGetCount(localizationList) > 0)
973 {
974 localizationName = CFArrayGetValueAtIndex(localizationList, 0);
975
976 if (localizationName != NULL &&
977 CFGetTypeID(localizationName) == CFStringGetTypeID())
978 {
979 CFIndex length = CFStringGetLength(localizationName);
980
981 if (length <= sizeof(buff) &&
982 CFStringGetCString(localizationName, buff, sizeof(buff),
983 kCFStringEncodingASCII))
984 {
985 buff[sizeof(buff) - 1] = '\0';
986
987 for (i = 0;
988 i < sizeof(apple_name_locale) / sizeof(apple_name_locale[0]);
989 i++)
990 {
991 if (strcasecmp(buff, apple_name_locale[i].name) == 0)
992 {
993 language = apple_name_locale[i].locale;
994 break;
995 }
996 }
997 }
998 }
999 }
1000
1001 CFRelease(localizationList);
1002 }
1003
1004 /*
1005 * If we didn't find the language, default to en_US...
1006 */
1007
1008 if (language == NULL)
1009 language = apple_name_locale[0].locale;
1010 }
1011
1012 /*
1013 * Return the cached locale...
1014 */
1015
1016 return (language);
1017 }
1018 # endif /* HAVE_CF_LOCALE_ID */
1019 #endif /* __APPLE__ */
1020
1021
1022 /*
1023 * 'cups_cache_lookup()' - Lookup a language in the cache...
1024 */
1025
1026 static cups_lang_t * /* O - Language data or NULL */
1027 cups_cache_lookup(const char *name,/* I - Name of locale */
1028 cups_encoding_t encoding)
1029 /* I - Encoding of locale */
1030 {
1031 cups_lang_t *lang; /* Current language */
1032
1033
1034 DEBUG_printf(("cups_cache_lookup(name=\"%s\", encoding=%d(%s))\n", name,
1035 encoding, encoding == CUPS_AUTO_ENCODING ? "auto" :
1036 lang_encodings[encoding]));
1037
1038 /*
1039 * Loop through the cache and return a match if found...
1040 */
1041
1042 for (lang = lang_cache; lang != NULL; lang = lang->next)
1043 {
1044 DEBUG_printf(("cups_cache_lookup: lang=%p, language=\"%s\", encoding=%d(%s)\n",
1045 lang, lang->language, lang->encoding,
1046 lang_encodings[lang->encoding]));
1047
1048 if (!strcmp(lang->language, name) &&
1049 (encoding == CUPS_AUTO_ENCODING || encoding == lang->encoding))
1050 {
1051 lang->used ++;
1052
1053 DEBUG_puts("cups_cache_lookup: returning match!");
1054
1055 return (lang);
1056 }
1057 }
1058
1059 DEBUG_puts("cups_cache_lookup: returning NULL!");
1060
1061 return (NULL);
1062 }
1063
1064
1065 /*
1066 * End of "$Id$".
1067 */