2 * "$Id: language.c 6916 2007-09-05 21:14:08Z mike $"
4 * I18N/language support for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2008 by Apple Inc.
7 * Copyright 1997-2007 by Easy Software Products.
9 * These coded instructions, statements, and computer programs are the
10 * property of Apple Inc. and are protected by Federal copyright
11 * law. Distribution and use rights are outlined in the file "LICENSE.txt"
12 * which should have been included with this file. If this file is
13 * file is missing or damaged, see the license at "http://www.cups.org/".
15 * This file is subject to the Apple OS-Developed Software exception.
19 * _cupsAppleLanguage() - Get the Apple language identifier associated
21 * _cupsEncodingName() - Return the character encoding name string
22 * for the given encoding enumeration.
23 * cupsLangDefault() - Return the default language.
24 * cupsLangEncoding() - Return the character encoding (us-ascii, etc.)
25 * for the given language.
26 * cupsLangFlush() - Flush all language data out of the cache.
27 * cupsLangFree() - Free language data.
28 * cupsLangGet() - Get a language.
29 * _cupsLangString() - Get a message string.
30 * _cupsMessageFree() - Free a messages array.
31 * _cupsMessageLoad() - Load a .po file into a messages array.
32 * _cupsMessageLookup() - Lookup a message string.
33 * appleLangDefault() - Get the default locale string.
34 * cups_cache_lookup() - Lookup a language in the cache...
35 * cups_message_compare() - Compare two messages.
36 * cups_unquote() - Unquote characters in strings...
40 * Include necessary headers...
47 #ifdef HAVE_LANGINFO_H
48 # include <langinfo.h>
49 #endif /* HAVE_LANGINFO_H */
55 #ifdef HAVE_COREFOUNDATION_H
56 # include <CoreFoundation/CoreFoundation.h>
57 #endif /* HAVE_COREFOUNDATION_H */
65 static pthread_mutex_t lang_mutex
= PTHREAD_MUTEX_INITIALIZER
;
66 /* Mutex to control access to cache */
67 #endif /* HAVE_PTHREAD_H */
68 static cups_lang_t
*lang_cache
= NULL
;
69 /* Language string cache */
70 static const char * const lang_encodings
[] =
71 { /* Encoding strings */
72 "us-ascii", "iso-8859-1",
73 "iso-8859-2", "iso-8859-3",
74 "iso-8859-4", "iso-8859-5",
75 "iso-8859-6", "iso-8859-7",
76 "iso-8859-8", "iso-8859-9",
77 "iso-8859-10", "utf-8",
78 "iso-8859-13", "iso-8859-14",
79 "iso-8859-15", "windows-874",
80 "windows-1250", "windows-1251",
81 "windows-1252", "windows-1253",
82 "windows-1254", "windows-1255",
83 "windows-1256", "windows-1257",
84 "windows-1258", "koi8-r",
85 "koi8-u", "iso-8859-11",
86 "iso-8859-16", "mac-roman",
100 "unknown", "unknown",
101 "unknown", "unknown",
102 "unknown", "unknown",
103 "unknown", "unknown",
104 "windows-932", "windows-936",
105 "windows-949", "windows-950",
106 "windows-1361", "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 "unknown", "unknown",
117 "unknown", "unknown",
118 "unknown", "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",
143 const char * const language
; /* Language ID */
144 const char * const locale
; /* Locale ID */
145 } _apple_language_locale_t
;
147 static const _apple_language_locale_t apple_language_locale
[] =
148 { /* Locale to language ID LUT */
151 { "zh-Hans" , "zh_CN" },
152 { "zh-Hant" , "zh_TW" }
154 #endif /* __APPLE__ */
162 static const char *appleLangDefault(void);
163 #endif /* __APPLE__ */
164 static cups_lang_t
*cups_cache_lookup(const char *name
,
165 cups_encoding_t encoding
);
166 static int cups_message_compare(_cups_message_t
*m1
,
167 _cups_message_t
*m2
);
168 static void cups_unquote(char *d
, const char *s
);
173 * _cupsAppleLanguage() - Get the Apple language identifier associated
177 const char * /* O - Language ID */
178 _cupsAppleLanguage(const char *locale
, /* I - Locale ID */
179 char *language
,/* I - Language ID buffer */
180 size_t langsize
) /* I - Size of language ID buffer */
182 int i
; /* Looping var */
183 CFStringRef localeid
, /* CF locale identifier */
184 langid
; /* CF language identifier */
188 * Copy the locale name and convert, as needed, to the Apple-specific
189 * locale identifier...
192 switch (strlen(locale
))
199 strlcpy(language
, "en", langsize
);
203 strlcpy(language
, locale
, langsize
);
207 strlcpy(language
, locale
, langsize
);
209 if (language
[2] == '-')
212 * Convert ll-cc to ll_CC...
216 language
[3] = toupper(language
[3] & 255);
217 language
[4] = toupper(language
[4] & 255);
223 i
< (int)(sizeof(apple_language_locale
) /
224 sizeof(apple_language_locale
[0]));
226 if (!strcmp(locale
, apple_language_locale
[i
].locale
))
228 strlcpy(language
, apple_language_locale
[i
].language
, sizeof(language
));
233 * Attempt to map the locale ID to a language ID...
236 if ((localeid
= CFStringCreateWithCString(kCFAllocatorDefault
, language
,
237 kCFStringEncodingASCII
)) != NULL
)
239 if ((langid
= CFLocaleCreateCanonicalLanguageIdentifierFromString(
240 kCFAllocatorDefault
, localeid
)) != NULL
)
242 CFStringGetCString(langid
, language
, langsize
, kCFStringEncodingASCII
);
250 * Return what we got...
255 #endif /* __APPLE__ */
259 * '_cupsEncodingName()' - Return the character encoding name string
260 * for the given encoding enumeration.
263 const char * /* O - Character encoding */
265 cups_encoding_t encoding
) /* I - Encoding value */
268 encoding
>= (sizeof(lang_encodings
) / sizeof(const char *)))
269 return (lang_encodings
[0]);
271 return (lang_encodings
[encoding
]);
276 * 'cupsLangDefault()' - Return the default language.
279 cups_lang_t
* /* O - Language data */
280 cupsLangDefault(void)
282 return (cupsLangGet(NULL
));
287 * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
288 * for the given language.
291 const char * /* O - Character encoding */
292 cupsLangEncoding(cups_lang_t
*lang
) /* I - Language data */
295 return ((char*)lang_encodings
[0]);
297 return ((char*)lang_encodings
[lang
->encoding
]);
302 * 'cupsLangFlush()' - Flush all language data out of the cache.
308 cups_lang_t
*lang
, /* Current language */
309 *next
; /* Next language */
313 * Free all languages in the cache...
316 #ifdef HAVE_PTHREAD_H
317 pthread_mutex_lock(&lang_mutex
);
318 #endif /* HAVE_PTHREAD_H */
320 for (lang
= lang_cache
; lang
!= NULL
; lang
= next
)
323 * Free all messages...
326 _cupsMessageFree(lang
->strings
);
329 * Then free the language structure itself...
338 #ifdef HAVE_PTHREAD_H
339 pthread_mutex_unlock(&lang_mutex
);
340 #endif /* HAVE_PTHREAD_H */
345 * 'cupsLangFree()' - Free language data.
347 * This does not actually free anything; use @link cupsLangFlush@ for that.
351 cupsLangFree(cups_lang_t
*lang
) /* I - Language to free */
353 #ifdef HAVE_PTHREAD_H
354 pthread_mutex_lock(&lang_mutex
);
355 #endif /* HAVE_PTHREAD_H */
357 if (lang
!= NULL
&& lang
->used
> 0)
360 #ifdef HAVE_PTHREAD_H
361 pthread_mutex_unlock(&lang_mutex
);
362 #endif /* HAVE_PTHREAD_H */
367 * 'cupsLangGet()' - Get a language.
370 cups_lang_t
* /* O - Language data */
371 cupsLangGet(const char *language
) /* I - Language or locale */
373 int i
; /* Looping var */
375 char locale
[255]; /* Copy of locale name */
376 #endif /* !__APPLE__ */
377 char langname
[16], /* Requested language name */
378 country
[16], /* Country code */
379 charset
[16], /* Character set */
380 *csptr
, /* Pointer to CODESET string */
381 *ptr
, /* Pointer into language/charset */
382 real
[48], /* Real language name */
383 filename
[1024]; /* Filename for language locale file */
384 cups_encoding_t encoding
; /* Encoding to use */
385 cups_lang_t
*lang
; /* Current language... */
386 _cups_globals_t
*cg
= _cupsGlobals();
387 /* Pointer to library globals */
388 static const char * const locale_encodings
[] =
389 { /* Locale charset names */
390 "ASCII", "ISO88591", "ISO88592", "ISO88593",
391 "ISO88594", "ISO88595", "ISO88596", "ISO88597",
392 "ISO88598", "ISO88599", "ISO885910", "UTF8",
393 "ISO885913", "ISO885914", "ISO885915", "CP874",
394 "CP1250", "CP1251", "CP1252", "CP1253",
395 "CP1254", "CP1255", "CP1256", "CP1257",
396 "CP1258", "KOI8R", "KOI8U", "ISO885911",
397 "ISO885916", "MACROMAN", "", "",
408 "CP932", "CP936", "CP949", "CP950",
409 "CP1361", "", "", "",
426 "EUCCN", "EUCJP", "EUCKR", "EUCTW"
430 DEBUG_printf(("cupsLangGet(language=\"%s\")\n", language
? language
: "(null)"));
434 * Set the character set to UTF-8...
437 strcpy(charset
, "UTF8");
440 * Apple's setlocale doesn't give us the user's localization
441 * preference so we have to look it up this way...
446 if ((language
= getenv("LANG")) == NULL
)
447 language
= appleLangDefault();
449 DEBUG_printf(("cupsLangGet: language=\"%s\"\n", language
));
454 * Set the charset to "unknown"...
460 * Use setlocale() to determine the currently set locale, and then
461 * fallback to environment variables to avoid setting the locale,
462 * since setlocale() is not thread-safe!
468 * First see if the locale has been set; if it is still "C" or
469 * "POSIX", use the environment to get the default...
473 ptr
= setlocale(LC_MESSAGES
, NULL
);
475 ptr
= setlocale(LC_ALL
, NULL
);
476 # endif /* LC_MESSAGES */
478 DEBUG_printf(("cupsLangGet: current locale is \"%s\"\n",
479 ptr
? ptr
: "(null)"));
481 if (!ptr
|| !strcmp(ptr
, "C") || !strcmp(ptr
, "POSIX"))
484 * Get the character set from the LC_CTYPE locale setting...
487 if ((ptr
= getenv("LC_CTYPE")) == NULL
)
488 if ((ptr
= getenv("LC_ALL")) == NULL
)
489 if ((ptr
= getenv("LANG")) == NULL
)
492 if ((csptr
= strchr(ptr
, '.')) != NULL
)
495 * Extract the character set from the environment...
498 for (ptr
= charset
, csptr
++; *csptr
; csptr
++)
499 if (ptr
< (charset
+ sizeof(charset
) - 1) && isalnum(*csptr
& 255))
506 * Get the locale for messages from the LC_MESSAGES locale setting...
509 if ((ptr
= getenv("LC_MESSAGES")) == NULL
)
510 if ((ptr
= getenv("LC_ALL")) == NULL
)
511 if ((ptr
= getenv("LANG")) == NULL
)
517 strlcpy(locale
, ptr
, sizeof(locale
));
521 * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
524 if (!strncmp(locale
, "nb", 2))
527 DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n", language
));
530 #endif /* __APPLE__ */
533 * If "language" is NULL at this point, then chances are we are using
534 * a language that is not installed for the base OS.
540 * Switch to the POSIX ("C") locale...
548 * On systems that support the nl_langinfo(CODESET) call, use
549 * this value as the character set...
552 if (!charset
[0] && (csptr
= nl_langinfo(CODESET
)) != NULL
)
555 * Copy all of the letters and numbers in the CODESET string...
558 for (ptr
= charset
; *csptr
; csptr
++)
559 if (isalnum(*csptr
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
564 DEBUG_printf(("cupsLangGet: charset set to \"%s\" via nl_langinfo(CODESET)...\n",
570 * If we don't have a character set by now, default to UTF-8...
574 strcpy(charset
, "UTF8");
577 * Parse the language string passed in to a locale string. "C" is the
578 * standard POSIX locale and is copied unchanged. Otherwise the
579 * language string is converted from ll-cc[.charset] (language-country)
580 * to ll_CC[.CHARSET] to match the file naming convention used by all
581 * POSIX-compliant operating systems. Invalid language names are mapped
582 * to the POSIX locale.
587 if (language
== NULL
|| !language
[0] ||
588 !strcmp(language
, "POSIX"))
589 strcpy(langname
, "C");
593 * Copy the parts of the locale string over safely...
596 for (ptr
= langname
; *language
; language
++)
597 if (*language
== '_' || *language
== '-' || *language
== '.')
599 else if (ptr
< (langname
+ sizeof(langname
) - 1))
600 *ptr
++ = tolower(*language
& 255);
604 if (*language
== '_' || *language
== '-')
607 * Copy the country code...
610 for (language
++, ptr
= country
; *language
; language
++)
611 if (*language
== '.')
613 else if (ptr
< (country
+ sizeof(country
) - 1))
614 *ptr
++ = toupper(*language
& 255);
619 if (*language
== '.' && !charset
[0])
622 * Copy the encoding...
625 for (language
++, ptr
= charset
; *language
; language
++)
626 if (isalnum(*language
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
627 *ptr
++ = toupper(*language
& 255);
633 * Force a POSIX locale for an invalid language name...
636 if (strlen(langname
) != 2)
638 strcpy(langname
, "C");
644 DEBUG_printf(("cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"\n",
645 langname
, country
, charset
));
648 * Figure out the desired encoding...
651 encoding
= CUPS_AUTO_ENCODING
;
656 i
< (int)(sizeof(locale_encodings
) / sizeof(locale_encodings
[0]));
658 if (!strcasecmp(charset
, locale_encodings
[i
]))
660 encoding
= (cups_encoding_t
)i
;
664 if (encoding
== CUPS_AUTO_ENCODING
)
667 * Map alternate names for various character sets...
670 if (!strcasecmp(charset
, "iso-2022-jp") ||
671 !strcasecmp(charset
, "sjis"))
672 encoding
= CUPS_WINDOWS_932
;
673 else if (!strcasecmp(charset
, "iso-2022-cn"))
674 encoding
= CUPS_WINDOWS_936
;
675 else if (!strcasecmp(charset
, "iso-2022-kr"))
676 encoding
= CUPS_WINDOWS_949
;
677 else if (!strcasecmp(charset
, "big5"))
678 encoding
= CUPS_WINDOWS_950
;
682 DEBUG_printf(("cupsLangGet: encoding=%d(%s)\n", encoding
,
683 encoding
== CUPS_AUTO_ENCODING
? "auto" :
684 lang_encodings
[encoding
]));
687 * See if we already have this language/country loaded...
692 snprintf(real
, sizeof(real
), "%s_%s", langname
, country
);
694 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
699 strcpy(real
, langname
);
700 filename
[0] = '\0'; /* anti-compiler-warning-code */
703 #ifdef HAVE_PTHREAD_H
704 pthread_mutex_lock(&lang_mutex
);
705 #endif /* HAVE_PTHREAD_H */
707 if ((lang
= cups_cache_lookup(real
, encoding
)) != NULL
)
709 #ifdef HAVE_PTHREAD_H
710 pthread_mutex_unlock(&lang_mutex
);
711 #endif /* HAVE_PTHREAD_H */
713 DEBUG_printf(("cupsLangGet: Using cached copy of \"%s\"...\n", real
));
718 if (!country
[0] || access(filename
, 0))
721 * Country localization not available, look for generic localization...
724 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
727 if (access(filename
, 0))
730 * No generic localization, so use POSIX...
733 DEBUG_printf(("cupsLangGet: access(\"%s\", 0): %s\n", filename
,
736 snprintf(filename
, sizeof(filename
), "%s/C/cups_C.po", cg
->localedir
);
741 * See if there is a free language available; if so, use that
745 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
752 * Allocate memory for the language and add it to the cache.
755 if ((lang
= calloc(sizeof(cups_lang_t
), 1)) == NULL
)
757 #ifdef HAVE_PTHREAD_H
758 pthread_mutex_unlock(&lang_mutex
);
759 #endif /* HAVE_PTHREAD_H */
764 lang
->next
= lang_cache
;
770 * Free all old strings as needed...
773 _cupsMessageFree(lang
->strings
);
777 * Then assign the language and encoding fields...
781 strlcpy(lang
->language
, real
, sizeof(lang
->language
));
783 if (encoding
!= CUPS_AUTO_ENCODING
)
784 lang
->encoding
= encoding
;
786 lang
->encoding
= CUPS_UTF8
;
789 * Read the strings from the file...
792 lang
->strings
= _cupsMessageLoad(filename
);
798 #ifdef HAVE_PTHREAD_H
799 pthread_mutex_unlock(&lang_mutex
);
800 #endif /* HAVE_PTHREAD_H */
807 * '_cupsLangString()' - Get a message string.
809 * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
810 * convert the string to the language encoding.
813 const char * /* O - Localized message */
814 _cupsLangString(cups_lang_t
*lang
, /* I - Language */
815 const char *message
) /* I - Message */
818 * Range check input...
821 if (!lang
|| !message
)
824 #ifdef HAVE_PTHREAD_H
826 const char *s
; /* Localized message */
828 pthread_mutex_lock(&lang_mutex
);
830 s
= _cupsMessageLookup(lang
->strings
, message
);
832 pthread_mutex_unlock(&lang_mutex
);
837 return (_cupsMessageLookup(lang
->strings
, message
));
838 #endif /* HAVE_PTHREAD_H */
843 * '_cupsMessageFree()' - Free a messages array.
847 _cupsMessageFree(cups_array_t
*a
) /* I - Message array */
849 _cups_message_t
*m
; /* Current message */
852 for (m
= (_cups_message_t
*)cupsArrayFirst(a
);
854 m
= (_cups_message_t
*)cupsArrayNext(a
))
857 * Remove the message from the array, then free the message and strings.
860 cupsArrayRemove(a
, m
);
880 * '_cupsMessageLoad()' - Load a .po file into a messages array.
883 cups_array_t
* /* O - New message array */
884 _cupsMessageLoad(const char *filename
) /* I - Message catalog to load */
886 cups_file_t
*fp
; /* Message file */
887 cups_array_t
*a
; /* Message array */
888 _cups_message_t
*m
; /* Current message */
889 char s
[4096], /* String buffer */
890 *ptr
, /* Pointer into buffer */
891 *temp
; /* New string */
892 int length
; /* Length of combined strings */
895 DEBUG_printf(("_cupsMessageLoad(filename=\"%s\")\n", filename
));
898 * Create an array to hold the messages...
901 if ((a
= cupsArrayNew((cups_array_func_t
)cups_message_compare
, NULL
)) == NULL
)
903 DEBUG_puts("_cupsMessageLoad: Unable to allocate array!");
908 * Open the message catalog file...
911 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
913 DEBUG_printf(("_cupsMessageLoad: Unable to open file: %s\n",
919 * Read messages from the catalog file until EOF...
921 * The format is the GNU gettext .po format, which is fairly simple:
924 * msgstr "localized text"
926 * The ID and localized text can span multiple lines using the form:
931 * "localized text spanning "
937 while (cupsFileGets(fp
, s
, sizeof(s
)) != NULL
)
940 * Skip blank and comment lines...
943 if (s
[0] == '#' || !s
[0])
947 * Strip the trailing quote...
950 if ((ptr
= strrchr(s
, '\"')) == NULL
)
956 * Find start of value...
959 if ((ptr
= strchr(s
, '\"')) == NULL
)
965 * Unquote the text...
968 cups_unquote(ptr
, ptr
);
971 * Create or add to a message...
974 if (!strncmp(s
, "msgid", 5))
977 * Add previous message as needed...
984 * Create a new message with the given msgid string...
987 if ((m
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
993 if ((m
->id
= strdup(ptr
)) == NULL
)
1000 else if (s
[0] == '\"' && m
)
1003 * Append to current string...
1006 length
= (int)strlen(m
->str
? m
->str
: m
->id
);
1008 if ((temp
= realloc(m
->str
? m
->str
: m
->id
,
1009 length
+ strlen(ptr
) + 1)) == NULL
)
1018 * Copy the new portion to the end of the msgstr string - safe
1019 * to use strcpy because the buffer is allocated to the correct
1025 strcpy(m
->str
+ length
, ptr
);
1030 * Copy the new portion to the end of the msgid string - safe
1031 * to use strcpy because the buffer is allocated to the correct
1037 strcpy(m
->id
+ length
, ptr
);
1040 else if (!strncmp(s
, "msgstr", 6) && m
)
1046 if ((m
->str
= strdup(ptr
)) == NULL
)
1055 * Add the last message string to the array as needed...
1062 * Close the message catalog file and return the new array...
1067 DEBUG_printf(("_cupsMessageLoad: Returning %d messages...\n",
1068 cupsArrayCount(a
)));
1075 * '_cupsMessageLookup()' - Lookup a message string.
1078 const char * /* O - Localized message */
1079 _cupsMessageLookup(cups_array_t
*a
, /* I - Message array */
1080 const char *m
) /* I - Message */
1082 _cups_message_t key
, /* Search key */
1083 *match
; /* Matching message */
1087 * Lookup the message string; if it doesn't exist in the catalog,
1088 * then return the message that was passed to us...
1092 match
= (_cups_message_t
*)cupsArrayFind(a
, &key
);
1094 if (match
&& match
->str
)
1095 return (match
->str
);
1103 * 'appleLangDefault()' - Get the default locale string.
1106 static const char * /* O - Locale string */
1107 appleLangDefault(void)
1109 int i
; /* Looping var */
1110 CFBundleRef bundle
; /* Main bundle (if any) */
1111 CFArrayRef bundleList
; /* List of localizations in bundle */
1112 CFPropertyListRef localizationList
;
1113 /* List of localization data */
1114 CFStringRef languageName
; /* Current name */
1115 CFStringRef localeName
; /* Canonical from of name */
1116 char *lang
; /* LANG environment variable */
1117 _cups_globals_t
*cg
= _cupsGlobals();
1118 /* Pointer to library globals */
1122 * Only do the lookup and translation the first time.
1125 if (!cg
->language
[0])
1127 if ((lang
= getenv("LANG")))
1129 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1130 return (cg
->language
);
1132 else if ((bundle
= CFBundleGetMainBundle()) != NULL
&&
1133 (bundleList
= CFBundleCopyBundleLocalizations(bundle
)) != NULL
)
1136 CFBundleCopyPreferredLocalizationsFromArray(bundleList
);
1138 CFRelease(bundleList
);
1142 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1143 kCFPreferencesCurrentApplication
);
1145 if (localizationList
)
1147 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1148 CFArrayGetCount(localizationList
) > 0)
1150 languageName
= CFArrayGetValueAtIndex(localizationList
, 0);
1153 CFGetTypeID(languageName
) == CFStringGetTypeID())
1155 localeName
= CFLocaleCreateCanonicalLocaleIdentifierFromString(
1156 kCFAllocatorDefault
, languageName
);
1160 CFStringGetCString(localeName
, cg
->language
, sizeof(cg
->language
),
1161 kCFStringEncodingASCII
);
1162 CFRelease(localeName
);
1164 DEBUG_printf(("appleLangDefault: cg->language=\"%s\"\n",
1168 * Map new language identifiers to locales...
1172 i
< (int)(sizeof(apple_language_locale
) /
1173 sizeof(apple_language_locale
[0]));
1176 if (!strcmp(cg
->language
, apple_language_locale
[i
].language
))
1178 DEBUG_printf(("appleLangDefault: mapping \"%s\" to \"%s\"...\n",
1179 cg
->language
, apple_language_locale
[i
].locale
));
1180 strlcpy(cg
->language
, apple_language_locale
[i
].locale
,
1181 sizeof(cg
->language
));
1187 * Convert language subtag into region subtag...
1190 if (cg
->language
[2] == '-')
1191 cg
->language
[2] = '_';
1193 if (!strchr(cg
->language
, '.'))
1194 strlcat(cg
->language
, ".UTF-8", sizeof(cg
->language
));
1199 CFRelease(localizationList
);
1203 * If we didn't find the language, default to en_US...
1206 if (!cg
->language
[0])
1207 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1211 * Return the cached locale...
1214 return (cg
->language
);
1216 #endif /* __APPLE__ */
1220 * 'cups_cache_lookup()' - Lookup a language in the cache...
1223 static cups_lang_t
* /* O - Language data or NULL */
1224 cups_cache_lookup(const char *name
,/* I - Name of locale */
1225 cups_encoding_t encoding
)
1226 /* I - Encoding of locale */
1228 cups_lang_t
*lang
; /* Current language */
1231 DEBUG_printf(("cups_cache_lookup(name=\"%s\", encoding=%d(%s))\n", name
,
1232 encoding
, encoding
== CUPS_AUTO_ENCODING
? "auto" :
1233 lang_encodings
[encoding
]));
1236 * Loop through the cache and return a match if found...
1239 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
1241 DEBUG_printf(("cups_cache_lookup: lang=%p, language=\"%s\", encoding=%d(%s)\n",
1242 lang
, lang
->language
, lang
->encoding
,
1243 lang_encodings
[lang
->encoding
]));
1245 if (!strcmp(lang
->language
, name
) &&
1246 (encoding
== CUPS_AUTO_ENCODING
|| encoding
== lang
->encoding
))
1250 DEBUG_puts("cups_cache_lookup: returning match!");
1256 DEBUG_puts("cups_cache_lookup: returning NULL!");
1263 * 'cups_message_compare()' - Compare two messages.
1266 static int /* O - Result of comparison */
1267 cups_message_compare(
1268 _cups_message_t
*m1
, /* I - First message */
1269 _cups_message_t
*m2
) /* I - Second message */
1271 return (strcmp(m1
->id
, m2
->id
));
1276 * 'cups_unquote()' - Unquote characters in strings...
1280 cups_unquote(char *d
, /* O - Unquoted string */
1281 const char *s
) /* I - Original string */
1294 *d
= *d
* 8 + *s
- '0';
1323 * End of "$Id: language.c 6916 2007-09-05 21:14:08Z mike $".