From fb5af92c8129673bf5f03f774b7b73abe48d8c22 Mon Sep 17 00:00:00 2001
From: Hanne Moa <hanne.moa@uninett.no>
Date: Tue, 25 Oct 2016 11:40:26 +0200
Subject: [PATCH] Fix loading of domain from modules

---
 lib/SimpleSAML/Locale/Localization.php | 95 +++++++++++++++-----------
 lib/SimpleSAML/XHTML/Template.php      | 47 ++++++++++---
 2 files changed, 96 insertions(+), 46 deletions(-)

diff --git a/lib/SimpleSAML/Locale/Localization.php b/lib/SimpleSAML/Locale/Localization.php
index fc307aa16..a8278ca4d 100644
--- a/lib/SimpleSAML/Locale/Localization.php
+++ b/lib/SimpleSAML/Locale/Localization.php
@@ -83,6 +83,34 @@ class Localization
     }
 
 
+    /**
+     * Get the default locale dir for a specific module aka. domain
+     *
+     * @param string $domain Name of module/domain
+     */
+    public function getDomainLocaleDir($domain)
+    {
+        $localeDir = $this->configuration->resolvePath('modules') . '/' . $domain . '/locales';
+        return $localeDir;
+    }
+
+
+    /*
+     * Add a new translation domain from a module
+     * (We're assuming that each domain only exists in one place)
+     *
+     * @param string $module Module name
+     * @param string $localeDir Absolute path if the module is housed elsewhere
+     */
+    public function addModuleDomain($module, $localeDir = null)
+    {
+        if (!$localeDir) {
+            $localeDir = $this->getDomainLocaleDir($module);
+        }
+        $this->addDomain($localeDir, $module);
+    }
+
+
     /*
      * Add a new translation domain
      * (We're assuming that each domain only exists in one place)
@@ -93,6 +121,8 @@ class Localization
     public function addDomain($localeDir, $domain)
     {
         $this->localeDomainMap[$domain] = $localeDir;
+        \SimpleSAML\Logger::debug("Localization: load domain '$domain' at '$localeDir'");
+        $this->loadGettextGettextFromPO($domain);
     }
 
     /*
@@ -107,6 +137,7 @@ class Localization
         $langcode = $langcode[0];
         $localeDir = $this->localeDomainMap[$domain];
         $langPath = $localeDir.'/'.$langcode.'/LC_MESSAGES/';
+        \SimpleSAML\Logger::debug("Trying langpath for '$langcode' as '$langPath'");
         if (is_dir($langPath) && is_readable($langPath)) {
             return $langPath;
         }
@@ -119,7 +150,6 @@ class Localization
             $error = "Localization not found for langcode '$langcode' at '$langPath', falling back to langcode '".
                      $defLangcode."'";
             \SimpleSAML\Logger::error($_SERVER['PHP_SELF'].' - '.$error);
-
             return $langPath;
         }
 
@@ -130,20 +160,40 @@ class Localization
     }
 
 
+    /**
+     * Setup the translator
+     */
+    private function setupTranslator()
+    {
+        $this->translator = new Translator();
+        $this->translator->register();
+    }
+
+
     /**
      * Load translation domain from Gettext/Gettext using .po
      *
+     * Note: Since Twig I18N does not support domains, all loaded files are
+     * merged. Use contexts if identical strings need to be disambiguated.
+     *
      * @param string $domain Name of domain
+     * @param boolean $catchException Whether to catch an exception on error or return early
+     *
+     * @throws \Exception If something is wrong with the locale file for the domain and activated language
      */
-    private function loadGettextGettextFromPO($domain = self::DEFAULT_DOMAIN)
+    private function loadGettextGettextFromPO($domain = self::DEFAULT_DOMAIN, $catchException = true)
     {
-        $this->translator = new Translator();
-        $this->translator->register();
         try {
             $langPath = $this->getLangPath($domain);
         } catch (\Exception $e) {
-            // bail out!
-            return;
+            $error = "Something wrong with path '$langPath', cannot load domain '$domain'";
+            \SimpleSAML\Logger::error($_SERVER['PHP_SELF'].' - '.$error);
+            if ($catchException) {
+                // bail out!
+                return;
+            } else {
+                throw $e;
+            }
         }
         $poFile = $domain.'.po';
         $poPath = $langPath.$poFile;
@@ -181,9 +231,9 @@ class Localization
             return;
         }
 
+        $this->setupTranslator();
         // setup default domain
         $this->addDomain($this->localeDir, self::DEFAULT_DOMAIN);
-        $this->activateDomain(self::DEFAULT_DOMAIN);
     }
 
     /**
@@ -194,35 +244,4 @@ class Localization
         return $this->localeDomainMap;
     }
 
-
-    /**
-     * Set which translation domain to use
-     *
-     * @param string $domain Name of domain
-     */
-    public function activateDomain($domain)
-    {
-        \SimpleSAML\Logger::debug("Localization: activate domain");
-        $this->loadGettextGettextFromPO($domain);
-        $this->currentDomain = $domain;
-    }
-
-
-    /**
-     * Get current translation domain
-     */
-    public function getCurrentDomain()
-    {
-        return $this->currentDomain ? $this->currentDomain : self::DEFAULT_DOMAIN;
-    }
-
-
-    /**
-     * Go back to default translation domain
-     */
-    public function restoreDefaultDomain()
-    {
-        $this->loadGettextGettextFromPO(self::DEFAULT_DOMAIN);
-        $this->currentDomain = self::DEFAULT_DOMAIN;
-    }
 }
diff --git a/lib/SimpleSAML/XHTML/Template.php b/lib/SimpleSAML/XHTML/Template.php
index 35b740c4a..97c17d466 100644
--- a/lib/SimpleSAML/XHTML/Template.php
+++ b/lib/SimpleSAML/XHTML/Template.php
@@ -71,6 +71,12 @@ class SimpleSAML_XHTML_Template
     private $twig_namespace = \Twig_Loader_Filesystem::MAIN_NAMESPACE;
 
 
+    /*
+     * Current module, if any
+     */
+    private $module;
+
+
     /**
      * Constructor
      *
@@ -84,6 +90,8 @@ class SimpleSAML_XHTML_Template
         $this->template = $template;
         // TODO: do not remove the slash from the beginning, change the templates instead!
         $this->data['baseurlpath'] = ltrim($this->configuration->getBasePath(), '/');
+        $result = $this->findModuleAndTemplateName($template);
+        $this->module = $result[0];
         $this->translator = new SimpleSAML\Locale\Translate($configuration, $defaultDictionary);
         $this->localization = new \SimpleSAML\Locale\Localization($configuration);
         $this->twig = $this->setupTwig();
@@ -165,6 +173,12 @@ class SimpleSAML_XHTML_Template
             return false;
         }
 
+
+        // load extra i18n domains
+        if ($this->module) {
+            $this->localization->addModuleDomain($this->module);
+        }
+
         $options = array(
             'cache' => $cache,
             'auto_reload' => $auto_reload,
@@ -337,6 +351,28 @@ class SimpleSAML_XHTML_Template
     }
 
 
+    /**
+     * Find module the template is in, if any
+     *
+     * @param string $template The relative path from the theme directory to the template file.
+     *
+     * @return array An array with the name of the module and template
+     */
+    private function findModuleAndTemplateName($template)
+    {
+        $tmp = explode(':', $template, 2);
+        if (count($tmp) === 2) {
+            $templateModule = $tmp[0];
+            $templateName = $tmp[1];
+        } else {
+            $templateModule = null;
+            $templateName = $tmp[0];
+        }
+
+        return array($templateModule, $templateName);
+    }
+
+
     /**
      * Find template path.
      *
@@ -356,14 +392,9 @@ class SimpleSAML_XHTML_Template
     {
         assert('is_string($template)');
 
-        $tmp = explode(':', $template, 2);
-        if (count($tmp) === 2) {
-            $templateModule = $tmp[0];
-            $templateName = $tmp[1];
-        } else {
-            $templateModule = 'default';
-            $templateName = $tmp[0];
-        }
+        $result = $this->findModuleAndTemplateName($template);
+        $templateModule = $result[0] ? $result[0] : 'default';
+        $templateName = $result[1];
 
         $tmp = explode(':', $this->configuration->getString('theme.use', 'default'), 2);
         if (count($tmp) === 2) {
-- 
GitLab