[BREAK] add possibility to download and use multiply
authorDavid Kalnischkies <kalnischkies@gmail.com>
Thu, 26 Nov 2009 21:23:08 +0000 (22:23 +0100)
committerDavid Kalnischkies <kalnischkies@gmail.com>
Thu, 26 Nov 2009 21:23:08 +0000 (22:23 +0100)
Translation files, configurable with Acquire::Languages
accessable with APT::Configuration::getLanguages() and
as always with documentation in apt.conf.
The commit also includes a very very simple testapp.

14 files changed:
apt-pkg/aptconfiguration.cc
apt-pkg/aptconfiguration.h
apt-pkg/deb/debindexfile.cc
apt-pkg/deb/debindexfile.h
apt-pkg/deb/deblistparser.cc
apt-pkg/deb/debmetaindex.cc
apt-pkg/deb/debrecords.cc
apt-pkg/indexfile.cc
apt-pkg/pkgcache.cc
debian/changelog
doc/apt.conf.5.xml
doc/examples/configure-index
test/libapt/getlanguages_test.cc [new file with mode: 0644]
test/libapt/makefile [new file with mode: 0644]

index 45ae9be..899004d 100644 (file)
@@ -87,4 +87,140 @@ const Configuration::getCompressionTypes(bool const &Cached) {
        return types;
 }
                                                                        /*}}}*/
+// GetLanguages - Return Vector of Language Codes                      /*{{{*/
+// ---------------------------------------------------------------------
+/* return a vector of language codes in the prefered order.
+   the special word "environment" will be replaced with the long and the short
+   code of the local settings and it will be insured that this will not add
+   duplicates. So in an german local the setting "environment, de_DE, en, de"
+   will result in "de_DE, de, en".
+   The special word "none" is the stopcode for the not-All code vector */
+std::vector<std::string> const Configuration::getLanguages(bool const &All,
+                               bool const &Cached, char const * const Locale) {
+       using std::string;
+
+       // The detection is boring and has a lot of cornercases,
+       // so we cache the results to calculated it only once.
+       std::vector<string> static allCodes;
+       std::vector<string> static codes;
+
+       // we have something in the cache
+       if (codes.empty() == false || allCodes.empty() == false) {
+               if (Cached == true) {
+                       if(All == true && allCodes.empty() == false)
+                               return allCodes;
+                       else
+                               return codes;
+               } else {
+                       allCodes.clear();
+                       codes.clear();
+               }
+       }
+
+       // get the environment language code
+       // we extract both, a long and a short code and then we will
+       // check if we actually need both (rare) or if the short is enough
+       string const envMsg = string(Locale == 0 ? std::setlocale(LC_MESSAGES, NULL) : Locale);
+       size_t const lenShort = (envMsg.find('_') != string::npos) ? envMsg.find('_') : 2;
+       size_t const lenLong = (envMsg.find('.') != string::npos) ? envMsg.find('.') : (lenShort + 3);
+
+       string envLong = envMsg.substr(0,lenLong);
+       string const envShort = envLong.substr(0,lenShort);
+       bool envLongIncluded = true, envShortIncluded = false;
+
+       // first cornercase: LANG=C, so we use only "en" Translation
+       if (envLong == "C") {
+               codes.push_back("en");
+               return codes;
+       }
+
+       if (envLong != envShort) {
+               // to save the servers from unneeded queries, we only try also long codes
+               // for languages it is realistic to have a long code translation file...
+               char const *needLong[] = { "cs", "en", "pt", "sv", "zh", NULL };
+               for (char const **l = needLong; *l != NULL; l++)
+                       if (envShort.compare(*l) == 0) {
+                               envLongIncluded = false;
+                               break;
+                       }
+       }
+
+       // we don't add the long code, but we allow the user to do so
+       if (envLongIncluded == true)
+               envLong.clear();
+
+       // FIXME: Remove support for the old APT::Acquire::Translation
+       // it was undocumented and so it should be not very widthly used
+       string const oldAcquire = _config->Find("APT::Acquire::Translation","");
+       if (oldAcquire.empty() == false && oldAcquire != "environment") {
+               if (oldAcquire != "none")
+                       codes.push_back(oldAcquire);
+               return codes;
+       }
+
+       // Support settings like Acquire::Translation=none on the command line to
+       // override the configuration settings vector of languages.
+       string const forceLang = _config->Find("Acquire::Languages","");
+       if (forceLang.empty() == false) {
+               if (forceLang == "environment") {
+                       if (envLongIncluded == false)
+                               codes.push_back(envLong);
+                       if (envShortIncluded == false)
+                               codes.push_back(envShort);
+                       return codes;
+               } else if (forceLang != "none")
+                       codes.push_back(forceLang);
+               return codes;
+       }
+
+       std::vector<string> const lang = _config->FindVector("Acquire::Languages");
+       // the default setting -> "environment, en"
+       if (lang.empty() == true) {
+               if (envLongIncluded == false)
+                       codes.push_back(envLong);
+               if (envShortIncluded == false)
+                       codes.push_back(envShort);
+               if (envShort != "en")
+                       codes.push_back("en");
+               return codes;
+       }
+
+       // the configs define the order, so add the environment
+       // then needed and ensure the codes are not listed twice.
+       bool noneSeen = false;
+       for (std::vector<string>::const_iterator l = lang.begin();
+            l != lang.end(); l++) {
+               if (*l == "environment") {
+                       if (envLongIncluded == true && envShortIncluded == true)
+                               continue;
+                       if (envLongIncluded == false) {
+                               envLongIncluded = true;
+                               if (noneSeen == false)
+                                       codes.push_back(envLong);
+                               allCodes.push_back(envLong);
+                       }
+                       if (envShortIncluded == false) {
+                               envShortIncluded = true;
+                               if (noneSeen == false)
+                                       codes.push_back(envShort);
+                               allCodes.push_back(envShort);
+                       }
+                       continue;
+               } else if (*l == "none") {
+                       noneSeen = true;
+                       continue;
+               } else if ((envLongIncluded == true && *l == envLong) ||
+                        (envShortIncluded == true && *l == envShort))
+                       continue;
+
+               if (noneSeen == false)
+                       codes.push_back(*l);
+               allCodes.push_back(*l);
+       }
+       if (All == true)
+               return allCodes;
+       else
+               return codes;
+}
+                                                                       /*}}}*/
 }
index 6a123ad..f2f04a3 100644 (file)
@@ -39,6 +39,33 @@ public:                                                                      /*{{{*/
         *  \return a vector of (all) Language Codes in the prefered usage order
         */
        std::vector<std::string> static const getCompressionTypes(bool const &Cached = true);
+
+       /** \brief Returns a vector of Language Codes
+        *
+        *  Languages can be defined with their two or five chars long code.
+        *  This methods handles the various ways to set the prefered codes,
+        *  honors the environment and ensures that the codes are not listed twice.
+        *
+        *  The special word "environment" will be replaced with the long and the short
+        *  code of the local settings and it will be insured that this will not add
+        *  duplicates. So in an german local the setting "environment, de_DE, en, de"
+        *  will result in "de_DE, de, en".
+        *
+        *  Another special word is "none" which separates the prefered from all codes
+        *  in this setting. So setting and method can be used to get codes the user want
+        *  to see or to get all language codes APT (should) have Translations available.
+        *
+        *  \param All return all codes or only codes for languages we want to use
+        *  \param Cached saves the result so we need to calculated it only once
+        *                this parameter should ony be used for testing purposes.
+        *  \param Locale don't get the locale from the system but use this one instead
+        *                this parameter should ony be used for testing purposes.
+        *
+        *  \return a vector of (all) Language Codes in the prefered usage order
+        */
+       std::vector<std::string> static const getLanguages(bool const &All = false,
+                       bool const &Cached = true, char const * const Locale = 0);
+
                                                                        /*}}}*/
 };
                                                                        /*}}}*/
index ed76338..5beb836 100644 (file)
@@ -319,10 +319,11 @@ pkgCache::PkgFileIterator debPackagesIndex::FindInCache(pkgCache &Cache) const
 // TranslationsIndex::debTranslationsIndex - Contructor                        /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-debTranslationsIndex::debTranslationsIndex(string URI,string Dist,string Section) : 
-                  pkgIndexFile(true), URI(URI), Dist(Dist), Section(Section)
-{
-}
+debTranslationsIndex::debTranslationsIndex(string URI,string Dist,string Section,
+                                               char const * const Translation) :
+                       pkgIndexFile(true), URI(URI), Dist(Dist), Section(Section),
+                               Language(Translation)
+{}
                                                                        /*}}}*/
 // TranslationIndex::Trans* - Return the URI to the translation files  /*{{{*/
 // ---------------------------------------------------------------------
@@ -355,8 +356,8 @@ string debTranslationsIndex::IndexURI(const char *Type) const
 bool debTranslationsIndex::GetIndexes(pkgAcquire *Owner) const
 {
    if (TranslationsAvailable()) {
-     string TranslationFile = "Translation-" + LanguageCode();
-     new pkgAcqIndexTrans(Owner, IndexURI(LanguageCode().c_str()),
+     string const TranslationFile = string("Translation-").append(Language);
+     new pkgAcqIndexTrans(Owner, IndexURI(Language),
                          Info(TranslationFile.c_str()),
                          TranslationFile);
    }
@@ -375,7 +376,7 @@ string debTranslationsIndex::Describe(bool Short) const
       snprintf(S,sizeof(S),"%s",Info(TranslationFile().c_str()).c_str());
    else
       snprintf(S,sizeof(S),"%s (%s)",Info(TranslationFile().c_str()).c_str(),
-              IndexFile(LanguageCode().c_str()).c_str());
+              IndexFile(Language).c_str());
    return S;
 }
                                                                        /*}}}*/
@@ -397,20 +398,20 @@ string debTranslationsIndex::Info(const char *Type) const
    return Info;
 }
                                                                        /*}}}*/
-bool debTranslationsIndex::HasPackages() const
+bool debTranslationsIndex::HasPackages() const                         /*{{{*/
 {
    if(!TranslationsAvailable())
       return false;
    
-   return FileExists(IndexFile(LanguageCode().c_str()));
+   return FileExists(IndexFile(Language));
 }
-
+                                                                       /*}}}*/
 // TranslationsIndex::Exists - Check if the index is available         /*{{{*/
 // ---------------------------------------------------------------------
 /* */
 bool debTranslationsIndex::Exists() const
 {
-   return FileExists(IndexFile(LanguageCode().c_str()));
+   return FileExists(IndexFile(Language));
 }
                                                                        /*}}}*/
 // TranslationsIndex::Size - Return the size of the index              /*{{{*/
@@ -419,7 +420,7 @@ bool debTranslationsIndex::Exists() const
 unsigned long debTranslationsIndex::Size() const
 {
    struct stat S;
-   if (stat(IndexFile(LanguageCode().c_str()).c_str(),&S) != 0)
+   if (stat(IndexFile(Language).c_str(),&S) != 0)
       return 0;
    return S.st_size;
 }
@@ -430,7 +431,7 @@ unsigned long debTranslationsIndex::Size() const
 bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
 {
    // Check the translation file, if in use
-   string TranslationFile = IndexFile(LanguageCode().c_str());
+   string TranslationFile = IndexFile(Language);
    if (TranslationsAvailable() && FileExists(TranslationFile))
    {
      FileFd Trans(TranslationFile,FileFd::ReadOnly);
@@ -462,7 +463,7 @@ bool debTranslationsIndex::Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const
 /* */
 pkgCache::PkgFileIterator debTranslationsIndex::FindInCache(pkgCache &Cache) const
 {
-   string FileName = IndexFile(LanguageCode().c_str());
+   string FileName = IndexFile(Language);
    
    pkgCache::PkgFileIterator File = Cache.FileBegin();
    for (; File.end() == false; File++)
index b0012c9..c0e8d7d 100644 (file)
@@ -77,12 +77,13 @@ class debTranslationsIndex : public pkgIndexFile
    string URI;
    string Dist;
    string Section;
+   const char * const Language;
    
    string Info(const char *Type) const;
    string IndexFile(const char *Type) const;
    string IndexURI(const char *Type) const;
 
-   inline string TranslationFile() const {return "Translation-" + LanguageCode();};
+   inline string TranslationFile() const {return string("Translation-").append(Language);};
 
    public:
    
@@ -99,7 +100,7 @@ class debTranslationsIndex : public pkgIndexFile
    virtual bool Merge(pkgCacheGenerator &Gen,OpProgress &Prog) const;
    virtual pkgCache::PkgFileIterator FindInCache(pkgCache &Cache) const;
 
-   debTranslationsIndex(string URI,string Dist,string Section);
+   debTranslationsIndex(string URI,string Dist,string Section, char const * const Language);
 };
 
 class debSourcesIndex : public pkgIndexFile
index 517b771..16e6ee3 100644 (file)
@@ -13,6 +13,7 @@
 #include <apt-pkg/deblistparser.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/crc-16.h>
 #include <apt-pkg/md5.h>
@@ -129,10 +130,11 @@ bool debListParser::NewVersion(pkgCache::VerIterator Ver)
    only describe package properties */
 string debListParser::Description()
 {
-   if (DescriptionLanguage().empty())
+   string const lang = DescriptionLanguage();
+   if (lang.empty())
       return Section.FindS("Description");
    else
-      return Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str());
+      return Section.FindS(string("Description-").append(lang).c_str());
 }
                                                                         /*}}}*/
 // ListParser::DescriptionLanguage - Return the description lang string        /*{{{*/
@@ -142,7 +144,16 @@ string debListParser::Description()
    assumed to describe original description. */
 string debListParser::DescriptionLanguage()
 {
-   return Section.FindS("Description").empty() ? pkgIndexFile::LanguageCode() : "";
+   if (Section.FindS("Description").empty() == false)
+      return "";
+
+   std::vector<string> const lang = APT::Configuration::getLanguages();
+   for (std::vector<string>::const_iterator l = lang.begin();
+       l != lang.end(); l++)
+      if (Section.FindS(string("Description-").append(*l).c_str()).empty() == false)
+        return *l;
+
+   return "";
 }
                                                                         /*}}}*/
 // ListParser::Description - Return the description_md5 MD5SumValue    /*{{{*/
index f3ab696..8f28f05 100644 (file)
@@ -5,6 +5,7 @@
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/acquire-item.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <apt-pkg/error.h>
 
 using namespace std;
@@ -170,13 +171,19 @@ bool debReleaseIndex::GetIndexes(pkgAcquire *Owner, bool GetAll) const
                     new indexRecords (Dist));
 
    // Queue the translations
+   std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
    for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); 
        I != SectionEntries.end(); I++) {
 
       if((*I)->IsSrc)
         continue;
-      debTranslationsIndex i = debTranslationsIndex(URI,Dist,(*I)->Section);
-      i.GetIndexes(Owner);
+
+      for (vector<string>::const_iterator l = lang.begin();
+               l != lang.end(); l++)
+      {
+       debTranslationsIndex i = debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str());
+       i.GetIndexes(Owner);
+      }
    }
 
    return true;
@@ -202,6 +209,7 @@ vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
       return Indexes;
 
    Indexes = new vector <pkgIndexFile*>;
+   std::vector<std::string> const lang = APT::Configuration::getLanguages(true);
    for (vector<const debSectionEntry *>::const_iterator I = SectionEntries.begin(); 
        I != SectionEntries.end(); I++) {
       if ((*I)->IsSrc)
@@ -209,7 +217,10 @@ vector <pkgIndexFile *> *debReleaseIndex::GetIndexFiles()
       else 
       {
          Indexes->push_back(new debPackagesIndex (URI, Dist, (*I)->Section, IsTrusted()));
-        Indexes->push_back(new debTranslationsIndex(URI, Dist, (*I)->Section));
+
+        for (vector<string>::const_iterator l = lang.begin();
+               l != lang.end(); l++)
+           Indexes->push_back(new debTranslationsIndex(URI,Dist,(*I)->Section,(*l).c_str()));
       }
    }
 
index 8ed0bb7..5b8538a 100644 (file)
@@ -11,6 +11,7 @@
 #include <apt-pkg/debrecords.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/error.h>
+#include <apt-pkg/aptconfiguration.h>
 #include <langinfo.h>
                                                                        /*}}}*/
 
@@ -109,13 +110,18 @@ string debRecordParser::ShortDesc()
 string debRecordParser::LongDesc()
 {
   string orig, dest;
-  char *codeset = nl_langinfo(CODESET);
 
   if (!Section.FindS("Description").empty())
      orig = Section.FindS("Description").c_str();
-  else 
-     orig = Section.FindS(("Description-" + pkgIndexFile::LanguageCode()).c_str()).c_str();
+  else
+  {
+     vector<string> const lang = APT::Configuration::getLanguages();
+     for (vector<string>::const_iterator l = lang.begin();
+         orig.empty() && l != lang.end(); l++)
+       orig = Section.FindS(string("Description-").append(*l).c_str());
+  }
 
+  char const * const codeset = nl_langinfo(CODESET);
   if (strcmp(codeset,"UTF-8") != 0) {
      UTF8ToCodeset(codeset, orig, &dest);
      orig = dest;
index 08f71fe..37be870 100644 (file)
@@ -8,9 +8,9 @@
    ##################################################################### */
                                                                        /*}}}*/
 // Include Files                                                       /*{{{*/
-#include <apt-pkg/configuration.h>
 #include <apt-pkg/indexfile.h>
 #include <apt-pkg/error.h>
+#include <apt-pkg/aptconfiguration.h>
 
 #include <clocale>
 #include <cstring>
@@ -66,28 +66,20 @@ string pkgIndexFile::SourceInfo(pkgSrcRecords::Parser const &Record,
    return string();
 }
                                                                        /*}}}*/
-// IndexFile::TranslationsAvailable - Check if will use Translation    /*{{{*/
+// IndexFile::TranslationsAvailable - Check if will use Translation    /*{{{*/
 // ---------------------------------------------------------------------
 /* */
-bool pkgIndexFile::TranslationsAvailable()
-{
-  const string Translation = _config->Find("APT::Acquire::Translation");
-  
-  if (Translation.compare("none") != 0)
-    return CheckLanguageCode(LanguageCode().c_str());
-  else
-    return false;
+bool pkgIndexFile::TranslationsAvailable() {
+       return (APT::Configuration::getLanguages().empty() != true);
 }
                                                                        /*}}}*/
-// IndexFile::CheckLanguageCode - Check the Language Code              /*{{{*/
+// IndexFile::CheckLanguageCode - Check the Language Code              /*{{{*/
 // ---------------------------------------------------------------------
-/* */
-/* common cases: de_DE, de_DE@euro, de_DE.UTF-8, de_DE.UTF-8@euro,
-                 de_DE.ISO8859-1, tig_ER
-                 more in /etc/gdm/locale.conf 
-*/
-
-bool pkgIndexFile::CheckLanguageCode(const char *Lang)
+/* No intern need for this method anymore as the check for correctness
+   is already done in getLanguages(). Note also that this check is
+   rather bad (doesn't take three character like ast into account).
+   TODO: Remove method with next API break */
+__attribute__ ((deprecated)) bool pkgIndexFile::CheckLanguageCode(const char *Lang)
 {
   if (strlen(Lang) == 2 || (strlen(Lang) == 5 && Lang[2] == '_'))
     return true;
@@ -98,31 +90,14 @@ bool pkgIndexFile::CheckLanguageCode(const char *Lang)
   return false;
 }
                                                                        /*}}}*/
-// IndexFile::LanguageCode - Return the Language Code                  /*{{{*/
+// IndexFile::LanguageCode - Return the Language Code                  /*{{{*/
 // ---------------------------------------------------------------------
-/* return the language code */
-string pkgIndexFile::LanguageCode()
-{
-  const string Translation = _config->Find("APT::Acquire::Translation");
-
-  if (Translation.compare("environment") == 0) 
-  {
-     string lang = std::setlocale(LC_MESSAGES,NULL);
-
-     // we have a mapping of the language codes that contains all the language
-     // codes that need the country code as well 
-     // (like pt_BR, pt_PT, sv_SE, zh_*, en_*)
-     const char *need_full_langcode[] = { "pt","sv","zh","en", NULL };
-     for(const char **s = need_full_langcode;*s != NULL; s++)
-       if(lang.find(*s) == 0)
-          return lang.substr(0,5);
-     
-     if(lang.size() > 2)
-       return lang.substr(0,2);
-     else
-       return lang;
-  }
-  else 
-     return Translation;
+/* As we have now possibly more than one LanguageCode this method is
+   supersided by a) private classmembers or b) getLanguages().
+   TODO: Remove method with next API break */
+__attribute__ ((deprecated)) string pkgIndexFile::LanguageCode() {
+       if (TranslationsAvailable() == false)
+               return "";
+       return APT::Configuration::getLanguages()[0];
 }
                                                                        /*}}}*/
index b0ce6e5..997ff51 100644 (file)
 // Include Files                                                       /*{{{*/
 #include <apt-pkg/pkgcache.h>
 #include <apt-pkg/policy.h>
-#include <apt-pkg/indexfile.h>
 #include <apt-pkg/version.h>
 #include <apt-pkg/error.h>
 #include <apt-pkg/strutl.h>
 #include <apt-pkg/configuration.h>
+#include <apt-pkg/aptconfiguration.h>
 
 #include <apti18n.h>
     
@@ -674,14 +674,22 @@ string pkgCache::PkgFileIterator::RelStr()
  */
 pkgCache::DescIterator pkgCache::VerIterator::TranslatedDescription() const
 {
-   pkgCache::DescIterator DescDefault = DescriptionList();
-   pkgCache::DescIterator Desc = DescDefault;
-   for (; Desc.end() == false; Desc++)
-      if (pkgIndexFile::LanguageCode() == Desc.LanguageCode())
-        break;
-   if (Desc.end() == true) 
-      Desc = DescDefault;
-   return Desc;
+   std::vector<string> const lang = APT::Configuration::getLanguages();
+   for (std::vector<string>::const_iterator l = lang.begin();
+       l != lang.end(); l++)
+   {
+      pkgCache::DescIterator DescDefault = DescriptionList();
+      pkgCache::DescIterator Desc = DescDefault;
+
+      for (; Desc.end() == false; Desc++)
+        if (*l == Desc.LanguageCode())
+           break;
+      if (Desc.end() == true) 
+        Desc = DescDefault;
+      return Desc;
+   }
+
+   return DescriptionList();
 };
 
                                                                        /*}}}*/
index 0cfb5ff..07d9c03 100644 (file)
@@ -17,6 +17,8 @@ apt (0.7.25) UNRELEASED; urgency=low
     Closes: #552606
 
   [ David Kalnischkies ]
+   * [BREAK] add possibility to download and use multiply
+     Translation files, configurable with Acquire::Translation
   * apt-pkg/packagemanager.cc:
     - better debug output for ImmediateAdd with depth and why
     - improve the message shown for failing immediate configuration
index d7ad51c..777630e 100644 (file)
@@ -142,7 +142,7 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
         <listitem><para>Default release to install packages from if more than one
         version available. Contains release name, codename or release version. Examples: 'stable', 'testing', 'unstable', 'lenny', 'squeeze', '4.0', '5.0*'. See also &apt-preferences;.</para></listitem>
      </varlistentry>
-     
+
      <varlistentry><term>Ignore-Hold</term>
      <listitem><para>Ignore Held packages; This global option causes the problem resolver to
      ignore held packages in its decision making.</para></listitem>
@@ -392,6 +392,27 @@ DPkg::Pre-Install-Pkgs {"/usr/sbin/dpkg-preconfigure --apt";};
      these warnings are most of the time false negatives. Future versions will maybe include a way to
      really prefer uncompressed files to support the usage of local mirrors.</para></listitem>
      </varlistentry>
+
+     <varlistentry><term>Languages</term>
+     <listitem><para>The Languages subsection controls which <filename>Translation</filename> files are downloaded
+     and in which order APT tries to display the Description-Translations. APT will try to display the first
+     available Description for the Language which is listed at first. Languages can be defined with their
+     short or long Languagecodes. Note that not all archives provide <filename>Translation</filename>
+     files for every Language - especially the long Languagecodes are rare, so please
+     inform you which ones are available before you set here impossible values.</para>
+     <para>The default list includes "environment" and "en". "<literal>environment</literal>" has a special meaning here:
+     It will be replaced at runtime with the languagecodes extracted from the <literal>LC_MESSAGES</literal> enviroment variable.
+     It will also ensure that these codes are not included twice in the list. If <literal>LC_MESSAGES</literal>
+     is set to "C" only the <filename>Translation-en</filename> file (if available) will be used.
+     To force apt to use no Translation file use the setting <literal>Acquire::Languages=none</literal>. "<literal>none</literal>"
+     is another special meaning code which will stop the search for a fitting <filename>Translation</filename> file.
+     This can be used by the system administrator to let APT know that it should download also this files without
+     actually use them if not the environment specifies this languages. So the following example configuration will
+     result in the order "en, de" in an english and in "de, en" in a german localization. Note that "fr" is downloaded,
+     but not used if APT is not used in a french localization, in such an environment the order would be "fr, de, en".
+     <programlisting>Acquire::Languages { "environment"; "de"; "en"; "none"; "fr"; };</programlisting></para></listitem>
+     </varlistentry>
+
    </variablelist>
   </para>
  </refsect1>
@@ -983,6 +1004,7 @@ is commented.
        </listitem>
      </varlistentry>
 -->
+
    </variablelist>
  </refsect1>
  
index 7e86b3d..05826fe 100644 (file)
@@ -273,6 +273,15 @@ Acquire
 
     Order { "gz"; "lzma"; "bz2"; };
   };
+
+  Languages
+  {
+     "environment";
+     "de";
+     "en";
+     "none";
+     "fr";
+  };
 };
 
 // Directory layout
diff --git a/test/libapt/getlanguages_test.cc b/test/libapt/getlanguages_test.cc
new file mode 100644 (file)
index 0000000..f3629df
--- /dev/null
@@ -0,0 +1,91 @@
+#include <apt-pkg/aptconfiguration.h>
+#include <apt-pkg/configuration.h>
+
+#include <assert.h>
+#include <string>
+#include <vector>
+
+#include <iostream>
+
+// simple helper to quickly output a vector of strings
+void dumpVector(std::vector<std::string> vec) {
+       for (std::vector<std::string>::const_iterator v = vec.begin();
+            v != vec.end(); v++)
+               std::cout << *v << std::endl;
+}
+
+int main(int argc,char *argv[])
+{
+       std::vector<std::string> vec = APT::Configuration::getLanguages(false, false, "de_DE.UTF-8");
+       assert(vec.size() == 2);
+       assert(vec[0] == "de");
+       assert(vec[1] == "en");
+
+       // Special: Check if the cache is actually in use
+               vec = APT::Configuration::getLanguages(false, true, "en_GB.UTF-8");
+               assert(vec.size() == 2);
+               assert(vec[0] == "de");
+               assert(vec[1] == "en");
+
+       vec = APT::Configuration::getLanguages(false, false, "en_GB.UTF-8");
+       assert(vec.size() == 2);
+       assert(vec[0] == "en_GB");
+       assert(vec[1] == "en");
+
+       vec = APT::Configuration::getLanguages(false, false, "pt_PR.UTF-8");
+       assert(vec.size() == 3);
+       assert(vec[0] == "pt_PR");
+       assert(vec[1] == "pt");
+       assert(vec[2] == "en");
+
+       vec = APT::Configuration::getLanguages(false, false, "ast_DE.UTF-8"); // bogus, but syntactical correct
+       assert(vec.size() == 2);
+       assert(vec[0] == "ast");
+       assert(vec[1] == "en");
+
+       vec = APT::Configuration::getLanguages(false, false, "C");
+       assert(vec.size() == 1);
+       assert(vec[0] == "en");
+
+       _config->Set("Acquire::Languages::1", "environment");
+       _config->Set("Acquire::Languages::2", "en");
+       vec = APT::Configuration::getLanguages(false, false, "de_DE.UTF-8");
+       assert(vec.size() == 2);
+       assert(vec[0] == "de");
+       assert(vec[1] == "en");
+
+       _config->Set("Acquire::Languages::3", "de");
+       vec = APT::Configuration::getLanguages(false, false, "de_DE.UTF-8");
+       assert(vec.size() == 2);
+       assert(vec[0] == "de");
+       assert(vec[1] == "en");
+
+       _config->Set("Acquire::Languages::1", "none");
+       vec = APT::Configuration::getLanguages(false, false, "de_DE.UTF-8");
+       assert(vec.size() == 0);
+       vec = APT::Configuration::getLanguages(true, false, "de_DE.UTF-8");
+       assert(vec[0] == "en");
+       assert(vec[1] == "de");
+
+       _config->Set("Acquire::Languages::1", "fr");
+       _config->Set("Acquire::Languages", "de_DE");
+       vec = APT::Configuration::getLanguages(false, false, "de_DE.UTF-8");
+       assert(vec.size() == 1);
+       assert(vec[0] == "de_DE");
+
+       _config->Set("Acquire::Languages", "none");
+       vec = APT::Configuration::getLanguages(true, false, "de_DE.UTF-8");
+       assert(vec.size() == 0);
+
+       _config->Set("Acquire::Languages", "");
+       //FIXME: Remove support for this deprecated setting
+               _config->Set("APT::Acquire::Translation", "ast_DE");
+               vec = APT::Configuration::getLanguages(true, false, "de_DE.UTF-8");
+               assert(vec.size() == 1);
+               assert(vec[0] == "ast_DE");
+               _config->Set("APT::Acquire::Translation", "none");
+               vec = APT::Configuration::getLanguages(true, false, "de_DE.UTF-8");
+               assert(vec.size() == 0);
+
+       return 0;
+}
diff --git a/test/libapt/makefile b/test/libapt/makefile
new file mode 100644 (file)
index 0000000..f61a95f
--- /dev/null
@@ -0,0 +1,13 @@
+# -*- make -*-
+BASE=../..
+SUBDIR=test/libapt
+BASENAME=_libapt_test
+
+# Bring in the default rules
+include ../../buildlib/defaults.mak
+
+# Program for testing getLanguageCode
+PROGRAM = getLanguages${BASENAME}
+SLIBS = -lapt-pkg
+SOURCE = getlanguages_test.cc
+include $(PROGRAM_H)