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", "windows-874",
75 "windows-1250", "windows-1251",
76 "windows-1252", "windows-1253",
77 "windows-1254", "windows-1255",
78 "windows-1256", "windows-1257",
79 "windows-1258", "koi8-r",
80 "koi8-u", "iso-8859-11",
81 "iso-8859-16", "mac-roman",
99 "windows-932", "windows-936",
100 "windows-949", "windows-950",
101 "windows-1361", "unknown",
102 "unknown", "unknown",
103 "unknown", "unknown",
104 "unknown", "unknown",
105 "unknown", "unknown",
106 "unknown", "unknown",
107 "unknown", "unknown",
108 "unknown", "unknown",
109 "unknown", "unknown",
110 "unknown", "unknown",
111 "unknown", "unknown",
112 "unknown", "unknown",
113 "unknown", "unknown",
114 "unknown", "unknown",
115 "unknown", "unknown",
116 "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 *)))
265 return (lang_encodings
[0]);
267 return (lang_encodings
[encoding
]);
272 * 'cupsLangDefault()' - Return the default language.
275 cups_lang_t
* /* O - Language data */
276 cupsLangDefault(void)
278 return (cupsLangGet(NULL
));
283 * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
284 * for the given language.
287 const char * /* O - Character encoding */
288 cupsLangEncoding(cups_lang_t
*lang
) /* I - Language data */
291 return ((char*)lang_encodings
[0]);
293 return ((char*)lang_encodings
[lang
->encoding
]);
298 * 'cupsLangFlush()' - Flush all language data out of the cache.
304 cups_lang_t
*lang
, /* Current language */
305 *next
; /* Next language */
309 * Free all languages in the cache...
312 _cupsMutexLock(&lang_mutex
);
314 for (lang
= lang_cache
; lang
!= NULL
; lang
= next
)
317 * Free all messages...
320 _cupsMessageFree(lang
->strings
);
323 * Then free the language structure itself...
332 _cupsMutexUnlock(&lang_mutex
);
337 * 'cupsLangFree()' - Free language data.
339 * This does not actually free anything; use @link cupsLangFlush@ for that.
343 cupsLangFree(cups_lang_t
*lang
) /* I - Language to free */
345 _cupsMutexLock(&lang_mutex
);
347 if (lang
!= NULL
&& lang
->used
> 0)
350 _cupsMutexUnlock(&lang_mutex
);
355 * 'cupsLangGet()' - Get a language.
358 cups_lang_t
* /* O - Language data */
359 cupsLangGet(const char *language
) /* I - Language or locale */
361 int i
; /* Looping var */
363 char locale
[255]; /* Copy of locale name */
364 #endif /* !__APPLE__ */
365 char langname
[16], /* Requested language name */
366 country
[16], /* Country code */
367 charset
[16], /* Character set */
368 *csptr
, /* Pointer to CODESET string */
369 *ptr
, /* Pointer into language/charset */
370 real
[48], /* Real language name */
371 filename
[1024]; /* Filename for language locale file */
372 cups_encoding_t encoding
; /* Encoding to use */
373 cups_lang_t
*lang
; /* Current language... */
374 _cups_globals_t
*cg
= _cupsGlobals();
375 /* Pointer to library globals */
376 static const char * const locale_encodings
[] =
377 { /* Locale charset names */
378 "ASCII", "ISO88591", "ISO88592", "ISO88593",
379 "ISO88594", "ISO88595", "ISO88596", "ISO88597",
380 "ISO88598", "ISO88599", "ISO885910", "UTF8",
381 "ISO885913", "ISO885914", "ISO885915", "CP874",
382 "CP1250", "CP1251", "CP1252", "CP1253",
383 "CP1254", "CP1255", "CP1256", "CP1257",
384 "CP1258", "KOI8R", "KOI8U", "ISO885911",
385 "ISO885916", "MACROMAN", "", "",
396 "CP932", "CP936", "CP949", "CP950",
397 "CP1361", "", "", "",
414 "EUCCN", "EUCJP", "EUCKR", "EUCTW",
419 DEBUG_printf(("2cupsLangGet(language=\"%s\")", language
));
423 * Set the character set to UTF-8...
426 strcpy(charset
, "UTF8");
429 * Apple's setlocale doesn't give us the user's localization
430 * preference so we have to look it up this way...
435 if (!getenv("SOFTWARE") || (language
= getenv("LANG")) == NULL
)
436 language
= appleLangDefault();
438 DEBUG_printf(("4cupsLangGet: language=\"%s\"", language
));
443 * Set the charset to "unknown"...
449 * Use setlocale() to determine the currently set locale, and then
450 * fallback to environment variables to avoid setting the locale,
451 * since setlocale() is not thread-safe!
457 * First see if the locale has been set; if it is still "C" or
458 * "POSIX", use the environment to get the default...
462 ptr
= setlocale(LC_MESSAGES
, NULL
);
464 ptr
= setlocale(LC_ALL
, NULL
);
465 # endif /* LC_MESSAGES */
467 DEBUG_printf(("4cupsLangGet: current locale is \"%s\"", ptr
));
469 if (!ptr
|| !strcmp(ptr
, "C") || !strcmp(ptr
, "POSIX"))
472 * Get the character set from the LC_CTYPE locale setting...
475 if ((ptr
= getenv("LC_CTYPE")) == NULL
)
476 if ((ptr
= getenv("LC_ALL")) == NULL
)
477 if ((ptr
= getenv("LANG")) == NULL
)
480 if ((csptr
= strchr(ptr
, '.')) != NULL
)
483 * Extract the character set from the environment...
486 for (ptr
= charset
, csptr
++; *csptr
; csptr
++)
487 if (ptr
< (charset
+ sizeof(charset
) - 1) && isalnum(*csptr
& 255))
494 * Get the locale for messages from the LC_MESSAGES locale setting...
497 if ((ptr
= getenv("LC_MESSAGES")) == NULL
)
498 if ((ptr
= getenv("LC_ALL")) == NULL
)
499 if ((ptr
= getenv("LANG")) == NULL
)
505 strlcpy(locale
, ptr
, sizeof(locale
));
509 * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
512 if (!strncmp(locale
, "nb", 2))
515 DEBUG_printf(("4cupsLangGet: new language value is \"%s\"", language
));
518 #endif /* __APPLE__ */
521 * If "language" is NULL at this point, then chances are we are using
522 * a language that is not installed for the base OS.
528 * Switch to the POSIX ("C") locale...
536 * On systems that support the nl_langinfo(CODESET) call, use
537 * this value as the character set...
540 if (!charset
[0] && (csptr
= nl_langinfo(CODESET
)) != NULL
)
543 * Copy all of the letters and numbers in the CODESET string...
546 for (ptr
= charset
; *csptr
; csptr
++)
547 if (isalnum(*csptr
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
552 DEBUG_printf(("4cupsLangGet: charset set to \"%s\" via "
553 "nl_langinfo(CODESET)...", charset
));
558 * If we don't have a character set by now, default to UTF-8...
562 strcpy(charset
, "UTF8");
565 * Parse the language string passed in to a locale string. "C" is the
566 * standard POSIX locale and is copied unchanged. Otherwise the
567 * language string is converted from ll-cc[.charset] (language-country)
568 * to ll_CC[.CHARSET] to match the file naming convention used by all
569 * POSIX-compliant operating systems. Invalid language names are mapped
570 * to the POSIX locale.
575 if (language
== NULL
|| !language
[0] ||
576 !strcmp(language
, "POSIX"))
577 strcpy(langname
, "C");
581 * Copy the parts of the locale string over safely...
584 for (ptr
= langname
; *language
; language
++)
585 if (*language
== '_' || *language
== '-' || *language
== '.')
587 else if (ptr
< (langname
+ sizeof(langname
) - 1))
588 *ptr
++ = tolower(*language
& 255);
592 if (*language
== '_' || *language
== '-')
595 * Copy the country code...
598 for (language
++, ptr
= country
; *language
; language
++)
599 if (*language
== '.')
601 else if (ptr
< (country
+ sizeof(country
) - 1))
602 *ptr
++ = toupper(*language
& 255);
607 if (*language
== '.' && !charset
[0])
610 * Copy the encoding...
613 for (language
++, ptr
= charset
; *language
; language
++)
614 if (isalnum(*language
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
615 *ptr
++ = toupper(*language
& 255);
621 * Force a POSIX locale for an invalid language name...
624 if (strlen(langname
) != 2)
626 strcpy(langname
, "C");
632 DEBUG_printf(("4cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"",
633 langname
, country
, charset
));
636 * Figure out the desired encoding...
639 encoding
= CUPS_AUTO_ENCODING
;
644 i
< (int)(sizeof(locale_encodings
) / sizeof(locale_encodings
[0]));
646 if (!strcasecmp(charset
, locale_encodings
[i
]))
648 encoding
= (cups_encoding_t
)i
;
652 if (encoding
== CUPS_AUTO_ENCODING
)
655 * Map alternate names for various character sets...
658 if (!strcasecmp(charset
, "iso-2022-jp") ||
659 !strcasecmp(charset
, "sjis"))
660 encoding
= CUPS_WINDOWS_932
;
661 else if (!strcasecmp(charset
, "iso-2022-cn"))
662 encoding
= CUPS_WINDOWS_936
;
663 else if (!strcasecmp(charset
, "iso-2022-kr"))
664 encoding
= CUPS_WINDOWS_949
;
665 else if (!strcasecmp(charset
, "big5"))
666 encoding
= CUPS_WINDOWS_950
;
670 DEBUG_printf(("4cupsLangGet: encoding=%d(%s)", encoding
,
671 encoding
== CUPS_AUTO_ENCODING
? "auto" :
672 lang_encodings
[encoding
]));
675 * See if we already have this language/country loaded...
680 snprintf(real
, sizeof(real
), "%s_%s", langname
, country
);
682 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
687 strcpy(real
, langname
);
688 filename
[0] = '\0'; /* anti-compiler-warning-code */
691 _cupsMutexLock(&lang_mutex
);
693 if ((lang
= cups_cache_lookup(real
, encoding
)) != NULL
)
695 _cupsMutexUnlock(&lang_mutex
);
697 DEBUG_printf(("3cupsLangGet: Using cached copy of \"%s\"...", real
));
702 if (!country
[0] || access(filename
, 0))
705 * Country localization not available, look for generic localization...
708 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
711 if (access(filename
, 0))
714 * No generic localization, so use POSIX...
717 DEBUG_printf(("4cupsLangGet: access(\"%s\", 0): %s", filename
,
720 snprintf(filename
, sizeof(filename
), "%s/C/cups_C.po", cg
->localedir
);
725 * See if there is a free language available; if so, use that
729 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
736 * Allocate memory for the language and add it to the cache.
739 if ((lang
= calloc(sizeof(cups_lang_t
), 1)) == NULL
)
741 _cupsMutexUnlock(&lang_mutex
);
746 lang
->next
= lang_cache
;
752 * Free all old strings as needed...
755 _cupsMessageFree(lang
->strings
);
759 * Then assign the language and encoding fields...
763 strlcpy(lang
->language
, real
, sizeof(lang
->language
));
765 if (encoding
!= CUPS_AUTO_ENCODING
)
766 lang
->encoding
= encoding
;
768 lang
->encoding
= CUPS_UTF8
;
771 * Read the strings from the file...
774 lang
->strings
= _cupsMessageLoad(filename
, 1);
780 _cupsMutexUnlock(&lang_mutex
);
787 * '_cupsLangString()' - Get a message string.
789 * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
790 * convert the string to the language encoding.
793 const char * /* O - Localized message */
794 _cupsLangString(cups_lang_t
*lang
, /* I - Language */
795 const char *message
) /* I - Message */
797 const char *s
; /* Localized message */
800 * Range check input...
803 if (!lang
|| !message
)
806 _cupsMutexLock(&lang_mutex
);
808 s
= _cupsMessageLookup(lang
->strings
, message
);
810 _cupsMutexUnlock(&lang_mutex
);
817 * '_cupsMessageFree()' - Free a messages array.
821 _cupsMessageFree(cups_array_t
*a
) /* I - Message array */
823 _cups_message_t
*m
; /* Current message */
826 for (m
= (_cups_message_t
*)cupsArrayFirst(a
);
828 m
= (_cups_message_t
*)cupsArrayNext(a
))
831 * Remove the message from the array, then free the message and strings.
834 cupsArrayRemove(a
, m
);
854 * '_cupsMessageLoad()' - Load a .po file into a messages array.
857 cups_array_t
* /* O - New message array */
858 _cupsMessageLoad(const char *filename
, /* I - Message catalog to load */
859 int unquote
) /* I - Unescape \foo in strings */
861 cups_file_t
*fp
; /* Message file */
862 cups_array_t
*a
; /* Message array */
863 _cups_message_t
*m
; /* Current message */
864 char s
[4096], /* String buffer */
865 *ptr
, /* Pointer into buffer */
866 *temp
; /* New string */
867 int length
; /* Length of combined strings */
870 DEBUG_printf(("4_cupsMessageLoad(filename=\"%s\")", filename
));
873 * Create an array to hold the messages...
876 if ((a
= cupsArrayNew((cups_array_func_t
)cups_message_compare
, NULL
)) == NULL
)
878 DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!");
883 * Open the message catalog file...
886 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
888 DEBUG_printf(("5_cupsMessageLoad: Unable to open file: %s",
894 * Read messages from the catalog file until EOF...
896 * The format is the GNU gettext .po format, which is fairly simple:
899 * msgstr "localized text"
901 * The ID and localized text can span multiple lines using the form:
906 * "localized text spanning "
912 while (cupsFileGets(fp
, s
, sizeof(s
)) != NULL
)
915 * Skip blank and comment lines...
918 if (s
[0] == '#' || !s
[0])
922 * Strip the trailing quote...
925 if ((ptr
= strrchr(s
, '\"')) == NULL
)
931 * Find start of value...
934 if ((ptr
= strchr(s
, '\"')) == NULL
)
940 * Unquote the text...
944 cups_unquote(ptr
, ptr
);
947 * Create or add to a message...
950 if (!strncmp(s
, "msgid", 5))
953 * Add previous message as needed...
960 * Create a new message with the given msgid string...
963 if ((m
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
969 if ((m
->id
= strdup(ptr
)) == NULL
)
976 else if (s
[0] == '\"' && m
)
979 * Append to current string...
982 length
= (int)strlen(m
->str
? m
->str
: m
->id
);
984 if ((temp
= realloc(m
->str
? m
->str
: m
->id
,
985 length
+ strlen(ptr
) + 1)) == NULL
)
994 * Copy the new portion to the end of the msgstr string - safe
995 * to use strcpy because the buffer is allocated to the correct
1001 strcpy(m
->str
+ length
, ptr
);
1006 * Copy the new portion to the end of the msgid string - safe
1007 * to use strcpy because the buffer is allocated to the correct
1013 strcpy(m
->id
+ length
, ptr
);
1016 else if (!strncmp(s
, "msgstr", 6) && m
)
1022 if ((m
->str
= strdup(ptr
)) == NULL
)
1031 * Add the last message string to the array as needed...
1038 * Close the message catalog file and return the new array...
1043 DEBUG_printf(("5_cupsMessageLoad: Returning %d messages...",
1044 cupsArrayCount(a
)));
1051 * '_cupsMessageLookup()' - Lookup a message string.
1054 const char * /* O - Localized message */
1055 _cupsMessageLookup(cups_array_t
*a
, /* I - Message array */
1056 const char *m
) /* I - Message */
1058 _cups_message_t key
, /* Search key */
1059 *match
; /* Matching message */
1063 * Lookup the message string; if it doesn't exist in the catalog,
1064 * then return the message that was passed to us...
1068 match
= (_cups_message_t
*)cupsArrayFind(a
, &key
);
1070 if (match
&& match
->str
)
1071 return (match
->str
);
1079 * 'appleLangDefault()' - Get the default locale string.
1082 static const char * /* O - Locale string */
1083 appleLangDefault(void)
1085 int i
; /* Looping var */
1086 CFBundleRef bundle
; /* Main bundle (if any) */
1087 CFArrayRef bundleList
; /* List of localizations in bundle */
1088 CFPropertyListRef localizationList
;
1089 /* List of localization data */
1090 CFStringRef languageName
; /* Current name */
1091 CFStringRef localeName
; /* Canonical from of name */
1092 char *lang
; /* LANG environment variable */
1093 _cups_globals_t
*cg
= _cupsGlobals();
1094 /* Pointer to library globals */
1097 DEBUG_puts("2appleLangDefault()");
1100 * Only do the lookup and translation the first time.
1103 if (!cg
->language
[0])
1105 if (getenv("SOFTWARE") != NULL
&& (lang
= getenv("LANG")) != NULL
)
1107 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1108 return (cg
->language
);
1110 else if ((bundle
= CFBundleGetMainBundle()) != NULL
&&
1111 (bundleList
= CFBundleCopyBundleLocalizations(bundle
)) != NULL
)
1114 CFBundleCopyPreferredLocalizationsFromArray(bundleList
);
1116 CFRelease(bundleList
);
1120 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1121 kCFPreferencesCurrentApplication
);
1123 if (localizationList
)
1125 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1126 CFArrayGetCount(localizationList
) > 0)
1128 languageName
= CFArrayGetValueAtIndex(localizationList
, 0);
1131 CFGetTypeID(languageName
) == CFStringGetTypeID())
1133 localeName
= CFLocaleCreateCanonicalLocaleIdentifierFromString(
1134 kCFAllocatorDefault
, languageName
);
1138 CFStringGetCString(localeName
, cg
->language
, sizeof(cg
->language
),
1139 kCFStringEncodingASCII
);
1140 CFRelease(localeName
);
1142 DEBUG_printf(("9appleLangDefault: cg->language=\"%s\"",
1146 * Map new language identifiers to locales...
1150 i
< (int)(sizeof(apple_language_locale
) /
1151 sizeof(apple_language_locale
[0]));
1154 if (!strcmp(cg
->language
, apple_language_locale
[i
].language
))
1156 DEBUG_printf(("9appleLangDefault: mapping \"%s\" to \"%s\"...",
1157 cg
->language
, apple_language_locale
[i
].locale
));
1158 strlcpy(cg
->language
, apple_language_locale
[i
].locale
,
1159 sizeof(cg
->language
));
1165 * Convert language subtag into region subtag...
1168 if (cg
->language
[2] == '-')
1169 cg
->language
[2] = '_';
1171 if (!strchr(cg
->language
, '.'))
1172 strlcat(cg
->language
, ".UTF-8", sizeof(cg
->language
));
1177 CFRelease(localizationList
);
1181 * If we didn't find the language, default to en_US...
1184 if (!cg
->language
[0])
1185 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1189 * Return the cached locale...
1192 return (cg
->language
);
1194 #endif /* __APPLE__ */
1198 * 'cups_cache_lookup()' - Lookup a language in the cache...
1201 static cups_lang_t
* /* O - Language data or NULL */
1202 cups_cache_lookup(const char *name
,/* I - Name of locale */
1203 cups_encoding_t encoding
)
1204 /* I - Encoding of locale */
1206 cups_lang_t
*lang
; /* Current language */
1209 DEBUG_printf(("7cups_cache_lookup(name=\"%s\", encoding=%d(%s))", name
,
1210 encoding
, encoding
== CUPS_AUTO_ENCODING
? "auto" :
1211 lang_encodings
[encoding
]));
1214 * Loop through the cache and return a match if found...
1217 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
1219 DEBUG_printf(("9cups_cache_lookup: lang=%p, language=\"%s\", "
1220 "encoding=%d(%s)", lang
, lang
->language
, lang
->encoding
,
1221 lang_encodings
[lang
->encoding
]));
1223 if (!strcmp(lang
->language
, name
) &&
1224 (encoding
== CUPS_AUTO_ENCODING
|| encoding
== lang
->encoding
))
1228 DEBUG_puts("8cups_cache_lookup: returning match!");
1234 DEBUG_puts("8cups_cache_lookup: returning NULL!");
1241 * 'cups_message_compare()' - Compare two messages.
1244 static int /* O - Result of comparison */
1245 cups_message_compare(
1246 _cups_message_t
*m1
, /* I - First message */
1247 _cups_message_t
*m2
) /* I - Second message */
1249 return (strcmp(m1
->id
, m2
->id
));
1254 * 'cups_unquote()' - Unquote characters in strings...
1258 cups_unquote(char *d
, /* O - Unquoted string */
1259 const char *s
) /* I - Original string */
1272 *d
= *d
* 8 + *s
- '0';
1301 * End of "$Id: language.c 7558 2008-05-12 23:46:44Z mike $".