2 * "$Id: language.c 6917 2007-09-05 21:14:17Z mike $"
4 * I18N/language support for the Common UNIX Printing System (CUPS).
6 * Copyright 2007 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 * _cupsEncodingName() - Return the character encoding name string
20 * for the given encoding enumeration.
21 * cupsLangDefault() - Return the default language.
22 * cupsLangEncoding() - Return the character encoding (us-ascii, etc.)
23 * for the given language.
24 * cupsLangFlush() - Flush all language data out of the cache.
25 * cupsLangFree() - Free language data.
26 * cupsLangGet() - Get a language.
27 * _cupsLangString() - Get a message string.
28 * _cupsMessageFree() - Free a messages array.
29 * _cupsMessageLoad() - Load a .po file into a messages array.
30 * _cupsMessageLookup() - Lookup a message string.
31 * appleLangDefault() - Get the default locale string.
32 * cups_cache_lookup() - Lookup a language in the cache...
33 * cups_message_compare() - Compare two messages.
34 * cups_unquote() - Unquote characters in strings...
38 * Include necessary headers...
45 #ifdef HAVE_LANGINFO_H
46 # include <langinfo.h>
47 #endif /* HAVE_LANGINFO_H */
53 #ifdef HAVE_COREFOUNDATION_H
54 # include <CoreFoundation/CoreFoundation.h>
55 #endif /* HAVE_COREFOUNDATION_H */
63 static pthread_mutex_t lang_mutex
= PTHREAD_MUTEX_INITIALIZER
;
64 /* Mutex to control access to cache */
65 #endif /* HAVE_PTHREAD_H */
66 static cups_lang_t
*lang_cache
= NULL
;
67 /* Language string cache */
75 static const char *appleLangDefault(void);
76 #endif /* __APPLE__ */
77 static cups_lang_t
*cups_cache_lookup(const char *name
,
78 cups_encoding_t encoding
);
79 static int cups_message_compare(_cups_message_t
*m1
,
81 static void cups_unquote(char *d
, const char *s
);
88 static const char * const lang_encodings
[] =
89 { /* Encoding strings */
90 "us-ascii", "iso-8859-1",
91 "iso-8859-2", "iso-8859-3",
92 "iso-8859-4", "iso-8859-5",
93 "iso-8859-6", "iso-8859-7",
94 "iso-8859-8", "iso-8859-9",
95 "iso-8859-10", "utf-8",
96 "iso-8859-13", "iso-8859-14",
97 "iso-8859-15", "windows-874",
98 "windows-1250", "windows-1251",
99 "windows-1252", "windows-1253",
100 "windows-1254", "windows-1255",
101 "windows-1256", "windows-1257",
102 "windows-1258", "koi8-r",
103 "koi8-u", "iso-8859-11",
104 "iso-8859-16", "mac-roman",
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 "windows-932", "windows-936",
123 "windows-949", "windows-950",
124 "windows-1361", "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",
136 "unknown", "unknown",
137 "unknown", "unknown",
138 "unknown", "unknown",
139 "unknown", "unknown",
140 "unknown", "unknown",
141 "unknown", "unknown",
142 "unknown", "unknown",
143 "unknown", "unknown",
144 "unknown", "unknown",
145 "unknown", "unknown",
146 "unknown", "unknown",
147 "unknown", "unknown",
148 "unknown", "unknown",
149 "unknown", "unknown",
150 "unknown", "unknown",
151 "unknown", "unknown",
152 "unknown", "unknown",
153 "unknown", "unknown",
160 * '_cupsEncodingName()' - Return the character encoding name string
161 * for the given encoding enumeration.
164 const char * /* O - Character encoding */
166 cups_encoding_t encoding
) /* I - Encoding value */
169 encoding
>= (sizeof(lang_encodings
) / sizeof(const char *)))
170 return (lang_encodings
[0]);
172 return (lang_encodings
[encoding
]);
177 * 'cupsLangDefault()' - Return the default language.
180 cups_lang_t
* /* O - Language data */
181 cupsLangDefault(void)
183 return (cupsLangGet(NULL
));
188 * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
189 * for the given language.
192 const char * /* O - Character encoding */
193 cupsLangEncoding(cups_lang_t
*lang
) /* I - Language data */
196 return ((char*)lang_encodings
[0]);
198 return ((char*)lang_encodings
[lang
->encoding
]);
203 * 'cupsLangFlush()' - Flush all language data out of the cache.
209 cups_lang_t
*lang
, /* Current language */
210 *next
; /* Next language */
214 * Free all languages in the cache...
217 #ifdef HAVE_PTHREAD_H
218 pthread_mutex_lock(&lang_mutex
);
219 #endif /* HAVE_PTHREAD_H */
221 for (lang
= lang_cache
; lang
!= NULL
; lang
= next
)
224 * Free all messages...
227 _cupsMessageFree(lang
->strings
);
230 * Then free the language structure itself...
239 #ifdef HAVE_PTHREAD_H
240 pthread_mutex_unlock(&lang_mutex
);
241 #endif /* HAVE_PTHREAD_H */
246 * 'cupsLangFree()' - Free language data.
248 * This does not actually free anything; use cupsLangFlush() for that.
252 cupsLangFree(cups_lang_t
*lang
) /* I - Language to free */
254 #ifdef HAVE_PTHREAD_H
255 pthread_mutex_lock(&lang_mutex
);
256 #endif /* HAVE_PTHREAD_H */
258 if (lang
!= NULL
&& lang
->used
> 0)
261 #ifdef HAVE_PTHREAD_H
262 pthread_mutex_unlock(&lang_mutex
);
263 #endif /* HAVE_PTHREAD_H */
268 * 'cupsLangGet()' - Get a language.
271 cups_lang_t
* /* O - Language data */
272 cupsLangGet(const char *language
) /* I - Language or locale */
274 int i
; /* Looping var */
276 char locale
[255]; /* Copy of locale name */
277 #endif /* !__APPLE__ */
278 char langname
[16], /* Requested language name */
279 country
[16], /* Country code */
280 charset
[16], /* Character set */
281 *csptr
, /* Pointer to CODESET string */
282 *ptr
, /* Pointer into language/charset */
283 real
[48], /* Real language name */
284 filename
[1024]; /* Filename for language locale file */
285 cups_encoding_t encoding
; /* Encoding to use */
286 cups_lang_t
*lang
; /* Current language... */
287 _cups_globals_t
*cg
= _cupsGlobals();
288 /* Pointer to library globals */
289 static const char * const locale_encodings
[] =
290 { /* Locale charset names */
291 "ASCII", "ISO88591", "ISO88592", "ISO88593",
292 "ISO88594", "ISO88595", "ISO88596", "ISO88597",
293 "ISO88598", "ISO88599", "ISO885910", "UTF8",
294 "ISO885913", "ISO885914", "ISO885915", "CP874",
295 "CP1250", "CP1251", "CP1252", "CP1253",
296 "CP1254", "CP1255", "CP1256", "CP1257",
297 "CP1258", "KOI8R", "KOI8U", "ISO885911",
298 "ISO885916", "MACROMAN", "", "",
309 "CP932", "CP936", "CP949", "CP950",
310 "CP1361", "", "", "",
327 "EUCCN", "EUCJP", "EUCKR", "EUCTW"
331 DEBUG_printf(("cupsLangGet(language=\"%s\")\n", language
? language
: "(null)"));
335 * Set the character set to UTF-8...
338 strcpy(charset
, "UTF8");
341 * Apple's setlocale doesn't give us the user's localization
342 * preference so we have to look it up this way...
345 if (!language
&& (language
= getenv("LANG")) == NULL
)
346 language
= appleLangDefault();
350 * Set the charset to "unknown"...
356 * Use setlocale() to determine the currently set locale, and then
357 * fallback to environment variables to avoid setting the locale,
358 * since setlocale() is not thread-safe!
364 * First see if the locale has been set; if it is still "C" or
365 * "POSIX", use the environment to get the default...
369 ptr
= setlocale(LC_MESSAGES
, NULL
);
371 ptr
= setlocale(LC_ALL
, NULL
);
372 # endif /* LC_MESSAGES */
374 DEBUG_printf(("cupsLangGet: current locale is \"%s\"\n",
375 ptr
? ptr
: "(null)"));
377 if (!ptr
|| !strcmp(ptr
, "C") || !strcmp(ptr
, "POSIX"))
380 * Get the character set from the LC_CTYPE locale setting...
383 if ((ptr
= getenv("LC_CTYPE")) == NULL
)
384 if ((ptr
= getenv("LC_ALL")) == NULL
)
385 if ((ptr
= getenv("LANG")) == NULL
)
388 if ((csptr
= strchr(ptr
, '.')) != NULL
)
391 * Extract the character set from the environment...
394 for (ptr
= charset
, csptr
++; *csptr
; csptr
++)
395 if (ptr
< (charset
+ sizeof(charset
) - 1) && isalnum(*csptr
& 255))
402 * Get the locale for messages from the LC_MESSAGES locale setting...
405 if ((ptr
= getenv("LC_MESSAGES")) == NULL
)
406 if ((ptr
= getenv("LC_ALL")) == NULL
)
407 if ((ptr
= getenv("LANG")) == NULL
)
413 strlcpy(locale
, ptr
, sizeof(locale
));
416 DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n",
417 language
? language
: "(null)"));
420 #endif /* __APPLE__ */
423 * If "language" is NULL at this point, then chances are we are using
424 * a language that is not installed for the base OS.
430 * Switch to the POSIX ("C") locale...
438 * On systems that support the nl_langinfo(CODESET) call, use
439 * this value as the character set...
442 if (!charset
[0] && (csptr
= nl_langinfo(CODESET
)) != NULL
)
445 * Copy all of the letters and numbers in the CODESET string...
448 for (ptr
= charset
; *csptr
; csptr
++)
449 if (isalnum(*csptr
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
454 DEBUG_printf(("cupsLangGet: charset set to \"%s\" via nl_langinfo(CODESET)...\n",
460 * If we don't have a character set by now, default to UTF-8...
464 strcpy(charset
, "UTF8");
467 * Parse the language string passed in to a locale string. "C" is the
468 * standard POSIX locale and is copied unchanged. Otherwise the
469 * language string is converted from ll-cc[.charset] (language-country)
470 * to ll_CC[.CHARSET] to match the file naming convention used by all
471 * POSIX-compliant operating systems. Invalid language names are mapped
472 * to the POSIX locale.
477 if (language
== NULL
|| !language
[0] ||
478 !strcmp(language
, "POSIX"))
479 strcpy(langname
, "C");
483 * Copy the parts of the locale string over safely...
486 for (ptr
= langname
; *language
; language
++)
487 if (*language
== '_' || *language
== '-' || *language
== '.')
489 else if (ptr
< (langname
+ sizeof(langname
) - 1))
490 *ptr
++ = tolower(*language
& 255);
494 if (*language
== '_' || *language
== '-')
497 * Copy the country code...
500 for (language
++, ptr
= country
; *language
; language
++)
501 if (*language
== '.')
503 else if (ptr
< (country
+ sizeof(country
) - 1))
504 *ptr
++ = toupper(*language
& 255);
509 if (*language
== '.' && !charset
[0])
512 * Copy the encoding...
515 for (language
++, ptr
= charset
; *language
; language
++)
516 if (isalnum(*language
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
517 *ptr
++ = toupper(*language
& 255);
523 * Force a POSIX locale for an invalid language name...
526 if (strlen(langname
) != 2)
528 strcpy(langname
, "C");
534 DEBUG_printf(("cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"\n",
535 langname
, country
, charset
));
538 * Figure out the desired encoding...
541 encoding
= CUPS_AUTO_ENCODING
;
546 i
< (int)(sizeof(locale_encodings
) / sizeof(locale_encodings
[0]));
548 if (!strcasecmp(charset
, locale_encodings
[i
]))
550 encoding
= (cups_encoding_t
)i
;
554 if (encoding
== CUPS_AUTO_ENCODING
)
557 * Map alternate names for various character sets...
560 if (!strcasecmp(charset
, "iso-2022-jp") ||
561 !strcasecmp(charset
, "sjis"))
562 encoding
= CUPS_WINDOWS_932
;
563 else if (!strcasecmp(charset
, "iso-2022-cn"))
564 encoding
= CUPS_WINDOWS_936
;
565 else if (!strcasecmp(charset
, "iso-2022-kr"))
566 encoding
= CUPS_WINDOWS_949
;
567 else if (!strcasecmp(charset
, "big5"))
568 encoding
= CUPS_WINDOWS_950
;
572 DEBUG_printf(("cupsLangGet: encoding=%d(%s)\n", encoding
,
573 encoding
== CUPS_AUTO_ENCODING
? "auto" :
574 lang_encodings
[encoding
]));
577 * See if we already have this language/country loaded...
582 snprintf(real
, sizeof(real
), "%s_%s", langname
, country
);
584 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
589 strcpy(real
, langname
);
590 filename
[0] = '\0'; /* anti-compiler-warning-code */
593 #ifdef HAVE_PTHREAD_H
594 pthread_mutex_lock(&lang_mutex
);
595 #endif /* HAVE_PTHREAD_H */
597 if ((lang
= cups_cache_lookup(real
, encoding
)) != NULL
)
599 #ifdef HAVE_PTHREAD_H
600 pthread_mutex_unlock(&lang_mutex
);
601 #endif /* HAVE_PTHREAD_H */
606 if (!country
[0] || access(filename
, 0))
609 * Country localization not available, look for generic localization...
612 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
615 if (access(filename
, 0))
618 * No generic localization, so use POSIX...
621 DEBUG_printf(("access(\"%s\", 0): %s\n", filename
, strerror(errno
)));
623 snprintf(filename
, sizeof(filename
), "%s/C/cups_C.po", cg
->localedir
);
628 * See if there is a free language available; if so, use that
632 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
639 * Allocate memory for the language and add it to the cache.
642 if ((lang
= calloc(sizeof(cups_lang_t
), 1)) == NULL
)
644 #ifdef HAVE_PTHREAD_H
645 pthread_mutex_unlock(&lang_mutex
);
646 #endif /* HAVE_PTHREAD_H */
651 lang
->next
= lang_cache
;
657 * Free all old strings as needed...
660 _cupsMessageFree(lang
->strings
);
664 * Then assign the language and encoding fields...
668 strlcpy(lang
->language
, real
, sizeof(lang
->language
));
670 if (encoding
!= CUPS_AUTO_ENCODING
)
671 lang
->encoding
= encoding
;
673 lang
->encoding
= CUPS_UTF8
;
676 * Read the strings from the file...
679 lang
->strings
= _cupsMessageLoad(filename
);
685 #ifdef HAVE_PTHREAD_H
686 pthread_mutex_unlock(&lang_mutex
);
687 #endif /* HAVE_PTHREAD_H */
694 * '_cupsLangString()' - Get a message string.
696 * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
697 * convert the string to the language encoding.
700 const char * /* O - Localized message */
701 _cupsLangString(cups_lang_t
*lang
, /* I - Language */
702 const char *message
) /* I - Message */
705 * Range check input...
708 if (!lang
|| !message
)
711 #ifdef HAVE_PTHREAD_H
713 const char *s
; /* Localized message */
715 pthread_mutex_lock(&lang_mutex
);
717 s
= _cupsMessageLookup(lang
->strings
, message
);
719 pthread_mutex_unlock(&lang_mutex
);
724 return (_cupsMessageLookup(lang
->strings
, message
));
725 #endif /* HAVE_PTHREAD_H */
730 * '_cupsMessageFree()' - Free a messages array.
734 _cupsMessageFree(cups_array_t
*a
) /* I - Message array */
736 _cups_message_t
*m
; /* Current message */
739 for (m
= (_cups_message_t
*)cupsArrayFirst(a
);
741 m
= (_cups_message_t
*)cupsArrayNext(a
))
744 * Remove the message from the array, then free the message and strings.
747 cupsArrayRemove(a
, m
);
767 * '_cupsMessageLoad()' - Load a .po file into a messages array.
770 cups_array_t
* /* O - New message array */
771 _cupsMessageLoad(const char *filename
) /* I - Message catalog to load */
773 cups_file_t
*fp
; /* Message file */
774 cups_array_t
*a
; /* Message array */
775 _cups_message_t
*m
; /* Current message */
776 char s
[4096], /* String buffer */
777 *ptr
, /* Pointer into buffer */
778 *temp
; /* New string */
779 int length
; /* Length of combined strings */
782 DEBUG_printf(("_cupsMessageLoad(filename=\"%s\")\n", filename
));
785 * Create an array to hold the messages...
788 if ((a
= cupsArrayNew((cups_array_func_t
)cups_message_compare
, NULL
)) == NULL
)
792 * Open the message catalog file...
795 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
799 * Read messages from the catalog file until EOF...
801 * The format is the GNU gettext .po format, which is fairly simple:
804 * msgstr "localized text"
806 * The ID and localized text can span multiple lines using the form:
811 * "localized text spanning "
817 while (cupsFileGets(fp
, s
, sizeof(s
)) != NULL
)
820 * Skip blank and comment lines...
823 if (s
[0] == '#' || !s
[0])
827 * Strip the trailing quote...
830 if ((ptr
= strrchr(s
, '\"')) == NULL
)
836 * Find start of value...
839 if ((ptr
= strchr(s
, '\"')) == NULL
)
845 * Unquote the text...
848 cups_unquote(ptr
, ptr
);
851 * Create or add to a message...
854 if (!strncmp(s
, "msgid", 5))
857 * Add previous message as needed...
864 * Create a new message with the given msgid string...
867 if ((m
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
875 else if (s
[0] == '\"' && m
)
878 * Append to current string...
881 length
= (int)strlen(m
->str
? m
->str
: m
->id
);
883 if ((temp
= realloc(m
->str
? m
->str
: m
->id
,
884 length
+ strlen(ptr
) + 1)) == NULL
)
893 * Copy the new portion to the end of the msgstr string - safe
894 * to use strcpy because the buffer is allocated to the correct
900 strcpy(m
->str
+ length
, ptr
);
905 * Copy the new portion to the end of the msgid string - safe
906 * to use strcpy because the buffer is allocated to the correct
912 strcpy(m
->id
+ length
, ptr
);
915 else if (!strncmp(s
, "msgstr", 6) && m
)
921 m
->str
= strdup(ptr
);
926 * Add the last message string to the array as needed...
933 * Close the message catalog file and return the new array...
943 * '_cupsMessageLookup()' - Lookup a message string.
946 const char * /* O - Localized message */
947 _cupsMessageLookup(cups_array_t
*a
, /* I - Message array */
948 const char *m
) /* I - Message */
950 _cups_message_t key
, /* Search key */
951 *match
; /* Matching message */
955 * Lookup the message string; if it doesn't exist in the catalog,
956 * then return the message that was passed to us...
960 match
= (_cups_message_t
*)cupsArrayFind(a
, &key
);
962 if (match
&& match
->str
)
971 * Code & data to translate OSX's language names to their ISO 639-1 locale.
973 * The first version uses the new CoreFoundation API added in 10.3 (Panther),
974 * the second is for 10.2 (Jaguar).
977 # ifdef HAVE_CF_LOCALE_ID
981 const char * const name
; /* Language name */
982 const char * const locale
; /* Locale name */
983 } _apple_name_locale_t
;
985 static const _apple_name_locale_t apple_name_locale
[] =
989 { "zh-Hans" , "zh_CN" },
990 { "zh-Hant" , "zh_TW" }
995 * 'appleLangDefault()' - Get the default locale string.
998 static const char * /* O - Locale string */
999 appleLangDefault(void)
1001 int i
; /* Looping var */
1002 CFBundleRef bundle
; /* Main bundle (if any) */
1003 CFArrayRef bundleList
; /* List of localizations in bundle */
1004 CFPropertyListRef localizationList
;
1005 /* List of localization data */
1006 CFStringRef languageName
; /* Current name */
1007 CFStringRef localeName
; /* Canonical from of name */
1008 char *lang
; /* LANG environment variable */
1009 _cups_globals_t
*cg
= _cupsGlobals();
1010 /* Pointer to library globals */
1014 * Only do the lookup and translation the first time.
1017 if (!cg
->language
[0])
1019 if ((lang
= getenv("LANG")))
1021 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1022 return (cg
->language
);
1024 else if ((bundle
= CFBundleGetMainBundle()) != NULL
&&
1025 (bundleList
= CFBundleCopyBundleLocalizations(bundle
)) != NULL
)
1028 CFBundleCopyPreferredLocalizationsFromArray(bundleList
);
1030 CFRelease(bundleList
);
1034 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1035 kCFPreferencesCurrentApplication
);
1037 if (localizationList
)
1039 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1040 CFArrayGetCount(localizationList
) > 0)
1042 languageName
= CFArrayGetValueAtIndex(localizationList
, 0);
1045 CFGetTypeID(languageName
) == CFStringGetTypeID())
1047 localeName
= CFLocaleCreateCanonicalLocaleIdentifierFromString(
1048 kCFAllocatorDefault
, languageName
);
1052 CFStringGetCString(localeName
, cg
->language
, sizeof(cg
->language
),
1053 kCFStringEncodingASCII
);
1054 CFRelease(localeName
);
1056 DEBUG_printf(("appleLangDefault: cg->language=\"%s\"\n",
1060 * Map new language identifiers to locales...
1064 i
< sizeof(apple_name_locale
) / sizeof(apple_name_locale
[0]);
1067 if (!strcmp(cg
->language
, apple_name_locale
[i
].name
))
1069 DEBUG_printf(("appleLangDefault: mapping \"%s\" to \"%s\"...\n",
1070 cg
->language
, apple_name_locale
[i
].locale
));
1071 strlcpy(cg
->language
, apple_name_locale
[i
].locale
,
1072 sizeof(cg
->language
));
1078 * Convert language subtag into region subtag...
1081 if (cg
->language
[2] == '-')
1082 cg
->language
[2] = '_';
1084 if (!strchr(cg
->language
, '.'))
1085 strlcat(cg
->language
, ".UTF-8", sizeof(cg
->language
));
1090 CFRelease(localizationList
);
1094 * If we didn't find the language, default to en_US...
1097 if (!cg
->language
[0])
1098 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1102 * Return the cached locale...
1105 return (cg
->language
);
1109 * Code & data to translate OSX 10.2's language names to their ISO 639-1
1115 const char * const name
; /* Language name */
1116 const char * const locale
; /* Locale name */
1117 } _apple_name_locale_t
;
1119 static const _apple_name_locale_t apple_name_locale
[] =
1121 { "English" , "en_US.UTF-8" }, { "French" , "fr.UTF-8" },
1122 { "German" , "de.UTF-8" }, { "Italian" , "it.UTF-8" },
1123 { "Dutch" , "nl.UTF-8" }, { "Swedish" , "sv.UTF-8" },
1124 { "Spanish" , "es.UTF-8" }, { "Danish" , "da.UTF-8" },
1125 { "Portuguese" , "pt.UTF-8" }, { "Norwegian" , "no.UTF-8" },
1126 { "Hebrew" , "he.UTF-8" }, { "Japanese" , "ja.UTF-8" },
1127 { "Arabic" , "ar.UTF-8" }, { "Finnish" , "fi.UTF-8" },
1128 { "Greek" , "el.UTF-8" }, { "Icelandic" , "is.UTF-8" },
1129 { "Maltese" , "mt.UTF-8" }, { "Turkish" , "tr.UTF-8" },
1130 { "Croatian" , "hr.UTF-8" }, { "Chinese" , "zh.UTF-8" },
1131 { "Urdu" , "ur.UTF-8" }, { "Hindi" , "hi.UTF-8" },
1132 { "Thai" , "th.UTF-8" }, { "Korean" , "ko.UTF-8" },
1133 { "Lithuanian" , "lt.UTF-8" }, { "Polish" , "pl.UTF-8" },
1134 { "Hungarian" , "hu.UTF-8" }, { "Estonian" , "et.UTF-8" },
1135 { "Latvian" , "lv.UTF-8" }, { "Sami" , "se.UTF-8" },
1136 { "Faroese" , "fo.UTF-8" }, { "Farsi" , "fa.UTF-8" },
1137 { "Russian" , "ru.UTF-8" }, { "Chinese" , "zh.UTF-8" },
1138 { "Dutch" , "nl.UTF-8" }, { "Irish" , "ga.UTF-8" },
1139 { "Albanian" , "sq.UTF-8" }, { "Romanian" , "ro.UTF-8" },
1140 { "Czech" , "cs.UTF-8" }, { "Slovak" , "sk.UTF-8" },
1141 { "Slovenian" , "sl.UTF-8" }, { "Yiddish" , "yi.UTF-8" },
1142 { "Serbian" , "sr.UTF-8" }, { "Macedonian" , "mk.UTF-8" },
1143 { "Bulgarian" , "bg.UTF-8" }, { "Ukrainian" , "uk.UTF-8" },
1144 { "Byelorussian", "be.UTF-8" }, { "Uzbek" , "uz.UTF-8" },
1145 { "Kazakh" , "kk.UTF-8" }, { "Azerbaijani", "az.UTF-8" },
1146 { "Azerbaijani" , "az.UTF-8" }, { "Armenian" , "hy.UTF-8" },
1147 { "Georgian" , "ka.UTF-8" }, { "Moldavian" , "mo.UTF-8" },
1148 { "Kirghiz" , "ky.UTF-8" }, { "Tajiki" , "tg.UTF-8" },
1149 { "Turkmen" , "tk.UTF-8" }, { "Mongolian" , "mn.UTF-8" },
1150 { "Mongolian" , "mn.UTF-8" }, { "Pashto" , "ps.UTF-8" },
1151 { "Kurdish" , "ku.UTF-8" }, { "Kashmiri" , "ks.UTF-8" },
1152 { "Sindhi" , "sd.UTF-8" }, { "Tibetan" , "bo.UTF-8" },
1153 { "Nepali" , "ne.UTF-8" }, { "Sanskrit" , "sa.UTF-8" },
1154 { "Marathi" , "mr.UTF-8" }, { "Bengali" , "bn.UTF-8" },
1155 { "Assamese" , "as.UTF-8" }, { "Gujarati" , "gu.UTF-8" },
1156 { "Punjabi" , "pa.UTF-8" }, { "Oriya" , "or.UTF-8" },
1157 { "Malayalam" , "ml.UTF-8" }, { "Kannada" , "kn.UTF-8" },
1158 { "Tamil" , "ta.UTF-8" }, { "Telugu" , "te.UTF-8" },
1159 { "Sinhalese" , "si.UTF-8" }, { "Burmese" , "my.UTF-8" },
1160 { "Khmer" , "km.UTF-8" }, { "Lao" , "lo.UTF-8" },
1161 { "Vietnamese" , "vi.UTF-8" }, { "Indonesian" , "id.UTF-8" },
1162 { "Tagalog" , "tl.UTF-8" }, { "Malay" , "ms.UTF-8" },
1163 { "Malay" , "ms.UTF-8" }, { "Amharic" , "am.UTF-8" },
1164 { "Tigrinya" , "ti.UTF-8" }, { "Oromo" , "om.UTF-8" },
1165 { "Somali" , "so.UTF-8" }, { "Swahili" , "sw.UTF-8" },
1166 { "Kinyarwanda" , "rw.UTF-8" }, { "Rundi" , "rn.UTF-8" },
1167 { "Nyanja" , "" }, { "Malagasy" , "mg.UTF-8" },
1168 { "Esperanto" , "eo.UTF-8" }, { "Welsh" , "cy.UTF-8" },
1169 { "Basque" , "eu.UTF-8" }, { "Catalan" , "ca.UTF-8" },
1170 { "Latin" , "la.UTF-8" }, { "Quechua" , "qu.UTF-8" },
1171 { "Guarani" , "gn.UTF-8" }, { "Aymara" , "ay.UTF-8" },
1172 { "Tatar" , "tt.UTF-8" }, { "Uighur" , "ug.UTF-8" },
1173 { "Dzongkha" , "dz.UTF-8" }, { "Javanese" , "jv.UTF-8" },
1174 { "Sundanese" , "su.UTF-8" }, { "Galician" , "gl.UTF-8" },
1175 { "Afrikaans" , "af.UTF-8" }, { "Breton" , "br.UTF-8" },
1176 { "Inuktitut" , "iu.UTF-8" }, { "Scottish" , "gd.UTF-8" },
1177 { "Manx" , "gv.UTF-8" }, { "Irish" , "ga.UTF-8" },
1178 { "Tongan" , "to.UTF-8" }, { "Greek" , "el.UTF-8" },
1179 { "Greenlandic" , "kl.UTF-8" }, { "Azerbaijani", "az.UTF-8" }
1184 * 'appleLangDefault()' - Get the default locale string.
1187 static const char * /* O - Locale string */
1188 appleLangDefault(void)
1190 int i
; /* Looping var */
1191 CFPropertyListRef localizationList
;
1192 /* List of localization data */
1193 CFStringRef localizationName
;
1195 char buff
[256]; /* Temporary buffer */
1196 _cups_globals_t
*cg
= _cupsGlobals();
1197 /* Pointer to library globals */
1198 char *lang
; /* LANG environment variable */
1202 * Only do the lookup and translation the first time.
1205 if (!cg
->language
[0])
1207 if ((lang
= getenv("LANG")))
1208 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1212 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1213 kCFPreferencesCurrentApplication
);
1215 if (localizationList
!= NULL
)
1217 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1218 CFArrayGetCount(localizationList
) > 0)
1220 localizationName
= CFArrayGetValueAtIndex(localizationList
, 0);
1222 if (localizationName
!= NULL
&&
1223 CFGetTypeID(localizationName
) == CFStringGetTypeID())
1225 CFIndex length
= CFStringGetLength(localizationName
);
1227 if (length
<= sizeof(buff
) &&
1228 CFStringGetCString(localizationName
, buff
, sizeof(buff
),
1229 kCFStringEncodingASCII
))
1231 buff
[sizeof(buff
) - 1] = '\0';
1234 i
< sizeof(apple_name_locale
) / sizeof(apple_name_locale
[0]);
1237 if (!strcasecmp(buff
, apple_name_locale
[i
].name
))
1239 strlcpy(cg
->language
, apple_name_locale
[i
].locale
,
1240 sizeof(cg
->language
));
1248 CFRelease(localizationList
);
1253 * If we didn't find the language, default to en_US...
1256 if (!cg
->language
[0])
1257 strlcpy(cg
->language
, apple_name_locale
[0].locale
, sizeof(cg
->language
));
1261 * Return the cached locale...
1264 return (cg
->language
);
1266 # endif /* HAVE_CF_LOCALE_ID */
1267 #endif /* __APPLE__ */
1271 * 'cups_cache_lookup()' - Lookup a language in the cache...
1274 static cups_lang_t
* /* O - Language data or NULL */
1275 cups_cache_lookup(const char *name
,/* I - Name of locale */
1276 cups_encoding_t encoding
)
1277 /* I - Encoding of locale */
1279 cups_lang_t
*lang
; /* Current language */
1282 DEBUG_printf(("cups_cache_lookup(name=\"%s\", encoding=%d(%s))\n", name
,
1283 encoding
, encoding
== CUPS_AUTO_ENCODING
? "auto" :
1284 lang_encodings
[encoding
]));
1287 * Loop through the cache and return a match if found...
1290 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
1292 DEBUG_printf(("cups_cache_lookup: lang=%p, language=\"%s\", encoding=%d(%s)\n",
1293 lang
, lang
->language
, lang
->encoding
,
1294 lang_encodings
[lang
->encoding
]));
1296 if (!strcmp(lang
->language
, name
) &&
1297 (encoding
== CUPS_AUTO_ENCODING
|| encoding
== lang
->encoding
))
1301 DEBUG_puts("cups_cache_lookup: returning match!");
1307 DEBUG_puts("cups_cache_lookup: returning NULL!");
1314 * 'cups_message_compare()' - Compare two messages.
1317 static int /* O - Result of comparison */
1318 cups_message_compare(
1319 _cups_message_t
*m1
, /* I - First message */
1320 _cups_message_t
*m2
) /* I - Second message */
1322 return (strcmp(m1
->id
, m2
->id
));
1327 * 'cups_unquote()' - Unquote characters in strings...
1331 cups_unquote(char *d
, /* O - Unquoted string */
1332 const char *s
) /* I - Original string */
1345 *d
= *d
* 8 + *s
- '0';
1374 * End of "$Id: language.c 6917 2007-09-05 21:14:17Z mike $".