]> git.ipfire.org Git - thirdparty/cups.git/blobdiff - cups/language.c
Import CUPS v1.7.1
[thirdparty/cups.git] / cups / language.c
index 2d07c3184df3c55f531ce5e0768894a6aca7a172..0836f6d96f91022bd35676056da9e85bc25fcaab 100644 (file)
@@ -1,9 +1,9 @@
 /*
- * "$Id: language.c 7558 2008-05-12 23:46:44Z mike $"
+ * "$Id: language.c 11424 2013-11-08 19:51:01Z msweet $"
  *
  *   I18N/language support for CUPS.
  *
- *   Copyright 2007-2011 by Apple Inc.
+ *   Copyright 2007-2012 by Apple Inc.
  *   Copyright 1997-2007 by Easy Software Products.
  *
  *   These coded instructions, statements, and computer programs are the
  * Contents:
  *
  *   _cupsAppleLanguage()   - Get the Apple language identifier associated with
- *                            a locale ID.
+ *                           a locale ID.
  *   _cupsEncodingName()    - Return the character encoding name string for the
- *                            given encoding enumeration.
- *   cupsLangDefault()      - Return the default language.
- *   cupsLangEncoding()     - Return the character encoding (us-ascii, etc.) for
- *                            the given language.
- *   cupsLangFlush()        - Flush all language data out of the cache.
- *   cupsLangFree()         - Free language data.
- *   cupsLangGet()          - Get a language.
- *   _cupsLangString()      - Get a message string.
+ *                           given encoding enumeration.
+ *   cupsLangDefault()     - Return the default language.
+ *   cupsLangEncoding()     - Return the character encoding (us-ascii, etc.)
+ *                           for the given language.
+ *   cupsLangFlush()       - Flush all language data out of the cache.
+ *   cupsLangFree()        - Free language data.
+ *   cupsLangGet()         - Get a language.
+ *   _cupsLangString()     - Get a message string.
  *   _cupsMessageFree()     - Free a messages array.
  *   _cupsMessageLoad()     - Load a .po file into a messages array.
  *   _cupsMessageLookup()   - Lookup a message string.
+ *   _cupsMessageNew()     - Make a new message catalog array.
  *   appleLangDefault()     - Get the default locale string.
  *   appleMessageLoad()     - Load a message catalog from a localizable bundle.
  *   cups_cache_lookup()    - Lookup a language in the cache...
  *   cups_message_compare() - Compare two messages.
  *   cups_message_free()    - Free a message.
- *   cups_unquote()         - Unquote characters in strings...
+ *   cups_message_load()    - Load the message catalog for a language.
+ *   cups_unquote()        - Unquote characters in strings...
  */
 
 /*
@@ -80,7 +82,7 @@ static const char * const lang_encodings[] =
                          "cp1256",             "cp1257",
                          "cp1258",             "koi8-r",
                          "koi8-u",             "iso-8859-11",
-                         "iso-8859-16",        "mac-roman",
+                         "iso-8859-16",        "mac",
                          "unknown",            "unknown",
                          "unknown",            "unknown",
                          "unknown",            "unknown",
@@ -132,7 +134,7 @@ static const char * const lang_encodings[] =
                          "unknown",            "unknown",
                          "euc-cn",             "euc-jp",
                          "euc-kr",             "euc-tw",
-                         "jis-x0213"
+                         "shift_jisx0213"
                        };
 
 #ifdef __APPLE__
@@ -156,10 +158,19 @@ static const _apple_language_locale_t apple_language_locale[] =
  * Local functions...
  */
 
+
 #ifdef __APPLE__
 static const char      *appleLangDefault(void);
 #  ifdef CUPS_BUNDLEDIR
-static cups_array_t    *appleMessageLoad(const char *locale);
+#    ifndef CF_RETURNS_RETAINED
+#      if __has_feature(attribute_cf_returns_retained)
+#        define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#      else
+#        define CF_RETURNS_RETAINED
+#      endif /* __has_feature(attribute_cf_returns_retained) */
+#    endif /* !CF_RETURNED_RETAINED */
+static cups_array_t    *appleMessageLoad(const char *locale)
+                       CF_RETURNS_RETAINED;
 #  endif /* CUPS_BUNDLEDIR */
 #endif /* __APPLE__ */
 static cups_lang_t     *cups_cache_lookup(const char *name,
@@ -167,6 +178,7 @@ static cups_lang_t  *cups_cache_lookup(const char *name,
 static int             cups_message_compare(_cups_message_t *m1,
                                             _cups_message_t *m2);
 static void            cups_message_free(_cups_message_t *m);
+static void            cups_message_load(cups_lang_t *lang);
 static void            cups_unquote(char *d, const char *s);
 
 
@@ -384,11 +396,6 @@ cupsLangGet(const char *language)  /* I - Language or locale */
                        real[48];       /* Real language name */
   cups_encoding_t      encoding;       /* Encoding to use */
   cups_lang_t          *lang;          /* Current language... */
-#if !defined(__APPLE__) || !defined(CUPS_BUNDLEDIR)
-  char                 filename[1024]; /* Filename for language locale file */
-  _cups_globals_t      *cg = _cupsGlobals();
-                                       /* Pointer to library globals */
-#endif /* !__APPLE__ || !CUPS_BUNDLEDIR */
   static const char * const locale_encodings[] =
                {                       /* Locale charset names */
                  "ASCII",      "ISO88591",     "ISO88592",     "ISO88593",
@@ -439,10 +446,10 @@ cupsLangGet(const char *language) /* I - Language or locale */
   * Set the character set to UTF-8...
   */
 
-  strcpy(charset, "UTF8");
+  strlcpy(charset, "UTF8", sizeof(charset));
 
  /*
-  * Apple's setlocale doesn't give us the user's localization 
+  * Apple's setlocale doesn't give us the user's localization
   * preference so we have to look it up this way...
   */
 
@@ -575,7 +582,7 @@ cupsLangGet(const char *language)   /* I - Language or locale */
   */
 
   if (!charset[0])
-    strcpy(charset, "UTF8");
+    strlcpy(charset, "UTF8", sizeof(charset));
 
  /*
   * Parse the language string passed in to a locale string. "C" is the
@@ -590,7 +597,7 @@ cupsLangGet(const char *language)   /* I - Language or locale */
 
   if (language == NULL || !language[0] ||
       !strcmp(language, "POSIX"))
-    strcpy(langname, "C");
+    strlcpy(langname, "C", sizeof(langname));
   else
   {
    /*
@@ -639,7 +646,7 @@ cupsLangGet(const char *language)   /* I - Language or locale */
 
     if (strlen(langname) != 2)
     {
-      strcpy(langname, "C");
+      strlcpy(langname, "C", sizeof(langname));
       country[0] = '\0';
       charset[0] = '\0';
     }
@@ -659,7 +666,7 @@ cupsLangGet(const char *language)   /* I - Language or locale */
     for (i = 0;
          i < (int)(sizeof(locale_encodings) / sizeof(locale_encodings[0]));
         i ++)
-      if (!strcasecmp(charset, locale_encodings[i]))
+      if (!_cups_strcasecmp(charset, locale_encodings[i]))
       {
        encoding = (cups_encoding_t)i;
        break;
@@ -671,14 +678,14 @@ cupsLangGet(const char *language) /* I - Language or locale */
       * Map alternate names for various character sets...
       */
 
-      if (!strcasecmp(charset, "iso-2022-jp") ||
-          !strcasecmp(charset, "sjis"))
+      if (!_cups_strcasecmp(charset, "iso-2022-jp") ||
+          !_cups_strcasecmp(charset, "sjis"))
        encoding = CUPS_WINDOWS_932;
-      else if (!strcasecmp(charset, "iso-2022-cn"))
+      else if (!_cups_strcasecmp(charset, "iso-2022-cn"))
        encoding = CUPS_WINDOWS_936;
-      else if (!strcasecmp(charset, "iso-2022-kr"))
+      else if (!_cups_strcasecmp(charset, "iso-2022-kr"))
        encoding = CUPS_WINDOWS_949;
-      else if (!strcasecmp(charset, "big5"))
+      else if (!_cups_strcasecmp(charset, "big5"))
        encoding = CUPS_WINDOWS_950;
     }
   }
@@ -692,21 +699,9 @@ cupsLangGet(const char *language)  /* I - Language or locale */
   */
 
   if (country[0])
-  {
     snprintf(real, sizeof(real), "%s_%s", langname, country);
-
-#if !defined(__APPLE__) || !defined(CUPS_BUNDLEDIR)
-    snprintf(filename, sizeof(filename), "%s/%s/cups_%s.po", cg->localedir,
-             real, real);
-#endif /* !__APPLE__ || !CUPS_BUNDLEDIR */
-  }
   else
-  {
-    strcpy(real, langname);
-#if !defined(__APPLE__) || !defined(CUPS_BUNDLEDIR)
-    filename[0] = '\0';                        /* anti-compiler-warning-code */
-#endif /* !__APPLE__ || !CUPS_BUNDLEDIR */
-  }
+    strlcpy(real, langname, sizeof(real));
 
   _cupsMutexLock(&lang_mutex);
 
@@ -719,30 +714,6 @@ cupsLangGet(const char *language)  /* I - Language or locale */
     return (lang);
   }
 
-#if !defined(__APPLE__) || !defined(CUPS_BUNDLEDIR)
-  if (!country[0] || access(filename, 0))
-  {
-   /*
-    * Country localization not available, look for generic localization...
-    */
-
-    snprintf(filename, sizeof(filename), "%s/%s/cups_%s.po", cg->localedir,
-             langname, langname);
-
-    if (access(filename, 0))
-    {
-     /*
-      * No generic localization, so use POSIX...
-      */
-
-      DEBUG_printf(("4cupsLangGet: access(\"%s\", 0): %s", filename,
-                    strerror(errno)));
-
-      snprintf(filename, sizeof(filename), "%s/C/cups_C.po", cg->localedir);
-    }
-  }
-#endif /* !__APPLE__ || !CUPS_BUNDLEDIR */
-
  /*
   * See if there is a free language available; if so, use that
   * record...
@@ -775,6 +746,7 @@ cupsLangGet(const char *language)   /* I - Language or locale */
     */
 
     _cupsMessageFree(lang->strings);
+    lang->strings = NULL;
   }
 
  /*
@@ -789,16 +761,6 @@ cupsLangGet(const char *language)  /* I - Language or locale */
   else
     lang->encoding = CUPS_UTF8;
 
- /*
-  * Read the strings from the file...
-  */
-
-#if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
-  lang->strings = appleMessageLoad(lang->language);
-#else
-  lang->strings = _cupsMessageLoad(filename, 1);
-#endif /* __APPLE__ && CUPS_BUNDLEDIR */
-
  /*
   * Return...
   */
@@ -826,11 +788,18 @@ _cupsLangString(cups_lang_t *lang,        /* I - Language */
   * Range check input...
   */
 
-  if (!lang || !message)
+  if (!lang || !message || !*message)
     return (message);
 
   _cupsMutexLock(&lang_mutex);
 
+ /*
+  * Load the message catalog if needed...
+  */
+
+  if (!lang->strings)
+    cups_message_load(lang);
+
   s = _cupsMessageLookup(lang->strings, message);
 
   _cupsMutexUnlock(&lang_mutex);
@@ -878,6 +847,7 @@ _cupsMessageLoad(const char *filename,      /* I - Message catalog to load */
                        *ptr,           /* Pointer into buffer */
                        *temp;          /* New string */
   int                  length;         /* Length of combined strings */
+  size_t               ptrlen;         /* Length of string */
 
 
   DEBUG_printf(("4_cupsMessageLoad(filename=\"%s\")", filename));
@@ -886,10 +856,7 @@ _cupsMessageLoad(const char *filename,     /* I - Message catalog to load */
   * Create an array to hold the messages...
   */
 
-  if ((a = cupsArrayNew3((cups_array_func_t)cups_message_compare, NULL,
-                         (cups_ahash_func_t)NULL, 0,
-                        (cups_acopy_func_t)NULL,
-                        (cups_afree_func_t)cups_message_free)) == NULL)
+  if ((a = _cupsMessageNew(NULL)) == NULL)
   {
     DEBUG_puts("5_cupsMessageLoad: Unable to allocate array!");
     return (NULL);
@@ -946,7 +913,7 @@ _cupsMessageLoad(const char *filename,      /* I - Message catalog to load */
    /*
     * Find start of value...
     */
-    
+
     if ((ptr = strchr(s, '\"')) == NULL)
       continue;
 
@@ -970,7 +937,23 @@ _cupsMessageLoad(const char *filename,     /* I - Message catalog to load */
       */
 
       if (m)
-        cupsArrayAdd(a, m);
+      {
+        if (m->str && m->str[0])
+        {
+          cupsArrayAdd(a, m);
+        }
+        else
+        {
+         /*
+          * Translation is empty, don't add it... (STR #4033)
+          */
+
+          free(m->id);
+          if (m->str)
+            free(m->str);
+          free(m);
+        }
+      }
 
      /*
       * Create a new message with the given msgid string...
@@ -996,10 +979,16 @@ _cupsMessageLoad(const char *filename,    /* I - Message catalog to load */
       */
 
       length = (int)strlen(m->str ? m->str : m->id);
+      ptrlen = strlen(ptr);
 
       if ((temp = realloc(m->str ? m->str : m->id,
-                          length + strlen(ptr) + 1)) == NULL)
+                          length + ptrlen + 1)) == NULL)
       {
+        if (m->str)
+         free(m->str);
+       free(m->id);
+        free(m);
+
        cupsFileClose(fp);
        return (a);
       }
@@ -1008,25 +997,25 @@ _cupsMessageLoad(const char *filename,   /* I - Message catalog to load */
       {
        /*
         * Copy the new portion to the end of the msgstr string - safe
-       * to use strcpy because the buffer is allocated to the correct
+       * to use memcpy because the buffer is allocated to the correct
        * size...
        */
 
         m->str = temp;
 
-       strcpy(m->str + length, ptr);
+       memcpy(m->str + length, ptr, ptrlen + 1);
       }
       else
       {
        /*
         * Copy the new portion to the end of the msgid string - safe
-       * to use strcpy because the buffer is allocated to the correct
+       * to use memcpy because the buffer is allocated to the correct
        * size...
        */
 
         m->id = temp;
 
-       strcpy(m->id + length, ptr);
+       memcpy(m->id + length, ptr, ptrlen + 1);
       }
     }
     else if (!strncmp(s, "msgstr", 6) && m)
@@ -1037,6 +1026,9 @@ _cupsMessageLoad(const char *filename,    /* I - Message catalog to load */
 
       if ((m->str = strdup(ptr)) == NULL)
       {
+       free(m->id);
+        free(m);
+
         cupsFileClose(fp);
        return (a);
       }
@@ -1048,7 +1040,23 @@ _cupsMessageLoad(const char *filename,   /* I - Message catalog to load */
   */
 
   if (m)
-    cupsArrayAdd(a, m);
+  {
+    if (m->str && m->str[0])
+    {
+      cupsArrayAdd(a, m);
+    }
+    else
+    {
+     /*
+      * Translation is empty, don't add it... (STR #4033)
+      */
+
+      free(m->id);
+      if (m->str)
+       free(m->str);
+      free(m);
+    }
+  }
 
  /*
   * Close the message catalog file and return the new array...
@@ -1107,10 +1115,17 @@ _cupsMessageLookup(cups_array_t *a,     /* I - Message array */
 
       CFStringGetCString(cfstr, buffer, sizeof(buffer), kCFStringEncodingUTF8);
       match->str = strdup(buffer);
+
+      DEBUG_printf(("1_cupsMessageLookup: Found \"%s\" as \"%s\"...",
+                    m, buffer));
     }
     else
+    {
       match->str = strdup(m);
 
+      DEBUG_printf(("1_cupsMessageLookup: Did not find \"%s\"...", m));
+    }
+
     cupsArrayAdd(a, match);
 
     if (cfm)
@@ -1125,6 +1140,20 @@ _cupsMessageLookup(cups_array_t *a,      /* I - Message array */
 }
 
 
+/*
+ * '_cupsMessageNew()' - Make a new message catalog array.
+ */
+
+cups_array_t *                         /* O - Array */
+_cupsMessageNew(void *context)         /* I - User data */
+{
+  return (cupsArrayNew3((cups_array_func_t)cups_message_compare, context,
+                        (cups_ahash_func_t)NULL, 0,
+                       (cups_acopy_func_t)NULL,
+                       (cups_afree_func_t)cups_message_free));
+}
+
+
 #ifdef __APPLE__
 /*
  * 'appleLangDefault()' - Get the default locale string.
@@ -1155,24 +1184,40 @@ appleLangDefault(void)
   {
     if (getenv("SOFTWARE") != NULL && (lang = getenv("LANG")) != NULL)
     {
+      DEBUG_printf(("3appleLangDefault: Using LANG=%s", lang));
       strlcpy(cg->language, lang, sizeof(cg->language));
       return (cg->language);
     }
     else if ((bundle = CFBundleGetMainBundle()) != NULL &&
              (bundleList = CFBundleCopyBundleLocalizations(bundle)) != NULL)
     {
+      DEBUG_puts("3appleLangDefault: Getting localizationList from bundle.");
+
       localizationList =
          CFBundleCopyPreferredLocalizationsFromArray(bundleList);
 
       CFRelease(bundleList);
     }
     else
+    {
+      DEBUG_puts("3appleLangDefault: Getting localizationList from preferences.");
+
       localizationList =
          CFPreferencesCopyAppValue(CFSTR("AppleLanguages"),
                                    kCFPreferencesCurrentApplication);
+    }
 
     if (localizationList)
     {
+
+#ifdef DEBUG
+      if (CFGetTypeID(localizationList) == CFArrayGetTypeID())
+        DEBUG_printf(("3appleLangDefault: Got localizationList, %d entries.",
+                      (int)CFArrayGetCount(localizationList)));
+      else
+        DEBUG_puts("3appleLangDefault: Got localizationList but not an array.");
+#endif /* DEBUG */
+
       if (CFGetTypeID(localizationList) == CFArrayGetTypeID() &&
          CFArrayGetCount(localizationList) > 0)
       {
@@ -1190,7 +1235,7 @@ appleLangDefault(void)
                               kCFStringEncodingASCII);
            CFRelease(localeName);
 
-           DEBUG_printf(("9appleLangDefault: cg->language=\"%s\"",
+           DEBUG_printf(("3appleLangDefault: cg->language=\"%s\"",
                          cg->language));
 
           /*
@@ -1204,9 +1249,9 @@ appleLangDefault(void)
            {
              if (!strcmp(cg->language, apple_language_locale[i].language))
              {
-               DEBUG_printf(("9appleLangDefault: mapping \"%s\" to \"%s\"...",
+               DEBUG_printf(("3appleLangDefault: mapping \"%s\" to \"%s\"...",
                              cg->language, apple_language_locale[i].locale));
-               strlcpy(cg->language, apple_language_locale[i].locale, 
+               strlcpy(cg->language, apple_language_locale[i].locale,
                        sizeof(cg->language));
                break;
              }
@@ -1222,18 +1267,23 @@ appleLangDefault(void)
            if (!strchr(cg->language, '.'))
              strlcat(cg->language, ".UTF-8", sizeof(cg->language));
          }
+         else
+           DEBUG_puts("3appleLangDefault: Unable to get localeName.");
        }
       }
 
       CFRelease(localizationList);
     }
-  
+
    /*
     * If we didn't find the language, default to en_US...
     */
 
     if (!cg->language[0])
+    {
+      DEBUG_puts("3appleLangDefault: Defaulting to en_US.");
       strlcpy(cg->language, "en_US.UTF-8", sizeof(cg->language));
+    }
   }
 
  /*
@@ -1245,27 +1295,24 @@ appleLangDefault(void)
 
 
 #  ifdef CUPS_BUNDLEDIR
-#    ifndef CF_RETURNS_RETAINED
-#      if __has_feature(attribute_cf_returns_retained)
-#        define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
-#      else
-#        define CF_RETURNS_RETAINED
-#      endif /* __has_feature(attribute_cf_returns_retained) */
-#    endif /* !CF_RETURNED_RETAINED */
-
 /*
  * 'appleMessageLoad()' - Load a message catalog from a localizable bundle.
  */
 
 static cups_array_t *                  /* O - Message catalog */
 appleMessageLoad(const char *locale)   /* I - Locale ID */
-CF_RETURNS_RETAINED
 {
   char                 filename[1024], /* Path to cups.strings file */
                        applelang[256]; /* Apple language ID */
   CFURLRef             url;            /* URL to cups.strings file */
-  CFReadStreamRef      stream;         /* File */
-  CFDictionaryRef      dict;           /* Localization dictionary */
+  CFReadStreamRef      stream = NULL;  /* File stream */
+  CFPropertyListRef    plist = NULL;   /* Localization file */
+#ifdef DEBUG
+  CFErrorRef           error = NULL;   /* Error when opening file */
+#endif /* DEBUG */
+
+
+  DEBUG_printf(("appleMessageLoad(locale=\"%s\")", locale));
 
  /*
   * Load the cups.strings file...
@@ -1274,26 +1321,95 @@ CF_RETURNS_RETAINED
   snprintf(filename, sizeof(filename),
            CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings",
           _cupsAppleLanguage(locale, applelang, sizeof(applelang)));
+  DEBUG_printf(("1appleMessageLoad: filename=\"%s\"", filename));
 
-  url    = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
-                                                   (UInt8 *)filename,
-                                                  strlen(filename), false);
-  stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
-  dict   = (CFDictionaryRef)CFPropertyListCreateWithStream(
-              kCFAllocatorDefault, stream, 0, kCFPropertyListImmutable, NULL,
-              NULL);
-  CFRelease(stream);
-  CFRelease(url);
+  if (access(filename, 0))
+  {
+   /*
+    * Try alternate lproj directory names...
+    */
+
+    if (!strncmp(locale, "en", 2))
+      locale = "English";
+    else if (!strncmp(locale, "nb", 2) || !strncmp(locale, "nl", 2))
+      locale = "Dutch";
+    else if (!strncmp(locale, "fr", 2))
+      locale = "French";
+    else if (!strncmp(locale, "de", 2))
+      locale = "German";
+    else if (!strncmp(locale, "it", 2))
+      locale = "Italian";
+    else if (!strncmp(locale, "ja", 2))
+      locale = "Japanese";
+    else if (!strncmp(locale, "es", 2))
+      locale = "Spanish";
+
+    snprintf(filename, sizeof(filename),
+            CUPS_BUNDLEDIR "/Resources/%s.lproj/cups.strings", locale);
+    DEBUG_printf(("1appleMessageLoad: alternate filename=\"%s\"", filename));
+  }
+
+  url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
+                                                (UInt8 *)filename,
+                                               strlen(filename), false);
+  if (url)
+  {
+    stream = CFReadStreamCreateWithFile(kCFAllocatorDefault, url);
+    if (stream)
+    {
+     /*
+      * Read the property list containing the localization data.
+      *
+      * NOTE: This code currently generates a clang "potential leak"
+      * warning, but the object is released in _cupsMessageFree().
+      */
+
+      CFReadStreamOpen(stream);
+
+#ifdef DEBUG
+      plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0,
+                                             kCFPropertyListImmutable, NULL,
+                                             &error);
+      if (error)
+      {
+        CFStringRef    msg = CFErrorCopyDescription(error);
+                                       /* Error message */
+
+        CFStringGetCString(msg, filename, sizeof(filename),
+                           kCFStringEncodingUTF8);
+        DEBUG_printf(("1appleMessageLoad: %s", filename));
+
+       CFRelease(msg);
+        CFRelease(error);
+      }
+
+#else
+      plist = CFPropertyListCreateWithStream(kCFAllocatorDefault, stream, 0,
+                                             kCFPropertyListImmutable, NULL,
+                                             NULL);
+#endif /* DEBUG */
+
+      if (plist && CFGetTypeID(plist) != CFDictionaryGetTypeID())
+      {
+         CFRelease(plist);
+         plist = NULL;
+      }
+
+      CFRelease(stream);
+    }
+
+    CFRelease(url);
+  }
+
+  DEBUG_printf(("1appleMessageLoad: url=%p, stream=%p, plist=%p", url, stream,
+                plist));
 
  /*
   * Create and return an empty array to act as a cache for messages, passing the
-  * dictionary as the user data.
+  * plist as the user data.
   */
 
-  return (cupsArrayNew3((cups_array_func_t)cups_message_compare, (void *)dict,
-                        (cups_ahash_func_t)NULL, 0,
-                       (cups_acopy_func_t)NULL,
-                       (cups_afree_func_t)cups_message_free));
+  return (_cupsMessageNew((void *)plist));
 }
 #  endif /* CUPS_BUNDLEDIR */
 #endif /* __APPLE__ */
@@ -1372,6 +1488,56 @@ cups_message_free(_cups_message_t *m)    /* I - Message */
 }
 
 
+/*
+ * 'cups_message_load()' - Load the message catalog for a language.
+ */
+
+static void
+cups_message_load(cups_lang_t *lang)   /* I - Language */
+{
+#if defined(__APPLE__) && defined(CUPS_BUNDLEDIR)
+  lang->strings = appleMessageLoad(lang->language);
+
+#else
+  char                 filename[1024]; /* Filename for language locale file */
+  _cups_globals_t      *cg = _cupsGlobals();
+                                       /* Pointer to library globals */
+
+
+  snprintf(filename, sizeof(filename), "%s/%s/cups_%s.po", cg->localedir,
+          lang->language, lang->language);
+
+  if (strchr(lang->language, '_') && access(filename, 0))
+  {
+   /*
+    * Country localization not available, look for generic localization...
+    */
+
+    snprintf(filename, sizeof(filename), "%s/%.2s/cups_%.2s.po", cg->localedir,
+             lang->language, lang->language);
+
+    if (access(filename, 0))
+    {
+     /*
+      * No generic localization, so use POSIX...
+      */
+
+      DEBUG_printf(("4cups_message_load: access(\"%s\", 0): %s", filename,
+                    strerror(errno)));
+
+      snprintf(filename, sizeof(filename), "%s/C/cups_C.po", cg->localedir);
+    }
+  }
+
+ /*
+  * Read the strings from the file...
+  */
+
+  lang->strings = _cupsMessageLoad(filename, 1);
+#endif /* __APPLE__ && CUPS_BUNDLEDIR */
+}
+
+
 /*
  * 'cups_unquote()' - Unquote characters in strings...
  */
@@ -1420,5 +1586,5 @@ cups_unquote(char       *d,               /* O - Unquoted string */
 
 
 /*
- * End of "$Id: language.c 7558 2008-05-12 23:46:44Z mike $".
+ * End of "$Id: language.c 11424 2013-11-08 19:51:01Z msweet $".
  */