]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/language.c
Import CUPS 1.4svn-r7226.
[thirdparty/cups.git] / cups / language.c
index e8cf5bed6085eacb32d72b73e6a318625348d788..ea629c9031cfd674d2f624b76f6626d1b34e85b8 100644 (file)
@@ -1,30 +1,23 @@
 /*
- * "$Id: language.c 6188 2007-01-10 16:23:06Z mike $"
+ * "$Id: language.c 6916 2007-09-05 21:14:08Z mike $"
  *
  *   I18N/language support for the Common UNIX Printing System (CUPS).
  *
+ *   Copyright 2007-2008 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
- *   property of Easy Software Products and are protected by Federal
- *   copyright law.  Distribution and use rights are outlined in the file
- *   "LICENSE.txt" which should have been included with this file.  If this
- *   file is missing or damaged please contact Easy Software Products
- *   at:
- *
- *       Attn: CUPS Licensing Information
- *       Easy Software Products
- *       44141 Airport View Drive, Suite 204
- *       Hollywood, Maryland 20636 USA
- *
- *       Voice: (301) 373-9600
- *       EMail: cups-info@cups.org
- *         WWW: http://www.cups.org
+ *   property of Apple Inc. and are protected by Federal copyright
+ *   law.  Distribution and use rights are outlined in the file "LICENSE.txt"
+ *   which should have been included with this file.  If this file is
+ *   file is missing or damaged, see the license at "http://www.cups.org/".
  *
  *   This file is subject to the Apple OS-Developed Software exception.
  *
  * Contents:
  *
+ *   _cupsAppleLanguage()   - Get the Apple language identifier associated
+ *                            with a locale ID.
  *   _cupsEncodingName()    - Return the character encoding name string
  *                            for the given encoding enumeration.
  *   cupsLangDefault()      - Return the default language.
@@ -74,26 +67,6 @@ static pthread_mutex_t       lang_mutex = PTHREAD_MUTEX_INITIALIZER;
 #endif /* HAVE_PTHREAD_H */
 static cups_lang_t     *lang_cache = NULL;
                                        /* Language string cache */
-
-
-/*
- * Local functions...
- */
-
-#ifdef __APPLE__
-static const char      *appleLangDefault(void);
-#endif /* __APPLE__ */
-static cups_lang_t     *cups_cache_lookup(const char *name,
-                                          cups_encoding_t encoding);
-static int             cups_message_compare(_cups_message_t *m1,
-                                            _cups_message_t *m2);
-static void            cups_unquote(char *d, const char *s);
-
-
-/*
- * Local globals...
- */
-
 static const char * const lang_encodings[] =
                        {               /* Encoding strings */
                          "us-ascii",           "iso-8859-1",
@@ -164,6 +137,123 @@ static const char * const lang_encodings[] =
                          "euc-kr",             "euc-tw"
                        };
 
+#ifdef __APPLE__
+typedef struct
+{
+  const char * const language;         /* Language ID */
+  const char * const locale;           /* Locale ID */
+} _apple_language_locale_t;
+
+static const _apple_language_locale_t apple_language_locale[] =
+{                                      /* Locale to language ID LUT */
+  { "en"       , "en_US" },
+  { "nb"       , "no"    },
+  { "zh-Hans"  , "zh_CN" },
+  { "zh-Hant"  , "zh_TW" }
+};
+#endif /* __APPLE__ */
+
+
+/*
+ * Local functions...
+ */
+
+#ifdef __APPLE__
+static const char      *appleLangDefault(void);
+#endif /* __APPLE__ */
+static cups_lang_t     *cups_cache_lookup(const char *name,
+                                          cups_encoding_t encoding);
+static int             cups_message_compare(_cups_message_t *m1,
+                                            _cups_message_t *m2);
+static void            cups_unquote(char *d, const char *s);
+
+
+#ifdef __APPLE__
+/*
+ *   _cupsAppleLanguage()   - Get the Apple language identifier associated
+ *                            with a locale ID.
+ */
+
+const char *                           /* O - Language ID */
+_cupsAppleLanguage(const char *locale, /* I - Locale ID */
+                   char       *language,/* I - Language ID buffer */
+                   size_t     langsize)        /* I - Size of language ID buffer */
+{
+  int          i;                      /* Looping var */
+  CFStringRef  localeid,               /* CF locale identifier */
+               langid;                 /* CF language identifier */
+
+
+ /*
+  * Copy the locale name and convert, as needed, to the Apple-specific
+  * locale identifier...
+  */
+
+  switch (strlen(locale))
+  {
+    default :
+        /*
+        * Invalid locale...
+        */
+
+        strlcpy(language, "en", langsize);
+        break;
+
+    case 2 :
+        strlcpy(language, locale, langsize);
+        break;
+
+    case 5 :
+        strlcpy(language, locale, langsize);
+
+       if (language[2] == '-')
+       {
+        /*
+         * Convert ll-cc to ll_CC...
+         */
+
+         language[2] = '_';
+         language[3] = toupper(language[3] & 255);
+         language[4] = toupper(language[4] & 255);
+       }
+       break;
+  }
+
+  for (i = 0;
+       i < (int)(sizeof(apple_language_locale) /
+                sizeof(apple_language_locale[0]));
+       i ++)
+    if (!strcmp(locale, apple_language_locale[i].locale))
+    {
+      strlcpy(language, apple_language_locale[i].language, sizeof(language));
+      break;
+    }
+
+ /*
+  * Attempt to map the locale ID to a language ID...
+  */
+
+  if ((localeid = CFStringCreateWithCString(kCFAllocatorDefault, language,
+                                            kCFStringEncodingASCII)) != NULL)
+  {
+    if ((langid = CFLocaleCreateCanonicalLanguageIdentifierFromString(
+                      kCFAllocatorDefault, localeid)) != NULL)
+    {
+      CFStringGetCString(langid, language, langsize, kCFStringEncodingASCII);
+      CFRelease(langid);
+    }
+
+    CFRelease(localeid);
+  }
+
+ /*
+  * Return what we got...
+  */
+
+  return (language);
+}
+#endif /* __APPLE__ */
+
 
 /*
  * '_cupsEncodingName()' - Return the character encoding name string
@@ -351,7 +441,7 @@ cupsLangGet(const char *language)   /* I - Language or locale */
   * preference so we have to look it up this way...
   */
 
-  if (!language)
+  if (!language && (language = getenv("LANG")) == NULL)
     language = appleLangDefault();
 
 #else
@@ -422,8 +512,14 @@ cupsLangGet(const char *language)  /* I - Language or locale */
       strlcpy(locale, ptr, sizeof(locale));
       language = locale;
 
-      DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n",
-                    language ? language : "(null)"));
+     /*
+      * CUPS STR #2575: Map "nb" to "no" for back-compatibility...
+      */
+
+      if (!strncmp(locale, "nb", 2))
+        locale[1] = 'o';
+
+      DEBUG_printf(("cupsLangGet: new language value is \"%s\"\n", language));
     }
   }
 #endif /* __APPLE__ */
@@ -603,7 +699,7 @@ cupsLangGet(const char *language)   /* I - Language or locale */
   pthread_mutex_lock(&lang_mutex);
 #endif /* HAVE_PTHREAD_H */
 
-  if ((lang = cups_cache_lookup(langname, encoding)) != NULL)
+  if ((lang = cups_cache_lookup(real, encoding)) != NULL)
   {
 #ifdef HAVE_PTHREAD_H
     pthread_mutex_unlock(&lang_mutex);
@@ -879,7 +975,12 @@ _cupsMessageLoad(const char *filename)     /* I - Message catalog to load */
        return (a);
       }
 
-      m->id = strdup(ptr);
+      if ((m->id = strdup(ptr)) == NULL)
+      {
+        free(m);
+        cupsFileClose(fp);
+       return (a);
+      }
     }
     else if (s[0] == '\"' && m)
     {
@@ -927,7 +1028,11 @@ _cupsMessageLoad(const char *filename)    /* I - Message catalog to load */
       * Set the string...
       */
 
-      m->str = strdup(ptr);
+      if ((m->str = strdup(ptr)) == NULL)
+      {
+        cupsFileClose(fp);
+       return (a);
+      }
     }
   }
 
@@ -976,14 +1081,6 @@ _cupsMessageLookup(cups_array_t *a,       /* I - Message array */
 
 
 #ifdef __APPLE__
-/*
- * Code & data to translate OSX's language names to their ISO 639-1 locale.
- *
- * The first version uses the new CoreFoundation API added in 10.3 (Panther),
- * the second is for 10.2 (Jaguar).
- */
-
-#  ifdef HAVE_CF_LOCALE_ID
 /*
  * 'appleLangDefault()' - Get the default locale string.
  */
@@ -991,6 +1088,9 @@ _cupsMessageLookup(cups_array_t *a,        /* I - Message array */
 static const char *                    /* O - Locale string */
 appleLangDefault(void)
 {
+  int                  i;              /* Looping var */
+  CFBundleRef          bundle;         /* Main bundle (if any) */
+  CFArrayRef           bundleList;     /* List of localizations in bundle */
   CFPropertyListRef    localizationList;
                                        /* List of localization data */
   CFStringRef          languageName;   /* Current name */
@@ -1007,201 +1107,78 @@ appleLangDefault(void)
   if (!cg->language[0])
   {
     if ((lang = getenv("LANG")))
+    {
       strlcpy(cg->language, lang, sizeof(cg->language));
-    else
+      return (cg->language);
+    }
+    else if ((bundle = CFBundleGetMainBundle()) != NULL &&
+             (bundleList = CFBundleCopyBundleLocalizations(bundle)) != NULL)
     {
       localizationList =
-          CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
-                                    kCFPreferencesCurrentApplication);
-
-      if (localizationList != NULL)
-      {
-       if (CFGetTypeID(localizationList) == CFArrayGetTypeID() &&
-           CFArrayGetCount(localizationList) > 0)
-       {
-          languageName = CFArrayGetValueAtIndex(localizationList, 0);
-
-          if (languageName != NULL &&
-              CFGetTypeID(languageName) == CFStringGetTypeID())
-          {
-           localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(
-                            kCFAllocatorDefault, languageName);
-
-           if (localeName != NULL)
-           {
-             CFStringGetCString(localeName, cg->language, sizeof(cg->language),
-                                kCFStringEncodingASCII);
-             CFRelease(localeName);
-
-             if (!strcmp(cg->language, "en"))
-               strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language));
-             else if (strchr(cg->language, '.') == NULL)
-               strlcat(cg->language, ".UTF-8", sizeof(cg->language));
-           }
-          }
-       }
+         CFBundleCopyPreferredLocalizationsFromArray(bundleList);
 
-       CFRelease(localizationList);
-      }
+      CFRelease(bundleList);
     }
-  
-   /*
-    * If we didn't find the language, default to en_US...
-    */
-
-    if (!cg->language[0])
-      strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language));
-  }
-
- /*
-  * Return the cached locale...
-  */
-
-  return (cg->language);
-}
-#  else
-/*
- * Code & data to translate OSX 10.2's language names to their ISO 639-1
- * locale.
- */
-
-typedef struct
-{
-  const char * const name;             /* Language name */
-  const char * const locale;           /* Locale name */
-} _apple_name_locale_t;
-
-static const _apple_name_locale_t apple_name_locale[] =
-{
-  { "English"     , "en_US.UTF-8" },   { "French"     , "fr.UTF-8" },
-  { "German"      , "de.UTF-8" },      { "Italian"    , "it.UTF-8" },  
-  { "Dutch"       , "nl.UTF-8" },      { "Swedish"    , "sv.UTF-8" },
-  { "Spanish"     , "es.UTF-8" },      { "Danish"     , "da.UTF-8" },  
-  { "Portuguese"  , "pt.UTF-8" },      { "Norwegian"  , "no.UTF-8" },
-  { "Hebrew"      , "he.UTF-8" },      { "Japanese"   , "ja.UTF-8" },  
-  { "Arabic"      , "ar.UTF-8" },      { "Finnish"    , "fi.UTF-8" },
-  { "Greek"       , "el.UTF-8" },      { "Icelandic"  , "is.UTF-8" },  
-  { "Maltese"     , "mt.UTF-8" },      { "Turkish"    , "tr.UTF-8" },
-  { "Croatian"    , "hr.UTF-8" },      { "Chinese"    , "zh.UTF-8" },  
-  { "Urdu"        , "ur.UTF-8" },      { "Hindi"      , "hi.UTF-8" },
-  { "Thai"        , "th.UTF-8" },      { "Korean"     , "ko.UTF-8" },  
-  { "Lithuanian"  , "lt.UTF-8" },      { "Polish"     , "pl.UTF-8" },
-  { "Hungarian"   , "hu.UTF-8" },      { "Estonian"   , "et.UTF-8" },  
-  { "Latvian"     , "lv.UTF-8" },      { "Sami"       , "se.UTF-8" },
-  { "Faroese"     , "fo.UTF-8" },      { "Farsi"      , "fa.UTF-8" },  
-  { "Russian"     , "ru.UTF-8" },      { "Chinese"    , "zh.UTF-8" },
-  { "Dutch"       , "nl.UTF-8" },      { "Irish"      , "ga.UTF-8" },  
-  { "Albanian"    , "sq.UTF-8" },      { "Romanian"   , "ro.UTF-8" },
-  { "Czech"       , "cs.UTF-8" },      { "Slovak"     , "sk.UTF-8" },  
-  { "Slovenian"   , "sl.UTF-8" },      { "Yiddish"    , "yi.UTF-8" },
-  { "Serbian"     , "sr.UTF-8" },      { "Macedonian" , "mk.UTF-8" },  
-  { "Bulgarian"   , "bg.UTF-8" },      { "Ukrainian"  , "uk.UTF-8" },
-  { "Byelorussian", "be.UTF-8" },      { "Uzbek"      , "uz.UTF-8" },  
-  { "Kazakh"      , "kk.UTF-8" },      { "Azerbaijani", "az.UTF-8" },
-  { "Azerbaijani" , "az.UTF-8" },      { "Armenian"   , "hy.UTF-8" },  
-  { "Georgian"    , "ka.UTF-8" },      { "Moldavian"  , "mo.UTF-8" },
-  { "Kirghiz"     , "ky.UTF-8" },      { "Tajiki"     , "tg.UTF-8" },  
-  { "Turkmen"     , "tk.UTF-8" },      { "Mongolian"  , "mn.UTF-8" },
-  { "Mongolian"   , "mn.UTF-8" },      { "Pashto"     , "ps.UTF-8" },  
-  { "Kurdish"     , "ku.UTF-8" },      { "Kashmiri"   , "ks.UTF-8" },
-  { "Sindhi"      , "sd.UTF-8" },      { "Tibetan"    , "bo.UTF-8" },  
-  { "Nepali"      , "ne.UTF-8" },      { "Sanskrit"   , "sa.UTF-8" },
-  { "Marathi"     , "mr.UTF-8" },      { "Bengali"    , "bn.UTF-8" },  
-  { "Assamese"    , "as.UTF-8" },      { "Gujarati"   , "gu.UTF-8" },
-  { "Punjabi"     , "pa.UTF-8" },      { "Oriya"      , "or.UTF-8" },  
-  { "Malayalam"   , "ml.UTF-8" },      { "Kannada"    , "kn.UTF-8" },
-  { "Tamil"       , "ta.UTF-8" },      { "Telugu"     , "te.UTF-8" },  
-  { "Sinhalese"   , "si.UTF-8" },      { "Burmese"    , "my.UTF-8" },
-  { "Khmer"       , "km.UTF-8" },      { "Lao"        , "lo.UTF-8" },  
-  { "Vietnamese"  , "vi.UTF-8" },      { "Indonesian" , "id.UTF-8" },
-  { "Tagalog"     , "tl.UTF-8" },      { "Malay"      , "ms.UTF-8" },  
-  { "Malay"       , "ms.UTF-8" },      { "Amharic"    , "am.UTF-8" },
-  { "Tigrinya"    , "ti.UTF-8" },      { "Oromo"      , "om.UTF-8" },  
-  { "Somali"      , "so.UTF-8" },      { "Swahili"    , "sw.UTF-8" },
-  { "Kinyarwanda" , "rw.UTF-8" },      { "Rundi"      , "rn.UTF-8" },  
-  { "Nyanja"      , "" },              { "Malagasy"   , "mg.UTF-8" },
-  { "Esperanto"   , "eo.UTF-8" },      { "Welsh"      , "cy.UTF-8" },  
-  { "Basque"      , "eu.UTF-8" },      { "Catalan"    , "ca.UTF-8" },
-  { "Latin"       , "la.UTF-8" },      { "Quechua"    , "qu.UTF-8" },  
-  { "Guarani"     , "gn.UTF-8" },      { "Aymara"     , "ay.UTF-8" },
-  { "Tatar"       , "tt.UTF-8" },      { "Uighur"     , "ug.UTF-8" },  
-  { "Dzongkha"    , "dz.UTF-8" },      { "Javanese"   , "jv.UTF-8" },
-  { "Sundanese"   , "su.UTF-8" },      { "Galician"   , "gl.UTF-8" },  
-  { "Afrikaans"   , "af.UTF-8" },      { "Breton"     , "br.UTF-8" },
-  { "Inuktitut"   , "iu.UTF-8" },      { "Scottish"   , "gd.UTF-8" },  
-  { "Manx"        , "gv.UTF-8" },      { "Irish"      , "ga.UTF-8" },
-  { "Tongan"      , "to.UTF-8" },      { "Greek"      , "el.UTF-8" },  
-  { "Greenlandic" , "kl.UTF-8" },      { "Azerbaijani", "az.UTF-8" }
-};
-
-
-/*
- * 'appleLangDefault()' - Get the default locale string.
- */
-
-static const char *                    /* O - Locale string */
-appleLangDefault(void)
-{
-  int                  i;              /* Looping var */
-  CFPropertyListRef    localizationList;
-                                       /* List of localization data */
-  CFStringRef          localizationName;
-                                       /* Current name */
-  char                 buff[256];      /* Temporary buffer */
-  _cups_globals_t      *cg = _cupsGlobals();
-                                       /* Pointer to library globals */
-  char                 *lang;          /* LANG environment variable */
-
-
- /*
-  * Only do the lookup and translation the first time.
-  */
-
-  if (!cg->language[0])
-  {
-    if ((lang = getenv("LANG")))
-      strlcpy(cg->language, lang, sizeof(cg->language));
     else
-    {
       localizationList =
-          CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
-                                    kCFPreferencesCurrentApplication);
+         CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
+                                   kCFPreferencesCurrentApplication);
 
-      if (localizationList != NULL)
+    if (localizationList)
+    {
+      if (CFGetTypeID(localizationList) == CFArrayGetTypeID() &&
+         CFArrayGetCount(localizationList) > 0)
       {
-       if (CFGetTypeID(localizationList) == CFArrayGetTypeID() &&
-           CFArrayGetCount(localizationList) > 0)
+       languageName = CFArrayGetValueAtIndex(localizationList, 0);
+
+       if (languageName &&
+           CFGetTypeID(languageName) == CFStringGetTypeID())
        {
-         localizationName = CFArrayGetValueAtIndex(localizationList, 0);
+         localeName = CFLocaleCreateCanonicalLocaleIdentifierFromString(
+                          kCFAllocatorDefault, languageName);
 
-         if (localizationName != NULL &&
-              CFGetTypeID(localizationName) == CFStringGetTypeID())
+         if (localeName)
          {
-           CFIndex length = CFStringGetLength(localizationName);
+           CFStringGetCString(localeName, cg->language, sizeof(cg->language),
+                              kCFStringEncodingASCII);
+           CFRelease(localeName);
 
-           if (length <= sizeof(buff) &&
-               CFStringGetCString(localizationName, buff, sizeof(buff),
-                                  kCFStringEncodingASCII))
-           {
-             buff[sizeof(buff) - 1] = '\0';
+           DEBUG_printf(("appleLangDefault: cg->language=\"%s\"\n",
+                         cg->language));
+
+          /*
+           * Map new language identifiers to locales...
+           */
 
-             for (i = 0;
-                  i < sizeof(apple_name_locale) / sizeof(apple_name_locale[0]);
-                  i++)
+           for (i = 0;
+                i < (int)(sizeof(apple_language_locale) /
+                          sizeof(apple_language_locale[0]));
+                i ++)
+           {
+             if (!strcmp(cg->language, apple_language_locale[i].language))
              {
-               if (!strcasecmp(buff, apple_name_locale[i].name))
-               {
-                 strlcpy(cg->language, apple_name_locale[i].locale, 
-                         sizeof(cg->language));
-                 break;
-               }
+               DEBUG_printf(("appleLangDefault: mapping \"%s\" to \"%s\"...\n",
+                             cg->language, apple_language_locale[i].locale));
+               strlcpy(cg->language, apple_language_locale[i].locale, 
+                       sizeof(cg->language));
+               break;
              }
            }
+
+          /*
+           * Convert language subtag into region subtag...
+           */
+
+           if (cg->language[2] == '-')
+             cg->language[2] = '_';
+
+           if (!strchr(cg->language, '.'))
+             strlcat(cg->language, ".UTF-8", sizeof(cg->language));
          }
        }
-
-       CFRelease(localizationList);
       }
+
+      CFRelease(localizationList);
     }
   
    /*
@@ -1209,7 +1186,7 @@ appleLangDefault(void)
     */
 
     if (!cg->language[0])
-      strlcpy(cg->language, apple_name_locale[0].locale, sizeof(cg->language));
+      strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language));
   }
 
  /*
@@ -1218,7 +1195,6 @@ appleLangDefault(void)
 
   return (cg->language);
 }
-#  endif /* HAVE_CF_LOCALE_ID */
 #endif /* __APPLE__ */
 
 
@@ -1326,5 +1302,5 @@ cups_unquote(char       *d,               /* O - Unquoted string */
 
 
 /*
- * End of "$Id: language.c 6188 2007-01-10 16:23:06Z mike $".
+ * End of "$Id: language.c 6916 2007-09-05 21:14:08Z mike $".
  */