2 * "$Id: language.c 6073 2006-11-02 20:01:54Z mike $"
4 * I18N/language support for the Common UNIX Printing System (CUPS).
6 * Copyright 1997-2006 by Easy Software Products.
8 * These coded instructions, statements, and computer programs are the
9 * property of Easy Software Products and are protected by Federal
10 * copyright law. Distribution and use rights are outlined in the file
11 * "LICENSE.txt" which should have been included with this file. If this
12 * file is missing or damaged please contact Easy Software Products
15 * Attn: CUPS Licensing Information
16 * Easy Software Products
17 * 44141 Airport View Drive, Suite 204
18 * Hollywood, Maryland 20636 USA
20 * Voice: (301) 373-9600
21 * EMail: cups-info@cups.org
22 * WWW: http://www.cups.org
24 * This file is subject to the Apple OS-Developed Software exception.
28 * _cupsEncodingName() - Return the character encoding name string
29 * for the given encoding enumeration.
30 * cupsLangDefault() - Return the default language.
31 * cupsLangEncoding() - Return the character encoding (us-ascii, etc.)
32 * for the given language.
33 * cupsLangFlush() - Flush all language data out of the cache.
34 * cupsLangFree() - Free language data.
35 * cupsLangGet() - Get a language.
36 * _cupsLangString() - Get a message string.
37 * _cupsMessageFree() - Free a messages array.
38 * _cupsMessageLoad() - Load a .po file into a messages array.
39 * _cupsMessageLookup() - Lookup a message string.
40 * appleLangDefault() - Get the default locale string.
41 * cups_cache_lookup() - Lookup a language in the cache...
42 * cups_message_compare() - Compare two messages.
43 * cups_unquote() - Unquote characters in strings...
47 * Include necessary headers...
54 #ifdef HAVE_LANGINFO_H
55 # include <langinfo.h>
56 #endif /* HAVE_LANGINFO_H */
62 #ifdef HAVE_COREFOUNDATION_H
63 # include <CoreFoundation/CoreFoundation.h>
64 #endif /* HAVE_COREFOUNDATION_H */
72 static pthread_mutex_t lang_mutex
= PTHREAD_MUTEX_INITIALIZER
;
73 /* Mutex to control access to cache */
74 #endif /* HAVE_PTHREAD_H */
75 static cups_lang_t
*lang_cache
= NULL
;
76 /* Language string cache */
84 static const char *appleLangDefault(void);
85 #endif /* __APPLE__ */
86 static cups_lang_t
*cups_cache_lookup(const char *name
,
87 cups_encoding_t encoding
);
88 static int cups_message_compare(_cups_message_t
*m1
,
90 static void cups_unquote(char *d
, const char *s
);
97 static const char * const lang_encodings
[] =
98 { /* Encoding strings */
99 "us-ascii", "iso-8859-1",
100 "iso-8859-2", "iso-8859-3",
101 "iso-8859-4", "iso-8859-5",
102 "iso-8859-6", "iso-8859-7",
103 "iso-8859-8", "iso-8859-9",
104 "iso-8859-10", "utf-8",
105 "iso-8859-13", "iso-8859-14",
106 "iso-8859-15", "windows-874",
107 "windows-1250", "windows-1251",
108 "windows-1252", "windows-1253",
109 "windows-1254", "windows-1255",
110 "windows-1256", "windows-1257",
111 "windows-1258", "koi8-r",
112 "koi8-u", "iso-8859-11",
113 "iso-8859-16", "mac-roman",
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 "windows-932", "windows-936",
132 "windows-949", "windows-950",
133 "windows-1361", "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",
154 "unknown", "unknown",
155 "unknown", "unknown",
156 "unknown", "unknown",
157 "unknown", "unknown",
158 "unknown", "unknown",
159 "unknown", "unknown",
160 "unknown", "unknown",
161 "unknown", "unknown",
162 "unknown", "unknown",
169 * '_cupsEncodingName()' - Return the character encoding name string
170 * for the given encoding enumeration.
173 const char * /* O - Character encoding */
175 cups_encoding_t encoding
) /* I - Encoding value */
178 encoding
>= (sizeof(lang_encodings
) / sizeof(const char *)))
179 return (lang_encodings
[0]);
181 return (lang_encodings
[encoding
]);
186 * 'cupsLangDefault()' - Return the default language.
189 cups_lang_t
* /* O - Language data */
190 cupsLangDefault(void)
192 return (cupsLangGet(NULL
));
197 * 'cupsLangEncoding()' - Return the character encoding (us-ascii, etc.)
198 * for the given language.
201 const char * /* O - Character encoding */
202 cupsLangEncoding(cups_lang_t
*lang
) /* I - Language data */
205 return ((char*)lang_encodings
[0]);
207 return ((char*)lang_encodings
[lang
->encoding
]);
212 * 'cupsLangFlush()' - Flush all language data out of the cache.
218 cups_lang_t
*lang
, /* Current language */
219 *next
; /* Next language */
223 * Free all languages in the cache...
226 #ifdef HAVE_PTHREAD_H
227 pthread_mutex_lock(&lang_mutex
);
228 #endif /* HAVE_PTHREAD_H */
230 for (lang
= lang_cache
; lang
!= NULL
; lang
= next
)
233 * Free all messages...
236 _cupsMessageFree(lang
->strings
);
239 * Then free the language structure itself...
248 #ifdef HAVE_PTHREAD_H
249 pthread_mutex_unlock(&lang_mutex
);
250 #endif /* HAVE_PTHREAD_H */
255 * 'cupsLangFree()' - Free language data.
257 * This does not actually free anything; use cupsLangFlush() for that.
261 cupsLangFree(cups_lang_t
*lang
) /* I - Language to free */
263 #ifdef HAVE_PTHREAD_H
264 pthread_mutex_lock(&lang_mutex
);
265 #endif /* HAVE_PTHREAD_H */
267 if (lang
!= NULL
&& lang
->used
> 0)
270 #ifdef HAVE_PTHREAD_H
271 pthread_mutex_unlock(&lang_mutex
);
272 #endif /* HAVE_PTHREAD_H */
277 * 'cupsLangGet()' - Get a language.
280 cups_lang_t
* /* O - Language data */
281 cupsLangGet(const char *language
) /* I - Language or locale */
283 int i
; /* Looping var */
285 char locale
[255]; /* Copy of locale name */
286 #endif /* !__APPLE__ */
287 char langname
[16], /* Requested language name */
288 country
[16], /* Country code */
289 charset
[16], /* Character set */
290 *csptr
, /* Pointer to CODESET string */
291 *ptr
, /* Pointer into language/charset */
292 real
[48], /* Real language name */
293 filename
[1024]; /* Filename for language locale file */
294 cups_encoding_t encoding
; /* Encoding to use */
295 cups_lang_t
*lang
; /* Current language... */
296 _cups_globals_t
*cg
= _cupsGlobals();
297 /* Pointer to library globals */
298 static const char * const locale_encodings
[] =
299 { /* Locale charset names */
300 "ASCII", "ISO88591", "ISO88592", "ISO88593",
301 "ISO88594", "ISO88595", "ISO88596", "ISO88597",
302 "ISO88598", "ISO88599", "ISO885910", "UTF8",
303 "ISO885913", "ISO885914", "ISO885915", "CP874",
304 "CP1250", "CP1251", "CP1252", "CP1253",
305 "CP1254", "CP1255", "CP1256", "CP1257",
306 "CP1258", "KOI8R", "KOI8U", "ISO885911",
307 "ISO885916", "MACROMAN", "", "",
318 "CP932", "CP936", "CP949", "CP950",
319 "CP1361", "", "", "",
336 "EUCCN", "EUCJP", "EUCKR", "EUCTW"
340 DEBUG_printf(("cupsLangGet(language=\"%s\")\n", language
? language
: "(null)"));
344 * Set the character set to UTF-8...
347 strcpy(charset
, "UTF8");
350 * Apple's setlocale doesn't give us the user's localization
351 * preference so we have to look it up this way...
355 language
= appleLangDefault();
359 * Set the charset to "unknown"...
365 * Use setlocale() to determine the currently set locale, and then
366 * fallback to environment variables to avoid setting the locale,
367 * since setlocale() is not thread-safe!
373 * First see if the locale has been set; if it is still "C" or
374 * "POSIX", use the environment to get the default...
378 ptr
= setlocale(LC_MESSAGES
, NULL
);
380 ptr
= setlocale(LC_ALL
, NULL
);
381 # endif /* LC_MESSAGES */
383 DEBUG_printf(("cupsLangGet: current locale is \"%s\"\n",
384 ptr
? ptr
: "(null)"));
386 if (!ptr
|| !strcmp(ptr
, "C") || !strcmp(ptr
, "POSIX"))
389 * Get the character set from the LC_CTYPE locale setting...
392 if ((ptr
= getenv("LC_CTYPE")) == NULL
)
393 if ((ptr
= getenv("LC_ALL")) == NULL
)
394 if ((ptr
= getenv("LANG")) == NULL
)
397 if ((csptr
= strchr(ptr
, '.')) != NULL
)
400 * Extract the character set from the environment...
403 for (ptr
= charset
, csptr
++; *csptr
; csptr
++)
404 if (ptr
< (charset
+ sizeof(charset
) - 1) && isalnum(*csptr
& 255))
411 * Get the locale for messages from the LC_MESSAGES locale setting...
414 if ((ptr
= getenv("LC_MESSAGES")) == NULL
)
415 if ((ptr
= getenv("LC_ALL")) == NULL
)
416 if ((ptr
= getenv("LANG")) == NULL
)
422 strlcpy(locale
, ptr
, sizeof(locale
));
425 DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n",
426 language
? language
: "(null)"));
429 #endif /* __APPLE__ */
432 * If "language" is NULL at this point, then chances are we are using
433 * a language that is not installed for the base OS.
439 * Switch to the POSIX ("C") locale...
447 * On systems that support the nl_langinfo(CODESET) call, use
448 * this value as the character set...
451 if (!charset
[0] && (csptr
= nl_langinfo(CODESET
)) != NULL
)
454 * Copy all of the letters and numbers in the CODESET string...
457 for (ptr
= charset
; *csptr
; csptr
++)
458 if (isalnum(*csptr
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
463 DEBUG_printf(("cupsLangGet: charset set to \"%s\" via nl_langinfo(CODESET)...\n",
469 * If we don't have a character set by now, default to UTF-8...
473 strcpy(charset
, "UTF8");
476 * Parse the language string passed in to a locale string. "C" is the
477 * standard POSIX locale and is copied unchanged. Otherwise the
478 * language string is converted from ll-cc[.charset] (language-country)
479 * to ll_CC[.CHARSET] to match the file naming convention used by all
480 * POSIX-compliant operating systems. Invalid language names are mapped
481 * to the POSIX locale.
486 if (language
== NULL
|| !language
[0] ||
487 !strcmp(language
, "POSIX"))
488 strcpy(langname
, "C");
492 * Copy the parts of the locale string over safely...
495 for (ptr
= langname
; *language
; language
++)
496 if (*language
== '_' || *language
== '-' || *language
== '.')
498 else if (ptr
< (langname
+ sizeof(langname
) - 1))
499 *ptr
++ = tolower(*language
& 255);
503 if (*language
== '_' || *language
== '-')
506 * Copy the country code...
509 for (language
++, ptr
= country
; *language
; language
++)
510 if (*language
== '.')
512 else if (ptr
< (country
+ sizeof(country
) - 1))
513 *ptr
++ = toupper(*language
& 255);
518 if (*language
== '.' && !charset
[0])
521 * Copy the encoding...
524 for (language
++, ptr
= charset
; *language
; language
++)
525 if (isalnum(*language
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
526 *ptr
++ = toupper(*language
& 255);
532 * Force a POSIX locale for an invalid language name...
535 if (strlen(langname
) != 2)
537 strcpy(langname
, "C");
543 DEBUG_printf(("cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"\n",
544 langname
, country
, charset
));
547 * Figure out the desired encoding...
550 encoding
= CUPS_AUTO_ENCODING
;
555 i
< (int)(sizeof(locale_encodings
) / sizeof(locale_encodings
[0]));
557 if (!strcasecmp(charset
, locale_encodings
[i
]))
559 encoding
= (cups_encoding_t
)i
;
563 if (encoding
== CUPS_AUTO_ENCODING
)
566 * Map alternate names for various character sets...
569 if (!strcasecmp(charset
, "iso-2022-jp") ||
570 !strcasecmp(charset
, "sjis"))
571 encoding
= CUPS_WINDOWS_932
;
572 else if (!strcasecmp(charset
, "iso-2022-cn"))
573 encoding
= CUPS_WINDOWS_936
;
574 else if (!strcasecmp(charset
, "iso-2022-kr"))
575 encoding
= CUPS_WINDOWS_949
;
576 else if (!strcasecmp(charset
, "big5"))
577 encoding
= CUPS_WINDOWS_950
;
581 DEBUG_printf(("cupsLangGet: encoding=%d(%s)\n", encoding
,
582 encoding
== CUPS_AUTO_ENCODING
? "auto" :
583 lang_encodings
[encoding
]));
586 * See if we already have this language/country loaded...
591 snprintf(real
, sizeof(real
), "%s_%s", langname
, country
);
593 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
598 strcpy(real
, langname
);
599 filename
[0] = '\0'; /* anti-compiler-warning-code */
602 #ifdef HAVE_PTHREAD_H
603 pthread_mutex_lock(&lang_mutex
);
604 #endif /* HAVE_PTHREAD_H */
606 if ((lang
= cups_cache_lookup(langname
, encoding
)) != NULL
)
608 #ifdef HAVE_PTHREAD_H
609 pthread_mutex_unlock(&lang_mutex
);
610 #endif /* HAVE_PTHREAD_H */
615 if (!country
[0] || access(filename
, 0))
618 * Country localization not available, look for generic localization...
621 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
624 if (access(filename
, 0))
627 * No generic localization, so use POSIX...
630 DEBUG_printf(("access(\"%s\", 0): %s\n", filename
, strerror(errno
)));
632 snprintf(filename
, sizeof(filename
), "%s/C/cups_C.po", cg
->localedir
);
637 * See if there is a free language available; if so, use that
641 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
648 * Allocate memory for the language and add it to the cache.
651 if ((lang
= calloc(sizeof(cups_lang_t
), 1)) == NULL
)
653 #ifdef HAVE_PTHREAD_H
654 pthread_mutex_unlock(&lang_mutex
);
655 #endif /* HAVE_PTHREAD_H */
660 lang
->next
= lang_cache
;
666 * Free all old strings as needed...
669 _cupsMessageFree(lang
->strings
);
673 * Then assign the language and encoding fields...
677 strlcpy(lang
->language
, real
, sizeof(lang
->language
));
679 if (encoding
!= CUPS_AUTO_ENCODING
)
680 lang
->encoding
= encoding
;
682 lang
->encoding
= CUPS_UTF8
;
685 * Read the strings from the file...
688 lang
->strings
= _cupsMessageLoad(filename
);
694 #ifdef HAVE_PTHREAD_H
695 pthread_mutex_unlock(&lang_mutex
);
696 #endif /* HAVE_PTHREAD_H */
703 * '_cupsLangString()' - Get a message string.
705 * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
706 * convert the string to the language encoding.
709 const char * /* O - Localized message */
710 _cupsLangString(cups_lang_t
*lang
, /* I - Language */
711 const char *message
) /* I - Message */
714 * Range check input...
717 if (!lang
|| !message
)
720 #ifdef HAVE_PTHREAD_H
722 const char *s
; /* Localized message */
724 pthread_mutex_lock(&lang_mutex
);
726 s
= _cupsMessageLookup(lang
->strings
, message
);
728 pthread_mutex_unlock(&lang_mutex
);
733 return (_cupsMessageLookup(lang
->strings
, message
));
734 #endif /* HAVE_PTHREAD_H */
739 * '_cupsMessageFree()' - Free a messages array.
743 _cupsMessageFree(cups_array_t
*a
) /* I - Message array */
745 _cups_message_t
*m
; /* Current message */
748 for (m
= (_cups_message_t
*)cupsArrayFirst(a
);
750 m
= (_cups_message_t
*)cupsArrayNext(a
))
753 * Remove the message from the array, then free the message and strings.
756 cupsArrayRemove(a
, m
);
776 * '_cupsMessageLoad()' - Load a .po file into a messages array.
779 cups_array_t
* /* O - New message array */
780 _cupsMessageLoad(const char *filename
) /* I - Message catalog to load */
782 cups_file_t
*fp
; /* Message file */
783 cups_array_t
*a
; /* Message array */
784 _cups_message_t
*m
; /* Current message */
785 char s
[4096], /* String buffer */
786 *ptr
, /* Pointer into buffer */
787 *temp
; /* New string */
788 int length
; /* Length of combined strings */
791 DEBUG_printf(("_cupsMessageLoad(filename=\"%s\")\n", filename
));
794 * Create an array to hold the messages...
797 if ((a
= cupsArrayNew((cups_array_func_t
)cups_message_compare
, NULL
)) == NULL
)
801 * Open the message catalog file...
804 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
808 * Read messages from the catalog file until EOF...
810 * The format is the GNU gettext .po format, which is fairly simple:
813 * msgstr "localized text"
815 * The ID and localized text can span multiple lines using the form:
820 * "localized text spanning "
826 while (cupsFileGets(fp
, s
, sizeof(s
)) != NULL
)
829 * Skip blank and comment lines...
832 if (s
[0] == '#' || !s
[0])
836 * Strip the trailing quote...
839 if ((ptr
= strrchr(s
, '\"')) == NULL
)
845 * Find start of value...
848 if ((ptr
= strchr(s
, '\"')) == NULL
)
854 * Unquote the text...
857 cups_unquote(ptr
, ptr
);
860 * Create or add to a message...
863 if (!strncmp(s
, "msgid", 5))
866 * Add previous message as needed...
873 * Create a new message with the given msgid string...
876 if ((m
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
884 else if (s
[0] == '\"' && m
)
887 * Append to current string...
890 length
= strlen(m
->str
? m
->str
: m
->id
);
892 if ((temp
= realloc(m
->str
? m
->str
: m
->id
,
893 length
+ strlen(ptr
) + 1)) == NULL
)
902 * Copy the new portion to the end of the msgstr string - safe
903 * to use strcpy because the buffer is allocated to the correct
909 strcpy(m
->str
+ length
, ptr
);
914 * Copy the new portion to the end of the msgid string - safe
915 * to use strcpy because the buffer is allocated to the correct
921 strcpy(m
->id
+ length
, ptr
);
924 else if (!strncmp(s
, "msgstr", 6) && m
)
930 m
->str
= strdup(ptr
);
935 * Add the last message string to the array as needed...
942 * Close the message catalog file and return the new array...
952 * '_cupsMessageLookup()' - Lookup a message string.
955 const char * /* O - Localized message */
956 _cupsMessageLookup(cups_array_t
*a
, /* I - Message array */
957 const char *m
) /* I - Message */
959 _cups_message_t key
, /* Search key */
960 *match
; /* Matching message */
964 * Lookup the message string; if it doesn't exist in the catalog,
965 * then return the message that was passed to us...
969 match
= (_cups_message_t
*)cupsArrayFind(a
, &key
);
971 if (match
&& match
->str
)
980 * Code & data to translate OSX's language names to their ISO 639-1 locale.
982 * The first version uses the new CoreFoundation API added in 10.3 (Panther),
983 * the second is for 10.2 (Jaguar).
986 # ifdef HAVE_CF_LOCALE_ID
988 * 'appleLangDefault()' - Get the default locale string.
991 static const char * /* O - Locale string */
992 appleLangDefault(void)
994 CFPropertyListRef localizationList
;
995 /* List of localization data */
996 CFStringRef languageName
; /* Current name */
997 CFStringRef localeName
; /* Canonical from of name */
998 char *lang
; /* LANG environment variable */
999 _cups_globals_t
*cg
= _cupsGlobals();
1000 /* Pointer to library globals */
1004 * Only do the lookup and translation the first time.
1007 if (!cg
->language
[0])
1009 if ((lang
= getenv("LANG")))
1010 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1014 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1015 kCFPreferencesCurrentApplication
);
1017 if (localizationList
!= NULL
)
1019 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1020 CFArrayGetCount(localizationList
) > 0)
1022 languageName
= CFArrayGetValueAtIndex(localizationList
, 0);
1024 if (languageName
!= NULL
&&
1025 CFGetTypeID(languageName
) == CFStringGetTypeID())
1027 localeName
= CFLocaleCreateCanonicalLocaleIdentifierFromString(
1028 kCFAllocatorDefault
, languageName
);
1030 if (localeName
!= NULL
)
1032 CFStringGetCString(localeName
, cg
->language
, sizeof(cg
->language
),
1033 kCFStringEncodingASCII
);
1034 CFRelease(localeName
);
1036 if (!strcmp(cg
->language
, "en"))
1037 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1038 else if (strchr(cg
->language
, '.') == NULL
)
1039 strlcat(cg
->language
, ".UTF-8", sizeof(cg
->language
));
1044 CFRelease(localizationList
);
1049 * If we didn't find the language, default to en_US...
1052 if (!cg
->language
[0])
1053 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1057 * Return the cached locale...
1060 return (cg
->language
);
1064 * Code & data to translate OSX 10.2's language names to their ISO 639-1
1070 const char * const name
; /* Language name */
1071 const char * const locale
; /* Locale name */
1072 } _apple_name_locale_t
;
1074 static const _apple_name_locale_t apple_name_locale
[] =
1076 { "English" , "en_US.UTF-8" }, { "French" , "fr.UTF-8" },
1077 { "German" , "de.UTF-8" }, { "Italian" , "it.UTF-8" },
1078 { "Dutch" , "nl.UTF-8" }, { "Swedish" , "sv.UTF-8" },
1079 { "Spanish" , "es.UTF-8" }, { "Danish" , "da.UTF-8" },
1080 { "Portuguese" , "pt.UTF-8" }, { "Norwegian" , "no.UTF-8" },
1081 { "Hebrew" , "he.UTF-8" }, { "Japanese" , "ja.UTF-8" },
1082 { "Arabic" , "ar.UTF-8" }, { "Finnish" , "fi.UTF-8" },
1083 { "Greek" , "el.UTF-8" }, { "Icelandic" , "is.UTF-8" },
1084 { "Maltese" , "mt.UTF-8" }, { "Turkish" , "tr.UTF-8" },
1085 { "Croatian" , "hr.UTF-8" }, { "Chinese" , "zh.UTF-8" },
1086 { "Urdu" , "ur.UTF-8" }, { "Hindi" , "hi.UTF-8" },
1087 { "Thai" , "th.UTF-8" }, { "Korean" , "ko.UTF-8" },
1088 { "Lithuanian" , "lt.UTF-8" }, { "Polish" , "pl.UTF-8" },
1089 { "Hungarian" , "hu.UTF-8" }, { "Estonian" , "et.UTF-8" },
1090 { "Latvian" , "lv.UTF-8" }, { "Sami" , "se.UTF-8" },
1091 { "Faroese" , "fo.UTF-8" }, { "Farsi" , "fa.UTF-8" },
1092 { "Russian" , "ru.UTF-8" }, { "Chinese" , "zh.UTF-8" },
1093 { "Dutch" , "nl.UTF-8" }, { "Irish" , "ga.UTF-8" },
1094 { "Albanian" , "sq.UTF-8" }, { "Romanian" , "ro.UTF-8" },
1095 { "Czech" , "cs.UTF-8" }, { "Slovak" , "sk.UTF-8" },
1096 { "Slovenian" , "sl.UTF-8" }, { "Yiddish" , "yi.UTF-8" },
1097 { "Serbian" , "sr.UTF-8" }, { "Macedonian" , "mk.UTF-8" },
1098 { "Bulgarian" , "bg.UTF-8" }, { "Ukrainian" , "uk.UTF-8" },
1099 { "Byelorussian", "be.UTF-8" }, { "Uzbek" , "uz.UTF-8" },
1100 { "Kazakh" , "kk.UTF-8" }, { "Azerbaijani", "az.UTF-8" },
1101 { "Azerbaijani" , "az.UTF-8" }, { "Armenian" , "hy.UTF-8" },
1102 { "Georgian" , "ka.UTF-8" }, { "Moldavian" , "mo.UTF-8" },
1103 { "Kirghiz" , "ky.UTF-8" }, { "Tajiki" , "tg.UTF-8" },
1104 { "Turkmen" , "tk.UTF-8" }, { "Mongolian" , "mn.UTF-8" },
1105 { "Mongolian" , "mn.UTF-8" }, { "Pashto" , "ps.UTF-8" },
1106 { "Kurdish" , "ku.UTF-8" }, { "Kashmiri" , "ks.UTF-8" },
1107 { "Sindhi" , "sd.UTF-8" }, { "Tibetan" , "bo.UTF-8" },
1108 { "Nepali" , "ne.UTF-8" }, { "Sanskrit" , "sa.UTF-8" },
1109 { "Marathi" , "mr.UTF-8" }, { "Bengali" , "bn.UTF-8" },
1110 { "Assamese" , "as.UTF-8" }, { "Gujarati" , "gu.UTF-8" },
1111 { "Punjabi" , "pa.UTF-8" }, { "Oriya" , "or.UTF-8" },
1112 { "Malayalam" , "ml.UTF-8" }, { "Kannada" , "kn.UTF-8" },
1113 { "Tamil" , "ta.UTF-8" }, { "Telugu" , "te.UTF-8" },
1114 { "Sinhalese" , "si.UTF-8" }, { "Burmese" , "my.UTF-8" },
1115 { "Khmer" , "km.UTF-8" }, { "Lao" , "lo.UTF-8" },
1116 { "Vietnamese" , "vi.UTF-8" }, { "Indonesian" , "id.UTF-8" },
1117 { "Tagalog" , "tl.UTF-8" }, { "Malay" , "ms.UTF-8" },
1118 { "Malay" , "ms.UTF-8" }, { "Amharic" , "am.UTF-8" },
1119 { "Tigrinya" , "ti.UTF-8" }, { "Oromo" , "om.UTF-8" },
1120 { "Somali" , "so.UTF-8" }, { "Swahili" , "sw.UTF-8" },
1121 { "Kinyarwanda" , "rw.UTF-8" }, { "Rundi" , "rn.UTF-8" },
1122 { "Nyanja" , "" }, { "Malagasy" , "mg.UTF-8" },
1123 { "Esperanto" , "eo.UTF-8" }, { "Welsh" , "cy.UTF-8" },
1124 { "Basque" , "eu.UTF-8" }, { "Catalan" , "ca.UTF-8" },
1125 { "Latin" , "la.UTF-8" }, { "Quechua" , "qu.UTF-8" },
1126 { "Guarani" , "gn.UTF-8" }, { "Aymara" , "ay.UTF-8" },
1127 { "Tatar" , "tt.UTF-8" }, { "Uighur" , "ug.UTF-8" },
1128 { "Dzongkha" , "dz.UTF-8" }, { "Javanese" , "jv.UTF-8" },
1129 { "Sundanese" , "su.UTF-8" }, { "Galician" , "gl.UTF-8" },
1130 { "Afrikaans" , "af.UTF-8" }, { "Breton" , "br.UTF-8" },
1131 { "Inuktitut" , "iu.UTF-8" }, { "Scottish" , "gd.UTF-8" },
1132 { "Manx" , "gv.UTF-8" }, { "Irish" , "ga.UTF-8" },
1133 { "Tongan" , "to.UTF-8" }, { "Greek" , "el.UTF-8" },
1134 { "Greenlandic" , "kl.UTF-8" }, { "Azerbaijani", "az.UTF-8" }
1139 * 'appleLangDefault()' - Get the default locale string.
1142 static const char * /* O - Locale string */
1143 appleLangDefault(void)
1145 int i
; /* Looping var */
1146 CFPropertyListRef localizationList
;
1147 /* List of localization data */
1148 CFStringRef localizationName
;
1150 char buff
[256]; /* Temporary buffer */
1151 _cups_globals_t
*cg
= _cupsGlobals();
1152 /* Pointer to library globals */
1153 char *lang
; /* LANG environment variable */
1157 * Only do the lookup and translation the first time.
1160 if (!cg
->language
[0])
1162 if ((lang
= getenv("LANG")))
1163 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1167 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1168 kCFPreferencesCurrentApplication
);
1170 if (localizationList
!= NULL
)
1172 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1173 CFArrayGetCount(localizationList
) > 0)
1175 localizationName
= CFArrayGetValueAtIndex(localizationList
, 0);
1177 if (localizationName
!= NULL
&&
1178 CFGetTypeID(localizationName
) == CFStringGetTypeID())
1180 CFIndex length
= CFStringGetLength(localizationName
);
1182 if (length
<= sizeof(buff
) &&
1183 CFStringGetCString(localizationName
, buff
, sizeof(buff
),
1184 kCFStringEncodingASCII
))
1186 buff
[sizeof(buff
) - 1] = '\0';
1189 i
< sizeof(apple_name_locale
) / sizeof(apple_name_locale
[0]);
1192 if (!strcasecmp(buff
, apple_name_locale
[i
].name
))
1194 strlcpy(cg
->language
, apple_name_locale
[i
].locale
,
1195 sizeof(cg
->language
));
1203 CFRelease(localizationList
);
1208 * If we didn't find the language, default to en_US...
1211 if (!cg
->language
[0])
1212 strlcpy(cg
->language
, apple_name_locale
[0].locale
, sizeof(cg
->language
));
1216 * Return the cached locale...
1219 return (cg
->language
);
1221 # endif /* HAVE_CF_LOCALE_ID */
1222 #endif /* __APPLE__ */
1226 * 'cups_cache_lookup()' - Lookup a language in the cache...
1229 static cups_lang_t
* /* O - Language data or NULL */
1230 cups_cache_lookup(const char *name
,/* I - Name of locale */
1231 cups_encoding_t encoding
)
1232 /* I - Encoding of locale */
1234 cups_lang_t
*lang
; /* Current language */
1237 DEBUG_printf(("cups_cache_lookup(name=\"%s\", encoding=%d(%s))\n", name
,
1238 encoding
, encoding
== CUPS_AUTO_ENCODING
? "auto" :
1239 lang_encodings
[encoding
]));
1242 * Loop through the cache and return a match if found...
1245 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
1247 DEBUG_printf(("cups_cache_lookup: lang=%p, language=\"%s\", encoding=%d(%s)\n",
1248 lang
, lang
->language
, lang
->encoding
,
1249 lang_encodings
[lang
->encoding
]));
1251 if (!strcmp(lang
->language
, name
) &&
1252 (encoding
== CUPS_AUTO_ENCODING
|| encoding
== lang
->encoding
))
1256 DEBUG_puts("cups_cache_lookup: returning match!");
1262 DEBUG_puts("cups_cache_lookup: returning NULL!");
1269 * 'cups_message_compare()' - Compare two messages.
1272 static int /* O - Result of comparison */
1273 cups_message_compare(
1274 _cups_message_t
*m1
, /* I - First message */
1275 _cups_message_t
*m2
) /* I - Second message */
1277 return (strcmp(m1
->id
, m2
->id
));
1282 * 'cups_unquote()' - Unquote characters in strings...
1286 cups_unquote(char *d
, /* O - Unquoted string */
1287 const char *s
) /* I - Original string */
1300 *d
= *d
* 8 + *s
- '0';
1329 * End of "$Id: language.c 6073 2006-11-02 20:01:54Z mike $".