2 * "$Id: language.c 7558 2008-05-12 23:46:44Z mike $"
4 * I18N/language support for CUPS.
6 * Copyright 2007-2010 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...
43 #include "cups-private.h"
44 #ifdef HAVE_LANGINFO_H
45 # include <langinfo.h>
46 #endif /* HAVE_LANGINFO_H */
52 #ifdef HAVE_COREFOUNDATION_H
53 # include <CoreFoundation/CoreFoundation.h>
54 #endif /* HAVE_COREFOUNDATION_H */
61 static _cups_mutex_t lang_mutex
= _CUPS_MUTEX_INITIALIZER
;
62 /* Mutex to control access to cache */
63 static cups_lang_t
*lang_cache
= NULL
;
64 /* Language string cache */
65 static const char * const lang_encodings
[] =
66 { /* Encoding strings */
67 "us-ascii", "iso-8859-1",
68 "iso-8859-2", "iso-8859-3",
69 "iso-8859-4", "iso-8859-5",
70 "iso-8859-6", "iso-8859-7",
71 "iso-8859-8", "iso-8859-9",
72 "iso-8859-10", "utf-8",
73 "iso-8859-13", "iso-8859-14",
74 "iso-8859-15", "cp874",
80 "koi8-u", "iso-8859-11",
81 "iso-8859-16", "mac-roman",
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 "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",
139 const char * const language
; /* Language ID */
140 const char * const locale
; /* Locale ID */
141 } _apple_language_locale_t
;
143 static const _apple_language_locale_t apple_language_locale
[] =
144 { /* Locale to language ID LUT */
147 { "zh-Hans" , "zh_CN" },
148 { "zh-Hant" , "zh_TW" }
150 #endif /* __APPLE__ */
158 static const char *appleLangDefault(void);
159 #endif /* __APPLE__ */
160 static cups_lang_t
*cups_cache_lookup(const char *name
,
161 cups_encoding_t encoding
);
162 static int cups_message_compare(_cups_message_t
*m1
,
163 _cups_message_t
*m2
);
164 static void cups_unquote(char *d
, const char *s
);
169 * _cupsAppleLanguage() - Get the Apple language identifier associated
173 const char * /* O - Language ID */
174 _cupsAppleLanguage(const char *locale
, /* I - Locale ID */
175 char *language
,/* I - Language ID buffer */
176 size_t langsize
) /* I - Size of language ID buffer */
178 int i
; /* Looping var */
179 CFStringRef localeid
, /* CF locale identifier */
180 langid
; /* CF language identifier */
184 * Copy the locale name and convert, as needed, to the Apple-specific
185 * locale identifier...
188 switch (strlen(locale
))
195 strlcpy(language
, "en", langsize
);
199 strlcpy(language
, locale
, langsize
);
203 strlcpy(language
, locale
, langsize
);
205 if (language
[2] == '-')
208 * Convert ll-cc to ll_CC...
212 language
[3] = toupper(language
[3] & 255);
213 language
[4] = toupper(language
[4] & 255);
219 i
< (int)(sizeof(apple_language_locale
) /
220 sizeof(apple_language_locale
[0]));
222 if (!strcmp(locale
, apple_language_locale
[i
].locale
))
224 strlcpy(language
, apple_language_locale
[i
].language
, sizeof(language
));
229 * Attempt to map the locale ID to a language ID...
232 if ((localeid
= CFStringCreateWithCString(kCFAllocatorDefault
, language
,
233 kCFStringEncodingASCII
)) != NULL
)
235 if ((langid
= CFLocaleCreateCanonicalLanguageIdentifierFromString(
236 kCFAllocatorDefault
, localeid
)) != NULL
)
238 CFStringGetCString(langid
, language
, langsize
, kCFStringEncodingASCII
);
246 * Return what we got...
251 #endif /* __APPLE__ */
255 * '_cupsEncodingName()' - Return the character encoding name string
256 * for the given encoding enumeration.
259 const char * /* O - Character encoding */
261 cups_encoding_t encoding
) /* I - Encoding value */
264 encoding
>= (sizeof(lang_encodings
) / sizeof(const char *)))
266 DEBUG_printf(("1_cupsEncodingName(encoding=%d) = out of range (\"%s\")",
267 encoding
, lang_encodings
[0]));
268 return (lang_encodings
[0]);
272 DEBUG_printf(("1_cupsEncodingName(encoding=%d) = \"%s\"",
273 encoding
, lang_encodings
[encoding
]));
274 return (lang_encodings
[encoding
]);
280 * 'cupsLangDefault()' - Return the default language.
283 cups_lang_t
* /* O - Language data */
284 cupsLangDefault(void)
286 return (cupsLangGet(NULL
));
291 * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
292 * for the given language.
295 const char * /* O - Character encoding */
296 cupsLangEncoding(cups_lang_t
*lang
) /* I - Language data */
299 return ((char*)lang_encodings
[0]);
301 return ((char*)lang_encodings
[lang
->encoding
]);
306 * 'cupsLangFlush()' - Flush all language data out of the cache.
312 cups_lang_t
*lang
, /* Current language */
313 *next
; /* Next language */
317 * Free all languages in the cache...
320 _cupsMutexLock(&lang_mutex
);
322 for (lang
= lang_cache
; lang
!= NULL
; lang
= next
)
325 * Free all messages...
328 _cupsMessageFree(lang
->strings
);
331 * Then free the language structure itself...
340 _cupsMutexUnlock(&lang_mutex
);
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 _cupsMutexLock(&lang_mutex
);
355 if (lang
!= NULL
&& lang
->used
> 0)
358 _cupsMutexUnlock(&lang_mutex
);
363 * 'cupsLangGet()' - Get a language.
366 cups_lang_t
* /* O - Language data */
367 cupsLangGet(const char *language
) /* I - Language or locale */
369 int i
; /* Looping var */
371 char locale
[255]; /* Copy of locale name */
372 #endif /* !__APPLE__ */
373 char langname
[16], /* Requested language name */
374 country
[16], /* Country code */
375 charset
[16], /* Character set */
376 *csptr
, /* Pointer to CODESET string */
377 *ptr
, /* Pointer into language/charset */
378 real
[48], /* Real language name */
379 filename
[1024]; /* Filename for language locale file */
380 cups_encoding_t encoding
; /* Encoding to use */
381 cups_lang_t
*lang
; /* Current language... */
382 _cups_globals_t
*cg
= _cupsGlobals();
383 /* Pointer to library globals */
384 static const char * const locale_encodings
[] =
385 { /* Locale charset names */
386 "ASCII", "ISO88591", "ISO88592", "ISO88593",
387 "ISO88594", "ISO88595", "ISO88596", "ISO88597",
388 "ISO88598", "ISO88599", "ISO885910", "UTF8",
389 "ISO885913", "ISO885914", "ISO885915", "CP874",
390 "CP1250", "CP1251", "CP1252", "CP1253",
391 "CP1254", "CP1255", "CP1256", "CP1257",
392 "CP1258", "KOI8R", "KOI8U", "ISO885911",
393 "ISO885916", "MACROMAN", "", "",
404 "CP932", "CP936", "CP949", "CP950",
405 "CP1361", "", "", "",
422 "EUCCN", "EUCJP", "EUCKR", "EUCTW",
427 DEBUG_printf(("2cupsLangGet(language=\"%s\")", language
));
431 * Set the character set to UTF-8...
434 strcpy(charset
, "UTF8");
437 * Apple's setlocale doesn't give us the user's localization
438 * preference so we have to look it up this way...
443 if (!getenv("SOFTWARE") || (language
= getenv("LANG")) == NULL
)
444 language
= appleLangDefault();
446 DEBUG_printf(("4cupsLangGet: language=\"%s\"", language
));
451 * Set the charset to "unknown"...
457 * Use setlocale() to determine the currently set locale, and then
458 * fallback to environment variables to avoid setting the locale,
459 * since setlocale() is not thread-safe!
465 * First see if the locale has been set; if it is still "C" or
466 * "POSIX", use the environment to get the default...
470 ptr
= setlocale(LC_MESSAGES
, NULL
);
472 ptr
= setlocale(LC_ALL
, NULL
);
473 # endif /* LC_MESSAGES */
475 DEBUG_printf(("4cupsLangGet: current locale is \"%s\"", ptr
));
477 if (!ptr
|| !strcmp(ptr
, "C") || !strcmp(ptr
, "POSIX"))
480 * Get the character set from the LC_CTYPE locale setting...
483 if ((ptr
= getenv("LC_CTYPE")) == NULL
)
484 if ((ptr
= getenv("LC_ALL")) == NULL
)
485 if ((ptr
= getenv("LANG")) == NULL
)
488 if ((csptr
= strchr(ptr
, '.')) != NULL
)
491 * Extract the character set from the environment...
494 for (ptr
= charset
, csptr
++; *csptr
; csptr
++)
495 if (ptr
< (charset
+ sizeof(charset
) - 1) && isalnum(*csptr
& 255))
502 * Get the locale for messages from the LC_MESSAGES locale setting...
505 if ((ptr
= getenv("LC_MESSAGES")) == NULL
)
506 if ((ptr
= getenv("LC_ALL")) == NULL
)
507 if ((ptr
= getenv("LANG")) == NULL
)
513 strlcpy(locale
, ptr
, sizeof(locale
));
517 * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
520 if (!strncmp(locale
, "nb", 2))
523 DEBUG_printf(("4cupsLangGet: new language value is \"%s\"", language
));
526 #endif /* __APPLE__ */
529 * If "language" is NULL at this point, then chances are we are using
530 * a language that is not installed for the base OS.
536 * Switch to the POSIX ("C") locale...
544 * On systems that support the nl_langinfo(CODESET) call, use
545 * this value as the character set...
548 if (!charset
[0] && (csptr
= nl_langinfo(CODESET
)) != NULL
)
551 * Copy all of the letters and numbers in the CODESET string...
554 for (ptr
= charset
; *csptr
; csptr
++)
555 if (isalnum(*csptr
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
560 DEBUG_printf(("4cupsLangGet: charset set to \"%s\" via "
561 "nl_langinfo(CODESET)...", charset
));
566 * If we don't have a character set by now, default to UTF-8...
570 strcpy(charset
, "UTF8");
573 * Parse the language string passed in to a locale string. "C" is the
574 * standard POSIX locale and is copied unchanged. Otherwise the
575 * language string is converted from ll-cc[.charset] (language-country)
576 * to ll_CC[.CHARSET] to match the file naming convention used by all
577 * POSIX-compliant operating systems. Invalid language names are mapped
578 * to the POSIX locale.
583 if (language
== NULL
|| !language
[0] ||
584 !strcmp(language
, "POSIX"))
585 strcpy(langname
, "C");
589 * Copy the parts of the locale string over safely...
592 for (ptr
= langname
; *language
; language
++)
593 if (*language
== '_' || *language
== '-' || *language
== '.')
595 else if (ptr
< (langname
+ sizeof(langname
) - 1))
596 *ptr
++ = tolower(*language
& 255);
600 if (*language
== '_' || *language
== '-')
603 * Copy the country code...
606 for (language
++, ptr
= country
; *language
; language
++)
607 if (*language
== '.')
609 else if (ptr
< (country
+ sizeof(country
) - 1))
610 *ptr
++ = toupper(*language
& 255);
615 if (*language
== '.' && !charset
[0])
618 * Copy the encoding...
621 for (language
++, ptr
= charset
; *language
; language
++)
622 if (isalnum(*language
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
623 *ptr
++ = toupper(*language
& 255);
629 * Force a POSIX locale for an invalid language name...
632 if (strlen(langname
) != 2)
634 strcpy(langname
, "C");
640 DEBUG_printf(("4cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"",
641 langname
, country
, charset
));
644 * Figure out the desired encoding...
647 encoding
= CUPS_AUTO_ENCODING
;
652 i
< (int)(sizeof(locale_encodings
) / sizeof(locale_encodings
[0]));
654 if (!strcasecmp(charset
, locale_encodings
[i
]))
656 encoding
= (cups_encoding_t
)i
;
660 if (encoding
== CUPS_AUTO_ENCODING
)
663 * Map alternate names for various character sets...
666 if (!strcasecmp(charset
, "iso-2022-jp") ||
667 !strcasecmp(charset
, "sjis"))
668 encoding
= CUPS_WINDOWS_932
;
669 else if (!strcasecmp(charset
, "iso-2022-cn"))
670 encoding
= CUPS_WINDOWS_936
;
671 else if (!strcasecmp(charset
, "iso-2022-kr"))
672 encoding
= CUPS_WINDOWS_949
;
673 else if (!strcasecmp(charset
, "big5"))
674 encoding
= CUPS_WINDOWS_950
;
678 DEBUG_printf(("4cupsLangGet: encoding=%d(%s)", encoding
,
679 encoding
== CUPS_AUTO_ENCODING
? "auto" :
680 lang_encodings
[encoding
]));
683 * See if we already have this language/country loaded...
688 snprintf(real
, sizeof(real
), "%s_%s", langname
, country
);
690 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
695 strcpy(real
, langname
);
696 filename
[0] = '\0'; /* anti-compiler-warning-code */
699 _cupsMutexLock(&lang_mutex
);
701 if ((lang
= cups_cache_lookup(real
, encoding
)) != NULL
)
703 _cupsMutexUnlock(&lang_mutex
);
705 DEBUG_printf(("3cupsLangGet: Using cached copy of \"%s\"...", real
));
710 if (!country
[0] || access(filename
, 0))
713 * Country localization not available, look for generic localization...
716 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
719 if (access(filename
, 0))
722 * No generic localization, so use POSIX...
725 DEBUG_printf(("4cupsLangGet: access(\"%s\", 0): %s", filename
,
728 snprintf(filename
, sizeof(filename
), "%s/C/cups_C.po", cg
->localedir
);
733 * See if there is a free language available; if so, use that
737 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
744 * Allocate memory for the language and add it to the cache.
747 if ((lang
= calloc(sizeof(cups_lang_t
), 1)) == NULL
)
749 _cupsMutexUnlock(&lang_mutex
);
754 lang
->next
= lang_cache
;
760 * Free all old strings as needed...
763 _cupsMessageFree(lang
->strings
);
767 * Then assign the language and encoding fields...
771 strlcpy(lang
->language
, real
, sizeof(lang
->language
));
773 if (encoding
!= CUPS_AUTO_ENCODING
)
774 lang
->encoding
= encoding
;
776 lang
->encoding
= CUPS_UTF8
;
779 * Read the strings from the file...
782 lang
->strings
= _cupsMessageLoad(filename
, 1);
788 _cupsMutexUnlock(&lang_mutex
);
795 * '_cupsLangString()' - Get a message string.
797 * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
798 * convert the string to the language encoding.
801 const char * /* O - Localized message */
802 _cupsLangString(cups_lang_t
*lang
, /* I - Language */
803 const char *message
) /* I - Message */
805 const char *s
; /* Localized message */
808 * Range check input...
811 if (!lang
|| !message
)
814 _cupsMutexLock(&lang_mutex
);
816 s
= _cupsMessageLookup(lang
->strings
, message
);
818 _cupsMutexUnlock(&lang_mutex
);
825 * '_cupsMessageFree()' - Free a messages array.
829 _cupsMessageFree(cups_array_t
*a
) /* I - Message array */
831 _cups_message_t
*m
; /* Current message */
834 for (m
= (_cups_message_t
*)cupsArrayFirst(a
);
836 m
= (_cups_message_t
*)cupsArrayNext(a
))
839 * Remove the message from the array, then free the message and strings.
842 cupsArrayRemove(a
, m
);
862 * '_cupsMessageLoad()' - Load a .po file into a messages array.
865 cups_array_t
* /* O - New message array */
866 _cupsMessageLoad(const char *filename
, /* I - Message catalog to load */
867 int unquote
) /* I - Unescape \foo in strings */
869 cups_file_t
*fp
; /* Message file */
870 cups_array_t
*a
; /* Message array */
871 _cups_message_t
*m
; /* Current message */
872 char s
[4096], /* String buffer */
873 *ptr
, /* Pointer into buffer */
874 *temp
; /* New string */
875 int length
; /* Length of combined strings */
878 DEBUG_printf(("4_cupsMessageLoad(filename=\"%s\")", filename
));
881 * Create an array to hold the messages...
884 if ((a
= cupsArrayNew((cups_array_func_t
)cups_message_compare
, NULL
)) == NULL
)
886 DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!");
891 * Open the message catalog file...
894 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
896 DEBUG_printf(("5_cupsMessageLoad: Unable to open file: %s",
902 * Read messages from the catalog file until EOF...
904 * The format is the GNU gettext .po format, which is fairly simple:
907 * msgstr "localized text"
909 * The ID and localized text can span multiple lines using the form:
914 * "localized text spanning "
920 while (cupsFileGets(fp
, s
, sizeof(s
)) != NULL
)
923 * Skip blank and comment lines...
926 if (s
[0] == '#' || !s
[0])
930 * Strip the trailing quote...
933 if ((ptr
= strrchr(s
, '\"')) == NULL
)
939 * Find start of value...
942 if ((ptr
= strchr(s
, '\"')) == NULL
)
948 * Unquote the text...
952 cups_unquote(ptr
, ptr
);
955 * Create or add to a message...
958 if (!strncmp(s
, "msgid", 5))
961 * Add previous message as needed...
968 * Create a new message with the given msgid string...
971 if ((m
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
977 if ((m
->id
= strdup(ptr
)) == NULL
)
984 else if (s
[0] == '\"' && m
)
987 * Append to current string...
990 length
= (int)strlen(m
->str
? m
->str
: m
->id
);
992 if ((temp
= realloc(m
->str
? m
->str
: m
->id
,
993 length
+ strlen(ptr
) + 1)) == NULL
)
1002 * Copy the new portion to the end of the msgstr string - safe
1003 * to use strcpy because the buffer is allocated to the correct
1009 strcpy(m
->str
+ length
, ptr
);
1014 * Copy the new portion to the end of the msgid string - safe
1015 * to use strcpy because the buffer is allocated to the correct
1021 strcpy(m
->id
+ length
, ptr
);
1024 else if (!strncmp(s
, "msgstr", 6) && m
)
1030 if ((m
->str
= strdup(ptr
)) == NULL
)
1039 * Add the last message string to the array as needed...
1046 * Close the message catalog file and return the new array...
1051 DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...",
1052 cupsArrayCount(a
)));
1059 * '_cupsMessageLookup()' - Lookup a message string.
1062 const char * /* O - Localized message */
1063 _cupsMessageLookup(cups_array_t
*a
, /* I - Message array */
1064 const char *m
) /* I - Message */
1066 _cups_message_t key
, /* Search key */
1067 *match
; /* Matching message */
1071 * Lookup the message string; if it doesn't exist in the catalog,
1072 * then return the message that was passed to us...
1076 match
= (_cups_message_t
*)cupsArrayFind(a
, &key
);
1078 if (match
&& match
->str
)
1079 return (match
->str
);
1087 * 'appleLangDefault()' - Get the default locale string.
1090 static const char * /* O - Locale string */
1091 appleLangDefault(void)
1093 int i
; /* Looping var */
1094 CFBundleRef bundle
; /* Main bundle (if any) */
1095 CFArrayRef bundleList
; /* List of localizations in bundle */
1096 CFPropertyListRef localizationList
;
1097 /* List of localization data */
1098 CFStringRef languageName
; /* Current name */
1099 CFStringRef localeName
; /* Canonical from of name */
1100 char *lang
; /* LANG environment variable */
1101 _cups_globals_t
*cg
= _cupsGlobals();
1102 /* Pointer to library globals */
1105 DEBUG_puts("2appleLangDefault()");
1108 * Only do the lookup and translation the first time.
1111 if (!cg
->language
[0])
1113 if (getenv("SOFTWARE") != NULL
&& (lang
= getenv("LANG")) != NULL
)
1115 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1116 return (cg
->language
);
1118 else if ((bundle
= CFBundleGetMainBundle()) != NULL
&&
1119 (bundleList
= CFBundleCopyBundleLocalizations(bundle
)) != NULL
)
1122 CFBundleCopyPreferredLocalizationsFromArray(bundleList
);
1124 CFRelease(bundleList
);
1128 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1129 kCFPreferencesCurrentApplication
);
1131 if (localizationList
)
1133 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1134 CFArrayGetCount(localizationList
) > 0)
1136 languageName
= CFArrayGetValueAtIndex(localizationList
, 0);
1139 CFGetTypeID(languageName
) == CFStringGetTypeID())
1141 localeName
= CFLocaleCreateCanonicalLocaleIdentifierFromString(
1142 kCFAllocatorDefault
, languageName
);
1146 CFStringGetCString(localeName
, cg
->language
, sizeof(cg
->language
),
1147 kCFStringEncodingASCII
);
1148 CFRelease(localeName
);
1150 DEBUG_printf(("9appleLangDefault: cg->language=\"%s\"",
1154 * Map new language identifiers to locales...
1158 i
< (int)(sizeof(apple_language_locale
) /
1159 sizeof(apple_language_locale
[0]));
1162 if (!strcmp(cg
->language
, apple_language_locale
[i
].language
))
1164 DEBUG_printf(("9appleLangDefault: mapping \"%s\" to \"%s\"...",
1165 cg
->language
, apple_language_locale
[i
].locale
));
1166 strlcpy(cg
->language
, apple_language_locale
[i
].locale
,
1167 sizeof(cg
->language
));
1173 * Convert language subtag into region subtag...
1176 if (cg
->language
[2] == '-')
1177 cg
->language
[2] = '_';
1179 if (!strchr(cg
->language
, '.'))
1180 strlcat(cg
->language
, ".UTF-8", sizeof(cg
->language
));
1185 CFRelease(localizationList
);
1189 * If we didn't find the language, default to en_US...
1192 if (!cg
->language
[0])
1193 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1197 * Return the cached locale...
1200 return (cg
->language
);
1202 #endif /* __APPLE__ */
1206 * 'cups_cache_lookup()' - Lookup a language in the cache...
1209 static cups_lang_t
* /* O - Language data or NULL */
1210 cups_cache_lookup(const char *name
,/* I - Name of locale */
1211 cups_encoding_t encoding
)
1212 /* I - Encoding of locale */
1214 cups_lang_t
*lang
; /* Current language */
1217 DEBUG_printf(("7cups_cache_lookup(name=\"%s\", encoding=%d(%s))", name
,
1218 encoding
, encoding
== CUPS_AUTO_ENCODING
? "auto" :
1219 lang_encodings
[encoding
]));
1222 * Loop through the cache and return a match if found...
1225 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
1227 DEBUG_printf(("9cups_cache_lookup: lang=%p, language=\"%s\", "
1228 "encoding=%d(%s)", lang
, lang
->language
, lang
->encoding
,
1229 lang_encodings
[lang
->encoding
]));
1231 if (!strcmp(lang
->language
, name
) &&
1232 (encoding
== CUPS_AUTO_ENCODING
|| encoding
== lang
->encoding
))
1236 DEBUG_puts("8cups_cache_lookup: returning match!");
1242 DEBUG_puts("8cups_cache_lookup: returning NULL!");
1249 * 'cups_message_compare()' - Compare two messages.
1252 static int /* O - Result of comparison */
1253 cups_message_compare(
1254 _cups_message_t
*m1
, /* I - First message */
1255 _cups_message_t
*m2
) /* I - Second message */
1257 return (strcmp(m1
->id
, m2
->id
));
1262 * 'cups_unquote()' - Unquote characters in strings...
1266 cups_unquote(char *d
, /* O - Unquoted string */
1267 const char *s
) /* I - Original string */
1280 *d
= *d
* 8 + *s
- '0';
1309 * End of "$Id: language.c 7558 2008-05-12 23:46:44Z mike $".