From 0bff3507f74fb143cbddf914fb68abad8abf784d Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Fri, 17 May 2019 15:18:06 +0100 Subject: [PATCH 1/2] MDL-55197 filter_multilang: move preg_callback fn into class --- filter/multilang/filter.php | 78 ++++++++++++++++++++----------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/filter/multilang/filter.php b/filter/multilang/filter.php index 4cf90f7a90916..5dcd572ef0a58 100644 --- a/filter/multilang/filter.php +++ b/filter/multilang/filter.php @@ -38,6 +38,12 @@ // Following new syntax is not compatible with old one: // one langanother language + +/** + * @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 +65,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 +73,46 @@ 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 { + $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]; + } - $searchtosplit = '/<(?:lang|span)[^>]+lang="([a-zA-Z0-9_-]+)"[^>]*>(.*?)<\/(?:lang|span)>/is'; + $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]; - } + if (!preg_match_all($searchtosplit, $langblock[0], $rawlanglist)) { + //skip malformed blocks + return $langblock[0]; + } - $langlist = array(); - foreach ($rawlanglist[1] as $index=>$lang) { - $lang = str_replace('-','_',strtolower($lang)); // normalize languages - $langlist[$lang] = $rawlanglist[2][$index]; - } + $langlist = array(); + foreach ($rawlanglist[1] as $index=>$lang) { + $lang = str_replace('-','_',strtolower($lang)); // normalize languages + $langlist[$lang] = $rawlanglist[2][$index]; + } - 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; + 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; + } } } - - From 0925ecdbd4b4ed6d82eab91364d870835bd1a418 Mon Sep 17 00:00:00 2001 From: Tim Hunt Date: Fri, 17 May 2019 15:35:54 +0100 Subject: [PATCH 2/2] MDL-55197 filter_multilang: handle 'en' as parent lang better --- filter/multilang/filter.php | 60 ++++++++++++++++---------- filter/multilang/tests/filter_test.php | 5 +++ 2 files changed, 43 insertions(+), 22 deletions(-) diff --git a/filter/multilang/filter.php b/filter/multilang/filter.php index 5dcd572ef0a58..2e9bac35575ee 100644 --- a/filter/multilang/filter.php +++ b/filter/multilang/filter.php @@ -40,6 +40,8 @@ /** + * 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 @@ -81,38 +83,52 @@ function filter($text, array $options = array()) { * @return string the replacement string (one of the possible translations). */ protected function process_match(array $langblock): string { - $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]; - } - $searchtosplit = '/<(?:lang|span)[^>]+lang="([a-zA-Z0-9_-]+)"[^>]*>(.*?)<\/(?:lang|span)>/is'; if (!preg_match_all($searchtosplit, $langblock[0], $rawlanglist)) { - //skip malformed blocks + // Skip malformed blocks. return $langblock[0]; } $langlist = array(); - foreach ($rawlanglist[1] as $index=>$lang) { - $lang = str_replace('-','_',strtolower($lang)); // normalize languages + foreach ($rawlanglist[1] as $index => $lang) { + $lang = str_replace('-', '_', strtolower($lang)); // Normalize languages. $langlist[$lang] = $rawlanglist[2][$index]; } - 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; + // Follow the stream of parent languages. + $lang = current_language(); + do { + if (isset($langlist[$lang])) { + return $langlist[$lang]; + } + } while ($lang = $this->get_parent_lang($lang)); + + // If we don't find a match, default to the first provided translation. + return array_shift($langlist); + } + + /** + * 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', + ], ]; }