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-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",
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(("cupsLangGet(language=\"%s\")\n", language
? language
: "(null)"));
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(("cupsLangGet: language=\"%s\"\n", 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(("cupsLangGet: current locale is \"%s\"\n",
481 ptr
? ptr
: "(null)"));
483 if (!ptr
|| !strcmp(ptr
, "C") || !strcmp(ptr
, "POSIX"))
486 * Get the character set from the LC_CTYPE locale setting...
489 if ((ptr
= getenv("LC_CTYPE")) == NULL
)
490 if ((ptr
= getenv("LC_ALL")) == NULL
)
491 if ((ptr
= getenv("LANG")) == NULL
)
494 if ((csptr
= strchr(ptr
, '.')) != NULL
)
497 * Extract the character set from the environment...
500 for (ptr
= charset
, csptr
++; *csptr
; csptr
++)
501 if (ptr
< (charset
+ sizeof(charset
) - 1) && isalnum(*csptr
& 255))
508 * Get the locale for messages from the LC_MESSAGES locale setting...
511 if ((ptr
= getenv("LC_MESSAGES")) == NULL
)
512 if ((ptr
= getenv("LC_ALL")) == NULL
)
513 if ((ptr
= getenv("LANG")) == NULL
)
519 strlcpy(locale
, ptr
, sizeof(locale
));
523 * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
526 if (!strncmp(locale
, "nb", 2))
529 DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n", language
));
532 #endif /* __APPLE__ */
535 * If "language" is NULL at this point, then chances are we are using
536 * a language that is not installed for the base OS.
542 * Switch to the POSIX ("C") locale...
550 * On systems that support the nl_langinfo(CODESET) call, use
551 * this value as the character set...
554 if (!charset
[0] && (csptr
= nl_langinfo(CODESET
)) != NULL
)
557 * Copy all of the letters and numbers in the CODESET string...
560 for (ptr
= charset
; *csptr
; csptr
++)
561 if (isalnum(*csptr
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
566 DEBUG_printf(("cupsLangGet: charset set to \"%s\" via nl_langinfo(CODESET)...\n",
572 * If we don't have a character set by now, default to UTF-8...
576 strcpy(charset
, "UTF8");
579 * Parse the language string passed in to a locale string. "C" is the
580 * standard POSIX locale and is copied unchanged. Otherwise the
581 * language string is converted from ll-cc[.charset] (language-country)
582 * to ll_CC[.CHARSET] to match the file naming convention used by all
583 * POSIX-compliant operating systems. Invalid language names are mapped
584 * to the POSIX locale.
589 if (language
== NULL
|| !language
[0] ||
590 !strcmp(language
, "POSIX"))
591 strcpy(langname
, "C");
595 * Copy the parts of the locale string over safely...
598 for (ptr
= langname
; *language
; language
++)
599 if (*language
== '_' || *language
== '-' || *language
== '.')
601 else if (ptr
< (langname
+ sizeof(langname
) - 1))
602 *ptr
++ = tolower(*language
& 255);
606 if (*language
== '_' || *language
== '-')
609 * Copy the country code...
612 for (language
++, ptr
= country
; *language
; language
++)
613 if (*language
== '.')
615 else if (ptr
< (country
+ sizeof(country
) - 1))
616 *ptr
++ = toupper(*language
& 255);
621 if (*language
== '.' && !charset
[0])
624 * Copy the encoding...
627 for (language
++, ptr
= charset
; *language
; language
++)
628 if (isalnum(*language
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
629 *ptr
++ = toupper(*language
& 255);
635 * Force a POSIX locale for an invalid language name...
638 if (strlen(langname
) != 2)
640 strcpy(langname
, "C");
646 DEBUG_printf(("cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"\n",
647 langname
, country
, charset
));
650 * Figure out the desired encoding...
653 encoding
= CUPS_AUTO_ENCODING
;
658 i
< (int)(sizeof(locale_encodings
) / sizeof(locale_encodings
[0]));
660 if (!strcasecmp(charset
, locale_encodings
[i
]))
662 encoding
= (cups_encoding_t
)i
;
666 if (encoding
== CUPS_AUTO_ENCODING
)
669 * Map alternate names for various character sets...
672 if (!strcasecmp(charset
, "iso-2022-jp") ||
673 !strcasecmp(charset
, "sjis"))
674 encoding
= CUPS_WINDOWS_932
;
675 else if (!strcasecmp(charset
, "iso-2022-cn"))
676 encoding
= CUPS_WINDOWS_936
;
677 else if (!strcasecmp(charset
, "iso-2022-kr"))
678 encoding
= CUPS_WINDOWS_949
;
679 else if (!strcasecmp(charset
, "big5"))
680 encoding
= CUPS_WINDOWS_950
;
684 DEBUG_printf(("cupsLangGet: encoding=%d(%s)\n", encoding
,
685 encoding
== CUPS_AUTO_ENCODING
? "auto" :
686 lang_encodings
[encoding
]));
689 * See if we already have this language/country loaded...
694 snprintf(real
, sizeof(real
), "%s_%s", langname
, country
);
696 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
701 strcpy(real
, langname
);
702 filename
[0] = '\0'; /* anti-compiler-warning-code */
705 #ifdef HAVE_PTHREAD_H
706 pthread_mutex_lock(&lang_mutex
);
707 #endif /* HAVE_PTHREAD_H */
709 if ((lang
= cups_cache_lookup(real
, encoding
)) != NULL
)
711 #ifdef HAVE_PTHREAD_H
712 pthread_mutex_unlock(&lang_mutex
);
713 #endif /* HAVE_PTHREAD_H */
715 DEBUG_printf(("cupsLangGet: Using cached copy of \"%s\"...\n", real
));
720 if (!country
[0] || access(filename
, 0))
723 * Country localization not available, look for generic localization...
726 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
729 if (access(filename
, 0))
732 * No generic localization, so use POSIX...
735 DEBUG_printf(("cupsLangGet: access(\"%s\", 0): %s\n", filename
,
738 snprintf(filename
, sizeof(filename
), "%s/C/cups_C.po", cg
->localedir
);
743 * See if there is a free language available; if so, use that
747 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
754 * Allocate memory for the language and add it to the cache.
757 if ((lang
= calloc(sizeof(cups_lang_t
), 1)) == NULL
)
759 #ifdef HAVE_PTHREAD_H
760 pthread_mutex_unlock(&lang_mutex
);
761 #endif /* HAVE_PTHREAD_H */
766 lang
->next
= lang_cache
;
772 * Free all old strings as needed...
775 _cupsMessageFree(lang
->strings
);
779 * Then assign the language and encoding fields...
783 strlcpy(lang
->language
, real
, sizeof(lang
->language
));
785 if (encoding
!= CUPS_AUTO_ENCODING
)
786 lang
->encoding
= encoding
;
788 lang
->encoding
= CUPS_UTF8
;
791 * Read the strings from the file...
794 lang
->strings
= _cupsMessageLoad(filename
);
800 #ifdef HAVE_PTHREAD_H
801 pthread_mutex_unlock(&lang_mutex
);
802 #endif /* HAVE_PTHREAD_H */
809 * '_cupsLangString()' - Get a message string.
811 * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
812 * convert the string to the language encoding.
815 const char * /* O - Localized message */
816 _cupsLangString(cups_lang_t
*lang
, /* I - Language */
817 const char *message
) /* I - Message */
820 * Range check input...
823 if (!lang
|| !message
)
826 #ifdef HAVE_PTHREAD_H
828 const char *s
; /* Localized message */
830 pthread_mutex_lock(&lang_mutex
);
832 s
= _cupsMessageLookup(lang
->strings
, message
);
834 pthread_mutex_unlock(&lang_mutex
);
839 return (_cupsMessageLookup(lang
->strings
, message
));
840 #endif /* HAVE_PTHREAD_H */
845 * '_cupsMessageFree()' - Free a messages array.
849 _cupsMessageFree(cups_array_t
*a
) /* I - Message array */
851 _cups_message_t
*m
; /* Current message */
854 for (m
= (_cups_message_t
*)cupsArrayFirst(a
);
856 m
= (_cups_message_t
*)cupsArrayNext(a
))
859 * Remove the message from the array, then free the message and strings.
862 cupsArrayRemove(a
, m
);
882 * '_cupsMessageLoad()' - Load a .po file into a messages array.
885 cups_array_t
* /* O - New message array */
886 _cupsMessageLoad(const char *filename
) /* I - Message catalog to load */
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(("_cupsMessageLoad(filename=\"%s\")\n", 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("_cupsMessageLoad: Unable to allocate array!");
910 * Open the message catalog file...
913 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
915 DEBUG_printf(("_cupsMessageLoad: Unable to open file: %s\n",
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...
970 cups_unquote(ptr
, ptr
);
973 * Create or add to a message...
976 if (!strncmp(s
, "msgid", 5))
979 * Add previous message as needed...
986 * Create a new message with the given msgid string...
989 if ((m
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
995 if ((m
->id
= strdup(ptr
)) == NULL
)
1002 else if (s
[0] == '\"' && m
)
1005 * Append to current string...
1008 length
= (int)strlen(m
->str
? m
->str
: m
->id
);
1010 if ((temp
= realloc(m
->str
? m
->str
: m
->id
,
1011 length
+ strlen(ptr
) + 1)) == NULL
)
1020 * Copy the new portion to the end of the msgstr string - safe
1021 * to use strcpy because the buffer is allocated to the correct
1027 strcpy(m
->str
+ length
, ptr
);
1032 * Copy the new portion to the end of the msgid string - safe
1033 * to use strcpy because the buffer is allocated to the correct
1039 strcpy(m
->id
+ length
, ptr
);
1042 else if (!strncmp(s
, "msgstr", 6) && m
)
1048 if ((m
->str
= strdup(ptr
)) == NULL
)
1057 * Add the last message string to the array as needed...
1064 * Close the message catalog file and return the new array...
1069 DEBUG_printf(("_cupsMessageLoad: Returning %d messages...\n",
1070 cupsArrayCount(a
)));
1077 * '_cupsMessageLookup()' - Lookup a message string.
1080 const char * /* O - Localized message */
1081 _cupsMessageLookup(cups_array_t
*a
, /* I - Message array */
1082 const char *m
) /* I - Message */
1084 _cups_message_t key
, /* Search key */
1085 *match
; /* Matching message */
1089 * Lookup the message string; if it doesn't exist in the catalog,
1090 * then return the message that was passed to us...
1094 match
= (_cups_message_t
*)cupsArrayFind(a
, &key
);
1096 if (match
&& match
->str
)
1097 return (match
->str
);
1105 * 'appleLangDefault()' - Get the default locale string.
1108 static const char * /* O - Locale string */
1109 appleLangDefault(void)
1111 int i
; /* Looping var */
1112 CFBundleRef bundle
; /* Main bundle (if any) */
1113 CFArrayRef bundleList
; /* List of localizations in bundle */
1114 CFPropertyListRef localizationList
;
1115 /* List of localization data */
1116 CFStringRef languageName
; /* Current name */
1117 CFStringRef localeName
; /* Canonical from of name */
1118 char *lang
; /* LANG environment variable */
1119 _cups_globals_t
*cg
= _cupsGlobals();
1120 /* Pointer to library globals */
1124 * Only do the lookup and translation the first time.
1127 if (!cg
->language
[0])
1129 if ((lang
= getenv("LANG")))
1131 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1132 return (cg
->language
);
1134 else if ((bundle
= CFBundleGetMainBundle()) != NULL
&&
1135 (bundleList
= CFBundleCopyBundleLocalizations(bundle
)) != NULL
)
1138 CFBundleCopyPreferredLocalizationsFromArray(bundleList
);
1140 CFRelease(bundleList
);
1144 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1145 kCFPreferencesCurrentApplication
);
1147 if (localizationList
)
1149 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1150 CFArrayGetCount(localizationList
) > 0)
1152 languageName
= CFArrayGetValueAtIndex(localizationList
, 0);
1155 CFGetTypeID(languageName
) == CFStringGetTypeID())
1157 localeName
= CFLocaleCreateCanonicalLocaleIdentifierFromString(
1158 kCFAllocatorDefault
, languageName
);
1162 CFStringGetCString(localeName
, cg
->language
, sizeof(cg
->language
),
1163 kCFStringEncodingASCII
);
1164 CFRelease(localeName
);
1166 DEBUG_printf(("appleLangDefault: cg->language=\"%s\"\n",
1170 * Map new language identifiers to locales...
1174 i
< (int)(sizeof(apple_language_locale
) /
1175 sizeof(apple_language_locale
[0]));
1178 if (!strcmp(cg
->language
, apple_language_locale
[i
].language
))
1180 DEBUG_printf(("appleLangDefault: mapping \"%s\" to \"%s\"...\n",
1181 cg
->language
, apple_language_locale
[i
].locale
));
1182 strlcpy(cg
->language
, apple_language_locale
[i
].locale
,
1183 sizeof(cg
->language
));
1189 * Convert language subtag into region subtag...
1192 if (cg
->language
[2] == '-')
1193 cg
->language
[2] = '_';
1195 if (!strchr(cg
->language
, '.'))
1196 strlcat(cg
->language
, ".UTF-8", sizeof(cg
->language
));
1201 CFRelease(localizationList
);
1205 * If we didn't find the language, default to en_US...
1208 if (!cg
->language
[0])
1209 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1213 * Return the cached locale...
1216 return (cg
->language
);
1218 #endif /* __APPLE__ */
1222 * 'cups_cache_lookup()' - Lookup a language in the cache...
1225 static cups_lang_t
* /* O - Language data or NULL */
1226 cups_cache_lookup(const char *name
,/* I - Name of locale */
1227 cups_encoding_t encoding
)
1228 /* I - Encoding of locale */
1230 cups_lang_t
*lang
; /* Current language */
1233 DEBUG_printf(("cups_cache_lookup(name=\"%s\", encoding=%d(%s))\n", name
,
1234 encoding
, encoding
== CUPS_AUTO_ENCODING
? "auto" :
1235 lang_encodings
[encoding
]));
1238 * Loop through the cache and return a match if found...
1241 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
1243 DEBUG_printf(("cups_cache_lookup: lang=%p, language=\"%s\", encoding=%d(%s)\n",
1244 lang
, lang
->language
, lang
->encoding
,
1245 lang_encodings
[lang
->encoding
]));
1247 if (!strcmp(lang
->language
, name
) &&
1248 (encoding
== CUPS_AUTO_ENCODING
|| encoding
== lang
->encoding
))
1252 DEBUG_puts("cups_cache_lookup: returning match!");
1258 DEBUG_puts("cups_cache_lookup: returning NULL!");
1265 * 'cups_message_compare()' - Compare two messages.
1268 static int /* O - Result of comparison */
1269 cups_message_compare(
1270 _cups_message_t
*m1
, /* I - First message */
1271 _cups_message_t
*m2
) /* I - Second message */
1273 return (strcmp(m1
->id
, m2
->id
));
1278 * 'cups_unquote()' - Unquote characters in strings...
1282 cups_unquote(char *d
, /* O - Unquoted string */
1283 const char *s
) /* I - Original string */
1296 *d
= *d
* 8 + *s
- '0';
1325 * End of "$Id: language.c 7558 2008-05-12 23:46:44Z mike $".