2 * "$Id: language.c 7558 2008-05-12 23:46:44Z mike $"
4 * I18N/language support for the Common UNIX Printing System (CUPS).
6 * Copyright 2007-2009 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",
144 const char * const language
; /* Language ID */
145 const char * const locale
; /* Locale ID */
146 } _apple_language_locale_t
;
148 static const _apple_language_locale_t apple_language_locale
[] =
149 { /* Locale to language ID LUT */
152 { "zh-Hans" , "zh_CN" },
153 { "zh-Hant" , "zh_TW" }
155 #endif /* __APPLE__ */
163 static const char *appleLangDefault(void);
164 #endif /* __APPLE__ */
165 static cups_lang_t
*cups_cache_lookup(const char *name
,
166 cups_encoding_t encoding
);
167 static int cups_message_compare(_cups_message_t
*m1
,
168 _cups_message_t
*m2
);
169 static void cups_unquote(char *d
, const char *s
);
174 * _cupsAppleLanguage() - Get the Apple language identifier associated
178 const char * /* O - Language ID */
179 _cupsAppleLanguage(const char *locale
, /* I - Locale ID */
180 char *language
,/* I - Language ID buffer */
181 size_t langsize
) /* I - Size of language ID buffer */
183 int i
; /* Looping var */
184 CFStringRef localeid
, /* CF locale identifier */
185 langid
; /* CF language identifier */
189 * Copy the locale name and convert, as needed, to the Apple-specific
190 * locale identifier...
193 switch (strlen(locale
))
200 strlcpy(language
, "en", langsize
);
204 strlcpy(language
, locale
, langsize
);
208 strlcpy(language
, locale
, langsize
);
210 if (language
[2] == '-')
213 * Convert ll-cc to ll_CC...
217 language
[3] = toupper(language
[3] & 255);
218 language
[4] = toupper(language
[4] & 255);
224 i
< (int)(sizeof(apple_language_locale
) /
225 sizeof(apple_language_locale
[0]));
227 if (!strcmp(locale
, apple_language_locale
[i
].locale
))
229 strlcpy(language
, apple_language_locale
[i
].language
, sizeof(language
));
234 * Attempt to map the locale ID to a language ID...
237 if ((localeid
= CFStringCreateWithCString(kCFAllocatorDefault
, language
,
238 kCFStringEncodingASCII
)) != NULL
)
240 if ((langid
= CFLocaleCreateCanonicalLanguageIdentifierFromString(
241 kCFAllocatorDefault
, localeid
)) != NULL
)
243 CFStringGetCString(langid
, language
, langsize
, kCFStringEncodingASCII
);
251 * Return what we got...
256 #endif /* __APPLE__ */
260 * '_cupsEncodingName()' - Return the character encoding name string
261 * for the given encoding enumeration.
264 const char * /* O - Character encoding */
266 cups_encoding_t encoding
) /* I - Encoding value */
269 encoding
>= (sizeof(lang_encodings
) / sizeof(const char *)))
270 return (lang_encodings
[0]);
272 return (lang_encodings
[encoding
]);
277 * 'cupsLangDefault()' - Return the default language.
280 cups_lang_t
* /* O - Language data */
281 cupsLangDefault(void)
283 return (cupsLangGet(NULL
));
288 * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
289 * for the given language.
292 const char * /* O - Character encoding */
293 cupsLangEncoding(cups_lang_t
*lang
) /* I - Language data */
296 return ((char*)lang_encodings
[0]);
298 return ((char*)lang_encodings
[lang
->encoding
]);
303 * 'cupsLangFlush()' - Flush all language data out of the cache.
309 cups_lang_t
*lang
, /* Current language */
310 *next
; /* Next language */
314 * Free all languages in the cache...
317 #ifdef HAVE_PTHREAD_H
318 pthread_mutex_lock(&lang_mutex
);
319 #endif /* HAVE_PTHREAD_H */
321 for (lang
= lang_cache
; lang
!= NULL
; lang
= next
)
324 * Free all messages...
327 _cupsMessageFree(lang
->strings
);
330 * Then free the language structure itself...
339 #ifdef HAVE_PTHREAD_H
340 pthread_mutex_unlock(&lang_mutex
);
341 #endif /* HAVE_PTHREAD_H */
346 * 'cupsLangFree()' - Free language data.
348 * This does not actually free anything; use @link cupsLangFlush@ for that.
352 cupsLangFree(cups_lang_t
*lang
) /* I - Language to free */
354 #ifdef HAVE_PTHREAD_H
355 pthread_mutex_lock(&lang_mutex
);
356 #endif /* HAVE_PTHREAD_H */
358 if (lang
!= NULL
&& lang
->used
> 0)
361 #ifdef HAVE_PTHREAD_H
362 pthread_mutex_unlock(&lang_mutex
);
363 #endif /* HAVE_PTHREAD_H */
368 * 'cupsLangGet()' - Get a language.
371 cups_lang_t
* /* O - Language data */
372 cupsLangGet(const char *language
) /* I - Language or locale */
374 int i
; /* Looping var */
376 char locale
[255]; /* Copy of locale name */
377 #endif /* !__APPLE__ */
378 char langname
[16], /* Requested language name */
379 country
[16], /* Country code */
380 charset
[16], /* Character set */
381 *csptr
, /* Pointer to CODESET string */
382 *ptr
, /* Pointer into language/charset */
383 real
[48], /* Real language name */
384 filename
[1024]; /* Filename for language locale file */
385 cups_encoding_t encoding
; /* Encoding to use */
386 cups_lang_t
*lang
; /* Current language... */
387 _cups_globals_t
*cg
= _cupsGlobals();
388 /* Pointer to library globals */
389 static const char * const locale_encodings
[] =
390 { /* Locale charset names */
391 "ASCII", "ISO88591", "ISO88592", "ISO88593",
392 "ISO88594", "ISO88595", "ISO88596", "ISO88597",
393 "ISO88598", "ISO88599", "ISO885910", "UTF8",
394 "ISO885913", "ISO885914", "ISO885915", "CP874",
395 "CP1250", "CP1251", "CP1252", "CP1253",
396 "CP1254", "CP1255", "CP1256", "CP1257",
397 "CP1258", "KOI8R", "KOI8U", "ISO885911",
398 "ISO885916", "MACROMAN", "", "",
409 "CP932", "CP936", "CP949", "CP950",
410 "CP1361", "", "", "",
427 "EUCCN", "EUCJP", "EUCKR", "EUCTW",
432 DEBUG_printf(("2cupsLangGet(language=\"%s\")", language
));
436 * Set the character set to UTF-8...
439 strcpy(charset
, "UTF8");
442 * Apple's setlocale doesn't give us the user's localization
443 * preference so we have to look it up this way...
448 if ((language
= getenv("LANG")) == NULL
)
449 language
= appleLangDefault();
451 DEBUG_printf(("4cupsLangGet: language=\"%s\"", language
));
456 * Set the charset to "unknown"...
462 * Use setlocale() to determine the currently set locale, and then
463 * fallback to environment variables to avoid setting the locale,
464 * since setlocale() is not thread-safe!
470 * First see if the locale has been set; if it is still "C" or
471 * "POSIX", use the environment to get the default...
475 ptr
= setlocale(LC_MESSAGES
, NULL
);
477 ptr
= setlocale(LC_ALL
, NULL
);
478 # endif /* LC_MESSAGES */
480 DEBUG_printf(("4cupsLangGet: current locale is \"%s\"", ptr
));
482 if (!ptr
|| !strcmp(ptr
, "C") || !strcmp(ptr
, "POSIX"))
485 * Get the character set from the LC_CTYPE locale setting...
488 if ((ptr
= getenv("LC_CTYPE")) == NULL
)
489 if ((ptr
= getenv("LC_ALL")) == NULL
)
490 if ((ptr
= getenv("LANG")) == NULL
)
493 if ((csptr
= strchr(ptr
, '.')) != NULL
)
496 * Extract the character set from the environment...
499 for (ptr
= charset
, csptr
++; *csptr
; csptr
++)
500 if (ptr
< (charset
+ sizeof(charset
) - 1) && isalnum(*csptr
& 255))
507 * Get the locale for messages from the LC_MESSAGES locale setting...
510 if ((ptr
= getenv("LC_MESSAGES")) == NULL
)
511 if ((ptr
= getenv("LC_ALL")) == NULL
)
512 if ((ptr
= getenv("LANG")) == NULL
)
518 strlcpy(locale
, ptr
, sizeof(locale
));
522 * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
525 if (!strncmp(locale
, "nb", 2))
528 DEBUG_printf(("4cupsLangGet: new language value is \"%s\"", language
));
531 #endif /* __APPLE__ */
534 * If "language" is NULL at this point, then chances are we are using
535 * a language that is not installed for the base OS.
541 * Switch to the POSIX ("C") locale...
549 * On systems that support the nl_langinfo(CODESET) call, use
550 * this value as the character set...
553 if (!charset
[0] && (csptr
= nl_langinfo(CODESET
)) != NULL
)
556 * Copy all of the letters and numbers in the CODESET string...
559 for (ptr
= charset
; *csptr
; csptr
++)
560 if (isalnum(*csptr
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
565 DEBUG_printf(("4cupsLangGet: charset set to \"%s\" via "
566 "nl_langinfo(CODESET)...", charset
));
571 * If we don't have a character set by now, default to UTF-8...
575 strcpy(charset
, "UTF8");
578 * Parse the language string passed in to a locale string. "C" is the
579 * standard POSIX locale and is copied unchanged. Otherwise the
580 * language string is converted from ll-cc[.charset] (language-country)
581 * to ll_CC[.CHARSET] to match the file naming convention used by all
582 * POSIX-compliant operating systems. Invalid language names are mapped
583 * to the POSIX locale.
588 if (language
== NULL
|| !language
[0] ||
589 !strcmp(language
, "POSIX"))
590 strcpy(langname
, "C");
594 * Copy the parts of the locale string over safely...
597 for (ptr
= langname
; *language
; language
++)
598 if (*language
== '_' || *language
== '-' || *language
== '.')
600 else if (ptr
< (langname
+ sizeof(langname
) - 1))
601 *ptr
++ = tolower(*language
& 255);
605 if (*language
== '_' || *language
== '-')
608 * Copy the country code...
611 for (language
++, ptr
= country
; *language
; language
++)
612 if (*language
== '.')
614 else if (ptr
< (country
+ sizeof(country
) - 1))
615 *ptr
++ = toupper(*language
& 255);
620 if (*language
== '.' && !charset
[0])
623 * Copy the encoding...
626 for (language
++, ptr
= charset
; *language
; language
++)
627 if (isalnum(*language
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
628 *ptr
++ = toupper(*language
& 255);
634 * Force a POSIX locale for an invalid language name...
637 if (strlen(langname
) != 2)
639 strcpy(langname
, "C");
645 DEBUG_printf(("4cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"",
646 langname
, country
, charset
));
649 * Figure out the desired encoding...
652 encoding
= CUPS_AUTO_ENCODING
;
657 i
< (int)(sizeof(locale_encodings
) / sizeof(locale_encodings
[0]));
659 if (!strcasecmp(charset
, locale_encodings
[i
]))
661 encoding
= (cups_encoding_t
)i
;
665 if (encoding
== CUPS_AUTO_ENCODING
)
668 * Map alternate names for various character sets...
671 if (!strcasecmp(charset
, "iso-2022-jp") ||
672 !strcasecmp(charset
, "sjis"))
673 encoding
= CUPS_WINDOWS_932
;
674 else if (!strcasecmp(charset
, "iso-2022-cn"))
675 encoding
= CUPS_WINDOWS_936
;
676 else if (!strcasecmp(charset
, "iso-2022-kr"))
677 encoding
= CUPS_WINDOWS_949
;
678 else if (!strcasecmp(charset
, "big5"))
679 encoding
= CUPS_WINDOWS_950
;
683 DEBUG_printf(("4cupsLangGet: encoding=%d(%s)", encoding
,
684 encoding
== CUPS_AUTO_ENCODING
? "auto" :
685 lang_encodings
[encoding
]));
688 * See if we already have this language/country loaded...
693 snprintf(real
, sizeof(real
), "%s_%s", langname
, country
);
695 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
700 strcpy(real
, langname
);
701 filename
[0] = '\0'; /* anti-compiler-warning-code */
704 #ifdef HAVE_PTHREAD_H
705 pthread_mutex_lock(&lang_mutex
);
706 #endif /* HAVE_PTHREAD_H */
708 if ((lang
= cups_cache_lookup(real
, encoding
)) != NULL
)
710 #ifdef HAVE_PTHREAD_H
711 pthread_mutex_unlock(&lang_mutex
);
712 #endif /* HAVE_PTHREAD_H */
714 DEBUG_printf(("3cupsLangGet: Using cached copy of \"%s\"...", real
));
719 if (!country
[0] || access(filename
, 0))
722 * Country localization not available, look for generic localization...
725 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
728 if (access(filename
, 0))
731 * No generic localization, so use POSIX...
734 DEBUG_printf(("4cupsLangGet: access(\"%s\", 0): %s", filename
,
737 snprintf(filename
, sizeof(filename
), "%s/C/cups_C.po", cg
->localedir
);
742 * See if there is a free language available; if so, use that
746 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
753 * Allocate memory for the language and add it to the cache.
756 if ((lang
= calloc(sizeof(cups_lang_t
), 1)) == NULL
)
758 #ifdef HAVE_PTHREAD_H
759 pthread_mutex_unlock(&lang_mutex
);
760 #endif /* HAVE_PTHREAD_H */
765 lang
->next
= lang_cache
;
771 * Free all old strings as needed...
774 _cupsMessageFree(lang
->strings
);
778 * Then assign the language and encoding fields...
782 strlcpy(lang
->language
, real
, sizeof(lang
->language
));
784 if (encoding
!= CUPS_AUTO_ENCODING
)
785 lang
->encoding
= encoding
;
787 lang
->encoding
= CUPS_UTF8
;
790 * Read the strings from the file...
793 lang
->strings
= _cupsMessageLoad(filename
, 1);
799 #ifdef HAVE_PTHREAD_H
800 pthread_mutex_unlock(&lang_mutex
);
801 #endif /* HAVE_PTHREAD_H */
808 * '_cupsLangString()' - Get a message string.
810 * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
811 * convert the string to the language encoding.
814 const char * /* O - Localized message */
815 _cupsLangString(cups_lang_t
*lang
, /* I - Language */
816 const char *message
) /* I - Message */
819 * Range check input...
822 if (!lang
|| !message
)
825 #ifdef HAVE_PTHREAD_H
827 const char *s
; /* Localized message */
829 pthread_mutex_lock(&lang_mutex
);
831 s
= _cupsMessageLookup(lang
->strings
, message
);
833 pthread_mutex_unlock(&lang_mutex
);
838 return (_cupsMessageLookup(lang
->strings
, message
));
839 #endif /* HAVE_PTHREAD_H */
844 * '_cupsMessageFree()' - Free a messages array.
848 _cupsMessageFree(cups_array_t
*a
) /* I - Message array */
850 _cups_message_t
*m
; /* Current message */
853 for (m
= (_cups_message_t
*)cupsArrayFirst(a
);
855 m
= (_cups_message_t
*)cupsArrayNext(a
))
858 * Remove the message from the array, then free the message and strings.
861 cupsArrayRemove(a
, m
);
881 * '_cupsMessageLoad()' - Load a .po file into a messages array.
884 cups_array_t
* /* O - New message array */
885 _cupsMessageLoad(const char *filename
, /* I - Message catalog to load */
886 int unquote
) /* I - Unescape \foo in strings */
888 cups_file_t
*fp
; /* Message file */
889 cups_array_t
*a
; /* Message array */
890 _cups_message_t
*m
; /* Current message */
891 char s
[4096], /* String buffer */
892 *ptr
, /* Pointer into buffer */
893 *temp
; /* New string */
894 int length
; /* Length of combined strings */
897 DEBUG_printf(("4_cupsMessageLoad(filename=\"%s\")", filename
));
900 * Create an array to hold the messages...
903 if ((a
= cupsArrayNew((cups_array_func_t
)cups_message_compare
, NULL
)) == NULL
)
905 DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!");
910 * Open the message catalog file...
913 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
915 DEBUG_printf(("5_cupsMessageLoad: Unable to open file: %s",
921 * Read messages from the catalog file until EOF...
923 * The format is the GNU gettext .po format, which is fairly simple:
926 * msgstr "localized text"
928 * The ID and localized text can span multiple lines using the form:
933 * "localized text spanning "
939 while (cupsFileGets(fp
, s
, sizeof(s
)) != NULL
)
942 * Skip blank and comment lines...
945 if (s
[0] == '#' || !s
[0])
949 * Strip the trailing quote...
952 if ((ptr
= strrchr(s
, '\"')) == NULL
)
958 * Find start of value...
961 if ((ptr
= strchr(s
, '\"')) == NULL
)
967 * Unquote the text...
971 cups_unquote(ptr
, ptr
);
974 * Create or add to a message...
977 if (!strncmp(s
, "msgid", 5))
980 * Add previous message as needed...
987 * Create a new message with the given msgid string...
990 if ((m
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
996 if ((m
->id
= strdup(ptr
)) == NULL
)
1003 else if (s
[0] == '\"' && m
)
1006 * Append to current string...
1009 length
= (int)strlen(m
->str
? m
->str
: m
->id
);
1011 if ((temp
= realloc(m
->str
? m
->str
: m
->id
,
1012 length
+ strlen(ptr
) + 1)) == NULL
)
1021 * Copy the new portion to the end of the msgstr string - safe
1022 * to use strcpy because the buffer is allocated to the correct
1028 strcpy(m
->str
+ length
, ptr
);
1033 * Copy the new portion to the end of the msgid string - safe
1034 * to use strcpy because the buffer is allocated to the correct
1040 strcpy(m
->id
+ length
, ptr
);
1043 else if (!strncmp(s
, "msgstr", 6) && m
)
1049 if ((m
->str
= strdup(ptr
)) == NULL
)
1058 * Add the last message string to the array as needed...
1065 * Close the message catalog file and return the new array...
1070 DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...",
1071 cupsArrayCount(a
)));
1078 * '_cupsMessageLookup()' - Lookup a message string.
1081 const char * /* O - Localized message */
1082 _cupsMessageLookup(cups_array_t
*a
, /* I - Message array */
1083 const char *m
) /* I - Message */
1085 _cups_message_t key
, /* Search key */
1086 *match
; /* Matching message */
1090 * Lookup the message string; if it doesn't exist in the catalog,
1091 * then return the message that was passed to us...
1095 match
= (_cups_message_t
*)cupsArrayFind(a
, &key
);
1097 if (match
&& match
->str
)
1098 return (match
->str
);
1106 * 'appleLangDefault()' - Get the default locale string.
1109 static const char * /* O - Locale string */
1110 appleLangDefault(void)
1112 int i
; /* Looping var */
1113 CFBundleRef bundle
; /* Main bundle (if any) */
1114 CFArrayRef bundleList
; /* List of localizations in bundle */
1115 CFPropertyListRef localizationList
;
1116 /* List of localization data */
1117 CFStringRef languageName
; /* Current name */
1118 CFStringRef localeName
; /* Canonical from of name */
1119 char *lang
; /* LANG environment variable */
1120 _cups_globals_t
*cg
= _cupsGlobals();
1121 /* Pointer to library globals */
1125 * Only do the lookup and translation the first time.
1128 if (!cg
->language
[0])
1130 if ((lang
= getenv("LANG")))
1132 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1133 return (cg
->language
);
1135 else if ((bundle
= CFBundleGetMainBundle()) != NULL
&&
1136 (bundleList
= CFBundleCopyBundleLocalizations(bundle
)) != NULL
)
1139 CFBundleCopyPreferredLocalizationsFromArray(bundleList
);
1141 CFRelease(bundleList
);
1145 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1146 kCFPreferencesCurrentApplication
);
1148 if (localizationList
)
1150 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1151 CFArrayGetCount(localizationList
) > 0)
1153 languageName
= CFArrayGetValueAtIndex(localizationList
, 0);
1156 CFGetTypeID(languageName
) == CFStringGetTypeID())
1158 localeName
= CFLocaleCreateCanonicalLocaleIdentifierFromString(
1159 kCFAllocatorDefault
, languageName
);
1163 CFStringGetCString(localeName
, cg
->language
, sizeof(cg
->language
),
1164 kCFStringEncodingASCII
);
1165 CFRelease(localeName
);
1167 DEBUG_printf(("9appleLangDefault: cg->language=\"%s\"",
1171 * Map new language identifiers to locales...
1175 i
< (int)(sizeof(apple_language_locale
) /
1176 sizeof(apple_language_locale
[0]));
1179 if (!strcmp(cg
->language
, apple_language_locale
[i
].language
))
1181 DEBUG_printf(("9appleLangDefault: mapping \"%s\" to \"%s\"...",
1182 cg
->language
, apple_language_locale
[i
].locale
));
1183 strlcpy(cg
->language
, apple_language_locale
[i
].locale
,
1184 sizeof(cg
->language
));
1190 * Convert language subtag into region subtag...
1193 if (cg
->language
[2] == '-')
1194 cg
->language
[2] = '_';
1196 if (!strchr(cg
->language
, '.'))
1197 strlcat(cg
->language
, ".UTF-8", sizeof(cg
->language
));
1202 CFRelease(localizationList
);
1206 * If we didn't find the language, default to en_US...
1209 if (!cg
->language
[0])
1210 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1214 * Return the cached locale...
1217 return (cg
->language
);
1219 #endif /* __APPLE__ */
1223 * 'cups_cache_lookup()' - Lookup a language in the cache...
1226 static cups_lang_t
* /* O - Language data or NULL */
1227 cups_cache_lookup(const char *name
,/* I - Name of locale */
1228 cups_encoding_t encoding
)
1229 /* I - Encoding of locale */
1231 cups_lang_t
*lang
; /* Current language */
1234 DEBUG_printf(("7cups_cache_lookup(name=\"%s\", encoding=%d(%s))", name
,
1235 encoding
, encoding
== CUPS_AUTO_ENCODING
? "auto" :
1236 lang_encodings
[encoding
]));
1239 * Loop through the cache and return a match if found...
1242 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
1244 DEBUG_printf(("9cups_cache_lookup: lang=%p, language=\"%s\", "
1245 "encoding=%d(%s)", lang
, lang
->language
, lang
->encoding
,
1246 lang_encodings
[lang
->encoding
]));
1248 if (!strcmp(lang
->language
, name
) &&
1249 (encoding
== CUPS_AUTO_ENCODING
|| encoding
== lang
->encoding
))
1253 DEBUG_puts("8cups_cache_lookup: returning match!");
1259 DEBUG_puts("8cups_cache_lookup: returning NULL!");
1266 * 'cups_message_compare()' - Compare two messages.
1269 static int /* O - Result of comparison */
1270 cups_message_compare(
1271 _cups_message_t
*m1
, /* I - First message */
1272 _cups_message_t
*m2
) /* I - Second message */
1274 return (strcmp(m1
->id
, m2
->id
));
1279 * 'cups_unquote()' - Unquote characters in strings...
1283 cups_unquote(char *d
, /* O - Unquoted string */
1284 const char *s
) /* I - Original string */
1297 *d
= *d
* 8 + *s
- '0';
1326 * End of "$Id: language.c 7558 2008-05-12 23:46:44Z mike $".