Merge branch 'MDL-55197' of https://github.com/timhunt/moodle
authorJun Pataleta <jun@moodle.com>
Thu, 23 May 2019 03:58:14 +0000 (11:58 +0800)
committerJun Pataleta <jun@moodle.com>
Thu, 23 May 2019 03:58:14 +0000 (11:58 +0800)
filter/multilang/filter.php
filter/multilang/tests/filter_test.php

index 4cf90f7..2e9bac3 100644 (file)
@@ -38,6 +38,14 @@ defined('MOODLE_INTERNAL') || die();
 // Following new syntax is not compatible with old one:
 //   <span lang="XX" class="multilang">one lang</span><span lang="YY" class="multilang">another language</span>
 
+
+/**
+ * Implementation of the Moodle filter API for the Multi-lang filter.
+ *
+ * @copyright  Gaetan Frenoy <gaetan@frenoy.net>
+ * @copyright  2004 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
 class filter_multilang extends moodle_text_filter {
     function filter($text, array $options = array()) {
         global $CFG;
@@ -59,7 +67,7 @@ class filter_multilang extends moodle_text_filter {
             $search = '/(<(?:lang|span) lang="[a-zA-Z0-9_-]*".*?>.*?<\/(?:lang|span)>)(\s*<(?:lang|span) lang="[a-zA-Z0-9_-]*".*?>.*?<\/(?:lang|span)>)+/is';
         }
 
-        $result = preg_replace_callback($search, 'filter_multilang_impl', $text);
+        $result = preg_replace_callback($search, [$this, 'process_match'], $text);
 
         if (is_null($result)) {
             return $text; //error during regex processing (too many nested spans?)
@@ -67,44 +75,60 @@ class filter_multilang extends moodle_text_filter {
             return $result;
         }
     }
-}
 
-function filter_multilang_impl($langblock) {
-    global $CFG;
-
-    $mylang = current_language();
-    static $parentcache;
-    if (!isset($parentcache)) {
-        $parentcache = array();
-    }
-    if (!array_key_exists($mylang, $parentcache)) {
-        $parentlang = get_parent_language($mylang);
-        $parentcache[$mylang] = $parentlang;
-    } else {
-        $parentlang = $parentcache[$mylang];
-    }
+    /**
+     * This is the callback used by the preg_replace_callback call above.
+     *
+     * @param array $langblock one of the matches from the regex match.
+     * @return string the replacement string (one of the possible translations).
+     */
+    protected function process_match(array $langblock): string {
+        $searchtosplit = '/<(?:lang|span)[^>]+lang="([a-zA-Z0-9_-]+)"[^>]*>(.*?)<\/(?:lang|span)>/is';
+
+        if (!preg_match_all($searchtosplit, $langblock[0], $rawlanglist)) {
+            // Skip malformed blocks.
+            return $langblock[0];
+        }
 
-    $searchtosplit = '/<(?:lang|span)[^>]+lang="([a-zA-Z0-9_-]+)"[^>]*>(.*?)<\/(?:lang|span)>/is';
+        $langlist = array();
+        foreach ($rawlanglist[1] as $index => $lang) {
+            $lang = str_replace('-', '_', strtolower($lang)); // Normalize languages.
+            $langlist[$lang] = $rawlanglist[2][$index];
+        }
 
-    if (!preg_match_all($searchtosplit, $langblock[0], $rawlanglist)) {
-        //skip malformed blocks
-        return $langblock[0];
-    }
+        // Follow the stream of parent languages.
+        $lang = current_language();
+        do {
+            if (isset($langlist[$lang])) {
+                return $langlist[$lang];
+            }
+        } while ($lang = $this->get_parent_lang($lang));
 
-    $langlist = array();
-    foreach ($rawlanglist[1] as $index=>$lang) {
-        $lang = str_replace('-','_',strtolower($lang)); // normalize languages
-        $langlist[$lang] = $rawlanglist[2][$index];
+        // If we don't find a match, default to the first provided translation.
+        return array_shift($langlist);
     }
 
-    if (array_key_exists($mylang, $langlist)) {
-        return $langlist[$mylang];
-    } else if (array_key_exists($parentlang, $langlist)) {
-        return $langlist[$parentlang];
-    } else {
-        $first = array_shift($langlist);
-        return $first;
+    /**
+     * Puts some caching around get_parent_language().
+     *
+     * Also handle parent == 'en' in a way that works better for us.
+     *
+     * @param string $lang a Moodle language code, e.g. 'fr'.
+     * @return string the parent language.
+     */
+    protected function get_parent_lang(string $lang): string {
+        static $parentcache;
+        if (!isset($parentcache)) {
+            $parentcache = ['en' => ''];
+        }
+        if (!isset($parentcache[$lang])) {
+            $parentcache[$lang] = get_parent_language($lang);
+            // The standard get_parent_language method returns '' for parent == 'en'.
+            // That is less helpful for us, so change it back.
+            if ($parentcache[$lang] === '') {
+                $parentcache[$lang] = 'en';
+            }
+        }
+        return $parentcache[$lang];
     }
 }
-
-
index 116dc50..2dbefa2 100644 (file)
@@ -116,6 +116,11 @@ class filter_multilang_filter_testcase extends advanced_testcase {
                 <span lang="fr_ca" class="multilang">Québécois</span>',
                 'fr', ['fr_ca' => 'fr'],
             ],
+            'Fallback to parent when child not present when parent is en' => [
+                'English',
+                '<span lang="de" class="multilang">Deutsch</span><span lang="en" class="multilang">English</span>',
+                'en_us',
+            ],
         ];
     }