2 * "$Id: language.c 6916 2007-09-05 21:14:08Z 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
));
417 * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
420 if (!strncmp(locale
, "nb", 2))
423 DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n", language
));
426 #endif /* __APPLE__ */
429 * If "language" is NULL at this point, then chances are we are using
430 * a language that is not installed for the base OS.
436 * Switch to the POSIX ("C") locale...
444 * On systems that support the nl_langinfo(CODESET) call, use
445 * this value as the character set...
448 if (!charset
[0] && (csptr
= nl_langinfo(CODESET
)) != NULL
)
451 * Copy all of the letters and numbers in the CODESET string...
454 for (ptr
= charset
; *csptr
; csptr
++)
455 if (isalnum(*csptr
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
460 DEBUG_printf(("cupsLangGet: charset set to \"%s\" via nl_langinfo(CODESET)...\n",
466 * If we don't have a character set by now, default to UTF-8...
470 strcpy(charset
, "UTF8");
473 * Parse the language string passed in to a locale string. "C" is the
474 * standard POSIX locale and is copied unchanged. Otherwise the
475 * language string is converted from ll-cc[.charset] (language-country)
476 * to ll_CC[.CHARSET] to match the file naming convention used by all
477 * POSIX-compliant operating systems. Invalid language names are mapped
478 * to the POSIX locale.
483 if (language
== NULL
|| !language
[0] ||
484 !strcmp(language
, "POSIX"))
485 strcpy(langname
, "C");
489 * Copy the parts of the locale string over safely...
492 for (ptr
= langname
; *language
; language
++)
493 if (*language
== '_' || *language
== '-' || *language
== '.')
495 else if (ptr
< (langname
+ sizeof(langname
) - 1))
496 *ptr
++ = tolower(*language
& 255);
500 if (*language
== '_' || *language
== '-')
503 * Copy the country code...
506 for (language
++, ptr
= country
; *language
; language
++)
507 if (*language
== '.')
509 else if (ptr
< (country
+ sizeof(country
) - 1))
510 *ptr
++ = toupper(*language
& 255);
515 if (*language
== '.' && !charset
[0])
518 * Copy the encoding...
521 for (language
++, ptr
= charset
; *language
; language
++)
522 if (isalnum(*language
& 255) && ptr
< (charset
+ sizeof(charset
) - 1))
523 *ptr
++ = toupper(*language
& 255);
529 * Force a POSIX locale for an invalid language name...
532 if (strlen(langname
) != 2)
534 strcpy(langname
, "C");
540 DEBUG_printf(("cupsLangGet: langname=\"%s\", country=\"%s\", charset=\"%s\"\n",
541 langname
, country
, charset
));
544 * Figure out the desired encoding...
547 encoding
= CUPS_AUTO_ENCODING
;
552 i
< (int)(sizeof(locale_encodings
) / sizeof(locale_encodings
[0]));
554 if (!strcasecmp(charset
, locale_encodings
[i
]))
556 encoding
= (cups_encoding_t
)i
;
560 if (encoding
== CUPS_AUTO_ENCODING
)
563 * Map alternate names for various character sets...
566 if (!strcasecmp(charset
, "iso-2022-jp") ||
567 !strcasecmp(charset
, "sjis"))
568 encoding
= CUPS_WINDOWS_932
;
569 else if (!strcasecmp(charset
, "iso-2022-cn"))
570 encoding
= CUPS_WINDOWS_936
;
571 else if (!strcasecmp(charset
, "iso-2022-kr"))
572 encoding
= CUPS_WINDOWS_949
;
573 else if (!strcasecmp(charset
, "big5"))
574 encoding
= CUPS_WINDOWS_950
;
578 DEBUG_printf(("cupsLangGet: encoding=%d(%s)\n", encoding
,
579 encoding
== CUPS_AUTO_ENCODING
? "auto" :
580 lang_encodings
[encoding
]));
583 * See if we already have this language/country loaded...
588 snprintf(real
, sizeof(real
), "%s_%s", langname
, country
);
590 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
595 strcpy(real
, langname
);
596 filename
[0] = '\0'; /* anti-compiler-warning-code */
599 #ifdef HAVE_PTHREAD_H
600 pthread_mutex_lock(&lang_mutex
);
601 #endif /* HAVE_PTHREAD_H */
603 if ((lang
= cups_cache_lookup(real
, encoding
)) != NULL
)
605 #ifdef HAVE_PTHREAD_H
606 pthread_mutex_unlock(&lang_mutex
);
607 #endif /* HAVE_PTHREAD_H */
612 if (!country
[0] || access(filename
, 0))
615 * Country localization not available, look for generic localization...
618 snprintf(filename
, sizeof(filename
), "%s/%s/cups_%s.po", cg
->localedir
,
621 if (access(filename
, 0))
624 * No generic localization, so use POSIX...
627 DEBUG_printf(("access(\"%s\", 0): %s\n", filename
, strerror(errno
)));
629 snprintf(filename
, sizeof(filename
), "%s/C/cups_C.po", cg
->localedir
);
634 * See if there is a free language available; if so, use that
638 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
645 * Allocate memory for the language and add it to the cache.
648 if ((lang
= calloc(sizeof(cups_lang_t
), 1)) == NULL
)
650 #ifdef HAVE_PTHREAD_H
651 pthread_mutex_unlock(&lang_mutex
);
652 #endif /* HAVE_PTHREAD_H */
657 lang
->next
= lang_cache
;
663 * Free all old strings as needed...
666 _cupsMessageFree(lang
->strings
);
670 * Then assign the language and encoding fields...
674 strlcpy(lang
->language
, real
, sizeof(lang
->language
));
676 if (encoding
!= CUPS_AUTO_ENCODING
)
677 lang
->encoding
= encoding
;
679 lang
->encoding
= CUPS_UTF8
;
682 * Read the strings from the file...
685 lang
->strings
= _cupsMessageLoad(filename
);
691 #ifdef HAVE_PTHREAD_H
692 pthread_mutex_unlock(&lang_mutex
);
693 #endif /* HAVE_PTHREAD_H */
700 * '_cupsLangString()' - Get a message string.
702 * The returned string is UTF-8 encoded; use cupsUTF8ToCharset() to
703 * convert the string to the language encoding.
706 const char * /* O - Localized message */
707 _cupsLangString(cups_lang_t
*lang
, /* I - Language */
708 const char *message
) /* I - Message */
711 * Range check input...
714 if (!lang
|| !message
)
717 #ifdef HAVE_PTHREAD_H
719 const char *s
; /* Localized message */
721 pthread_mutex_lock(&lang_mutex
);
723 s
= _cupsMessageLookup(lang
->strings
, message
);
725 pthread_mutex_unlock(&lang_mutex
);
730 return (_cupsMessageLookup(lang
->strings
, message
));
731 #endif /* HAVE_PTHREAD_H */
736 * '_cupsMessageFree()' - Free a messages array.
740 _cupsMessageFree(cups_array_t
*a
) /* I - Message array */
742 _cups_message_t
*m
; /* Current message */
745 for (m
= (_cups_message_t
*)cupsArrayFirst(a
);
747 m
= (_cups_message_t
*)cupsArrayNext(a
))
750 * Remove the message from the array, then free the message and strings.
753 cupsArrayRemove(a
, m
);
773 * '_cupsMessageLoad()' - Load a .po file into a messages array.
776 cups_array_t
* /* O - New message array */
777 _cupsMessageLoad(const char *filename
) /* I - Message catalog to load */
779 cups_file_t
*fp
; /* Message file */
780 cups_array_t
*a
; /* Message array */
781 _cups_message_t
*m
; /* Current message */
782 char s
[4096], /* String buffer */
783 *ptr
, /* Pointer into buffer */
784 *temp
; /* New string */
785 int length
; /* Length of combined strings */
788 DEBUG_printf(("_cupsMessageLoad(filename=\"%s\")\n", filename
));
791 * Create an array to hold the messages...
794 if ((a
= cupsArrayNew((cups_array_func_t
)cups_message_compare
, NULL
)) == NULL
)
798 * Open the message catalog file...
801 if ((fp
= cupsFileOpen(filename
, "r")) == NULL
)
805 * Read messages from the catalog file until EOF...
807 * The format is the GNU gettext .po format, which is fairly simple:
810 * msgstr "localized text"
812 * The ID and localized text can span multiple lines using the form:
817 * "localized text spanning "
823 while (cupsFileGets(fp
, s
, sizeof(s
)) != NULL
)
826 * Skip blank and comment lines...
829 if (s
[0] == '#' || !s
[0])
833 * Strip the trailing quote...
836 if ((ptr
= strrchr(s
, '\"')) == NULL
)
842 * Find start of value...
845 if ((ptr
= strchr(s
, '\"')) == NULL
)
851 * Unquote the text...
854 cups_unquote(ptr
, ptr
);
857 * Create or add to a message...
860 if (!strncmp(s
, "msgid", 5))
863 * Add previous message as needed...
870 * Create a new message with the given msgid string...
873 if ((m
= (_cups_message_t
*)calloc(1, sizeof(_cups_message_t
))) == NULL
)
881 else if (s
[0] == '\"' && m
)
884 * Append to current string...
887 length
= (int)strlen(m
->str
? m
->str
: m
->id
);
889 if ((temp
= realloc(m
->str
? m
->str
: m
->id
,
890 length
+ strlen(ptr
) + 1)) == NULL
)
899 * Copy the new portion to the end of the msgstr string - safe
900 * to use strcpy because the buffer is allocated to the correct
906 strcpy(m
->str
+ length
, ptr
);
911 * Copy the new portion to the end of the msgid string - safe
912 * to use strcpy because the buffer is allocated to the correct
918 strcpy(m
->id
+ length
, ptr
);
921 else if (!strncmp(s
, "msgstr", 6) && m
)
927 m
->str
= strdup(ptr
);
932 * Add the last message string to the array as needed...
939 * Close the message catalog file and return the new array...
949 * '_cupsMessageLookup()' - Lookup a message string.
952 const char * /* O - Localized message */
953 _cupsMessageLookup(cups_array_t
*a
, /* I - Message array */
954 const char *m
) /* I - Message */
956 _cups_message_t key
, /* Search key */
957 *match
; /* Matching message */
961 * Lookup the message string; if it doesn't exist in the catalog,
962 * then return the message that was passed to us...
966 match
= (_cups_message_t
*)cupsArrayFind(a
, &key
);
968 if (match
&& match
->str
)
977 * Code & data to translate OSX's language names to their ISO 639-1 locale.
979 * The first version uses the new CoreFoundation API added in 10.3 (Panther),
980 * the second is for 10.2 (Jaguar).
983 # ifdef HAVE_CF_LOCALE_ID
987 const char * const name
; /* Language name */
988 const char * const locale
; /* Locale name */
989 } _apple_name_locale_t
;
991 static const _apple_name_locale_t apple_name_locale
[] =
995 { "zh-Hans" , "zh_CN" },
996 { "zh-Hant" , "zh_TW" }
1001 * 'appleLangDefault()' - Get the default locale string.
1004 static const char * /* O - Locale string */
1005 appleLangDefault(void)
1007 int i
; /* Looping var */
1008 CFBundleRef bundle
; /* Main bundle (if any) */
1009 CFArrayRef bundleList
; /* List of localizations in bundle */
1010 CFPropertyListRef localizationList
;
1011 /* List of localization data */
1012 CFStringRef languageName
; /* Current name */
1013 CFStringRef localeName
; /* Canonical from of name */
1014 char *lang
; /* LANG environment variable */
1015 _cups_globals_t
*cg
= _cupsGlobals();
1016 /* Pointer to library globals */
1020 * Only do the lookup and translation the first time.
1023 if (!cg
->language
[0])
1025 if ((lang
= getenv("LANG")))
1027 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1028 return (cg
->language
);
1030 else if ((bundle
= CFBundleGetMainBundle()) != NULL
&&
1031 (bundleList
= CFBundleCopyBundleLocalizations(bundle
)) != NULL
)
1034 CFBundleCopyPreferredLocalizationsFromArray(bundleList
);
1036 CFRelease(bundleList
);
1040 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1041 kCFPreferencesCurrentApplication
);
1043 if (localizationList
)
1045 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1046 CFArrayGetCount(localizationList
) > 0)
1048 languageName
= CFArrayGetValueAtIndex(localizationList
, 0);
1051 CFGetTypeID(languageName
) == CFStringGetTypeID())
1053 localeName
= CFLocaleCreateCanonicalLocaleIdentifierFromString(
1054 kCFAllocatorDefault
, languageName
);
1058 CFStringGetCString(localeName
, cg
->language
, sizeof(cg
->language
),
1059 kCFStringEncodingASCII
);
1060 CFRelease(localeName
);
1062 DEBUG_printf(("appleLangDefault: cg->language=\"%s\"\n",
1066 * Map new language identifiers to locales...
1070 i
< sizeof(apple_name_locale
) / sizeof(apple_name_locale
[0]);
1073 if (!strcmp(cg
->language
, apple_name_locale
[i
].name
))
1075 DEBUG_printf(("appleLangDefault: mapping \"%s\" to \"%s\"...\n",
1076 cg
->language
, apple_name_locale
[i
].locale
));
1077 strlcpy(cg
->language
, apple_name_locale
[i
].locale
,
1078 sizeof(cg
->language
));
1084 * Convert language subtag into region subtag...
1087 if (cg
->language
[2] == '-')
1088 cg
->language
[2] = '_';
1090 if (!strchr(cg
->language
, '.'))
1091 strlcat(cg
->language
, ".UTF-8", sizeof(cg
->language
));
1096 CFRelease(localizationList
);
1100 * If we didn't find the language, default to en_US...
1103 if (!cg
->language
[0])
1104 strlcpy(cg
->language
, "en_US.UTF-8", sizeof(cg
->language
));
1108 * Return the cached locale...
1111 return (cg
->language
);
1115 * Code & data to translate OSX 10.2's language names to their ISO 639-1
1121 const char * const name
; /* Language name */
1122 const char * const locale
; /* Locale name */
1123 } _apple_name_locale_t
;
1125 static const _apple_name_locale_t apple_name_locale
[] =
1127 { "English" , "en_US.UTF-8" }, { "French" , "fr.UTF-8" },
1128 { "German" , "de.UTF-8" }, { "Italian" , "it.UTF-8" },
1129 { "Dutch" , "nl.UTF-8" }, { "Swedish" , "sv.UTF-8" },
1130 { "Spanish" , "es.UTF-8" }, { "Danish" , "da.UTF-8" },
1131 { "Portuguese" , "pt.UTF-8" }, { "Norwegian" , "no.UTF-8" },
1132 { "Hebrew" , "he.UTF-8" }, { "Japanese" , "ja.UTF-8" },
1133 { "Arabic" , "ar.UTF-8" }, { "Finnish" , "fi.UTF-8" },
1134 { "Greek" , "el.UTF-8" }, { "Icelandic" , "is.UTF-8" },
1135 { "Maltese" , "mt.UTF-8" }, { "Turkish" , "tr.UTF-8" },
1136 { "Croatian" , "hr.UTF-8" }, { "Chinese" , "zh.UTF-8" },
1137 { "Urdu" , "ur.UTF-8" }, { "Hindi" , "hi.UTF-8" },
1138 { "Thai" , "th.UTF-8" }, { "Korean" , "ko.UTF-8" },
1139 { "Lithuanian" , "lt.UTF-8" }, { "Polish" , "pl.UTF-8" },
1140 { "Hungarian" , "hu.UTF-8" }, { "Estonian" , "et.UTF-8" },
1141 { "Latvian" , "lv.UTF-8" }, { "Sami" , "se.UTF-8" },
1142 { "Faroese" , "fo.UTF-8" }, { "Farsi" , "fa.UTF-8" },
1143 { "Russian" , "ru.UTF-8" }, { "Chinese" , "zh.UTF-8" },
1144 { "Dutch" , "nl.UTF-8" }, { "Irish" , "ga.UTF-8" },
1145 { "Albanian" , "sq.UTF-8" }, { "Romanian" , "ro.UTF-8" },
1146 { "Czech" , "cs.UTF-8" }, { "Slovak" , "sk.UTF-8" },
1147 { "Slovenian" , "sl.UTF-8" }, { "Yiddish" , "yi.UTF-8" },
1148 { "Serbian" , "sr.UTF-8" }, { "Macedonian" , "mk.UTF-8" },
1149 { "Bulgarian" , "bg.UTF-8" }, { "Ukrainian" , "uk.UTF-8" },
1150 { "Byelorussian", "be.UTF-8" }, { "Uzbek" , "uz.UTF-8" },
1151 { "Kazakh" , "kk.UTF-8" }, { "Azerbaijani", "az.UTF-8" },
1152 { "Azerbaijani" , "az.UTF-8" }, { "Armenian" , "hy.UTF-8" },
1153 { "Georgian" , "ka.UTF-8" }, { "Moldavian" , "mo.UTF-8" },
1154 { "Kirghiz" , "ky.UTF-8" }, { "Tajiki" , "tg.UTF-8" },
1155 { "Turkmen" , "tk.UTF-8" }, { "Mongolian" , "mn.UTF-8" },
1156 { "Mongolian" , "mn.UTF-8" }, { "Pashto" , "ps.UTF-8" },
1157 { "Kurdish" , "ku.UTF-8" }, { "Kashmiri" , "ks.UTF-8" },
1158 { "Sindhi" , "sd.UTF-8" }, { "Tibetan" , "bo.UTF-8" },
1159 { "Nepali" , "ne.UTF-8" }, { "Sanskrit" , "sa.UTF-8" },
1160 { "Marathi" , "mr.UTF-8" }, { "Bengali" , "bn.UTF-8" },
1161 { "Assamese" , "as.UTF-8" }, { "Gujarati" , "gu.UTF-8" },
1162 { "Punjabi" , "pa.UTF-8" }, { "Oriya" , "or.UTF-8" },
1163 { "Malayalam" , "ml.UTF-8" }, { "Kannada" , "kn.UTF-8" },
1164 { "Tamil" , "ta.UTF-8" }, { "Telugu" , "te.UTF-8" },
1165 { "Sinhalese" , "si.UTF-8" }, { "Burmese" , "my.UTF-8" },
1166 { "Khmer" , "km.UTF-8" }, { "Lao" , "lo.UTF-8" },
1167 { "Vietnamese" , "vi.UTF-8" }, { "Indonesian" , "id.UTF-8" },
1168 { "Tagalog" , "tl.UTF-8" }, { "Malay" , "ms.UTF-8" },
1169 { "Malay" , "ms.UTF-8" }, { "Amharic" , "am.UTF-8" },
1170 { "Tigrinya" , "ti.UTF-8" }, { "Oromo" , "om.UTF-8" },
1171 { "Somali" , "so.UTF-8" }, { "Swahili" , "sw.UTF-8" },
1172 { "Kinyarwanda" , "rw.UTF-8" }, { "Rundi" , "rn.UTF-8" },
1173 { "Nyanja" , "" }, { "Malagasy" , "mg.UTF-8" },
1174 { "Esperanto" , "eo.UTF-8" }, { "Welsh" , "cy.UTF-8" },
1175 { "Basque" , "eu.UTF-8" }, { "Catalan" , "ca.UTF-8" },
1176 { "Latin" , "la.UTF-8" }, { "Quechua" , "qu.UTF-8" },
1177 { "Guarani" , "gn.UTF-8" }, { "Aymara" , "ay.UTF-8" },
1178 { "Tatar" , "tt.UTF-8" }, { "Uighur" , "ug.UTF-8" },
1179 { "Dzongkha" , "dz.UTF-8" }, { "Javanese" , "jv.UTF-8" },
1180 { "Sundanese" , "su.UTF-8" }, { "Galician" , "gl.UTF-8" },
1181 { "Afrikaans" , "af.UTF-8" }, { "Breton" , "br.UTF-8" },
1182 { "Inuktitut" , "iu.UTF-8" }, { "Scottish" , "gd.UTF-8" },
1183 { "Manx" , "gv.UTF-8" }, { "Irish" , "ga.UTF-8" },
1184 { "Tongan" , "to.UTF-8" }, { "Greek" , "el.UTF-8" },
1185 { "Greenlandic" , "kl.UTF-8" }, { "Azerbaijani", "az.UTF-8" }
1190 * 'appleLangDefault()' - Get the default locale string.
1193 static const char * /* O - Locale string */
1194 appleLangDefault(void)
1196 int i
; /* Looping var */
1197 CFPropertyListRef localizationList
;
1198 /* List of localization data */
1199 CFStringRef localizationName
;
1201 char buff
[256]; /* Temporary buffer */
1202 _cups_globals_t
*cg
= _cupsGlobals();
1203 /* Pointer to library globals */
1204 char *lang
; /* LANG environment variable */
1208 * Only do the lookup and translation the first time.
1211 if (!cg
->language
[0])
1213 if ((lang
= getenv("LANG")))
1214 strlcpy(cg
->language
, lang
, sizeof(cg
->language
));
1218 CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
1219 kCFPreferencesCurrentApplication
);
1221 if (localizationList
!= NULL
)
1223 if (CFGetTypeID(localizationList
) == CFArrayGetTypeID() &&
1224 CFArrayGetCount(localizationList
) > 0)
1226 localizationName
= CFArrayGetValueAtIndex(localizationList
, 0);
1228 if (localizationName
!= NULL
&&
1229 CFGetTypeID(localizationName
) == CFStringGetTypeID())
1231 CFIndex length
= CFStringGetLength(localizationName
);
1233 if (length
<= sizeof(buff
) &&
1234 CFStringGetCString(localizationName
, buff
, sizeof(buff
),
1235 kCFStringEncodingASCII
))
1237 buff
[sizeof(buff
) - 1] = '\0';
1240 i
< sizeof(apple_name_locale
) / sizeof(apple_name_locale
[0]);
1243 if (!strcasecmp(buff
, apple_name_locale
[i
].name
))
1245 strlcpy(cg
->language
, apple_name_locale
[i
].locale
,
1246 sizeof(cg
->language
));
1254 CFRelease(localizationList
);
1259 * If we didn't find the language, default to en_US...
1262 if (!cg
->language
[0])
1263 strlcpy(cg
->language
, apple_name_locale
[0].locale
, sizeof(cg
->language
));
1267 * Return the cached locale...
1270 return (cg
->language
);
1272 # endif /* HAVE_CF_LOCALE_ID */
1273 #endif /* __APPLE__ */
1277 * 'cups_cache_lookup()' - Lookup a language in the cache...
1280 static cups_lang_t
* /* O - Language data or NULL */
1281 cups_cache_lookup(const char *name
,/* I - Name of locale */
1282 cups_encoding_t encoding
)
1283 /* I - Encoding of locale */
1285 cups_lang_t
*lang
; /* Current language */
1288 DEBUG_printf(("cups_cache_lookup(name=\"%s\", encoding=%d(%s))\n", name
,
1289 encoding
, encoding
== CUPS_AUTO_ENCODING
? "auto" :
1290 lang_encodings
[encoding
]));
1293 * Loop through the cache and return a match if found...
1296 for (lang
= lang_cache
; lang
!= NULL
; lang
= lang
->next
)
1298 DEBUG_printf(("cups_cache_lookup: lang=%p, language=\"%s\", encoding=%d(%s)\n",
1299 lang
, lang
->language
, lang
->encoding
,
1300 lang_encodings
[lang
->encoding
]));
1302 if (!strcmp(lang
->language
, name
) &&
1303 (encoding
== CUPS_AUTO_ENCODING
|| encoding
== lang
->encoding
))
1307 DEBUG_puts("cups_cache_lookup: returning match!");
1313 DEBUG_puts("cups_cache_lookup: returning NULL!");
1320 * 'cups_message_compare()' - Compare two messages.
1323 static int /* O - Result of comparison */
1324 cups_message_compare(
1325 _cups_message_t
*m1
, /* I - First message */
1326 _cups_message_t
*m2
) /* I - Second message */
1328 return (strcmp(m1
->id
, m2
->id
));
1333 * 'cups_unquote()' - Unquote characters in strings...
1337 cups_unquote(char *d
, /* O - Unquoted string */
1338 const char *s
) /* I - Original string */
1351 *d
= *d
* 8 + *s
- '0';
1380 * End of "$Id: language.c 6916 2007-09-05 21:14:08Z mike $".