diff --git a/filter/multilang/filter.php b/filter/multilang/filter.php
index 4cf90f7a90916..2e9bac35575ee 100644
--- a/filter/multilang/filter.php
+++ b/filter/multilang/filter.php
@@ -38,6 +38,14 @@
// Following new syntax is not compatible with old one:
// one langanother language
+
+/**
+ * Implementation of the Moodle filter API for the Multi-lang filter.
+ *
+ * @copyright Gaetan Frenoy
+ * @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 @@ function filter($text, array $options = array()) {
$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 @@ function filter($text, array $options = array()) {
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];
}
}
-
-
diff --git a/filter/multilang/tests/filter_test.php b/filter/multilang/tests/filter_test.php
index 116dc50f02ae9..2dbefa2c8219b 100644
--- a/filter/multilang/tests/filter_test.php
+++ b/filter/multilang/tests/filter_test.php
@@ -116,6 +116,11 @@ public function multilang_testcases() {
Québécois',
'fr', ['fr_ca' => 'fr'],
],
+ 'Fallback to parent when child not present when parent is en' => [
+ 'English',
+ 'DeutschEnglish',
+ 'en_us',
+ ],
];
}