iarenaza / moodle-filter_multilang2

Moodle filter for Multi-Language Content (v2)
6 stars 17 forks source link

Inconsistent behaviour with English child languages #42

Open michael-milette opened 11 months ago

michael-milette commented 11 months ago

Hi @iarenaza ,

Thank you so much for your continued efforts with this plugin. I've been using it successfully with the English and Canadian French language packs for many years and highly recommend it to others. My sites and courses all contain thousands of instances of mlang tags in the following format:

{mlang en}English{mlang}{mlang fr}Français{mlang}

I really like that, regardless of whether I have the Canadian French child language pack or just the French language pack, this format with the 2 letter parent language has always worked for me. I say worked for me because I recently started using the Canadian English child language pack. The problem that I now observe is that, what works in French does not seem to work in English.

Using the same string mentioned above, when I view with the UI set to English, it works as expected. However, the text no longer appears at all if I am viewing using Canadian English. I expected the child English language pack to work the same way as the other child languages.

Anything you could do to fix this issue would be most appreciated. Let me know if you have any questions.

Best regards,

Michael

iarenaza commented 11 months ago

Hi @michael-milette

I'm afraid that this is caused by a "surprising behavior" from get_language_dependencies(). If you have a look at it, you will see that there is the following piece of text in its documentation string:

English (en) is considered as the top implicit parent of all language packs and is not included in the returned list.

That is why fr_ca works as expected, as get_language_dependencies() returns an array containing both fr_ca and fr. But en_ca doesn't, as get_language_dependencies() returns an array containing just en_ca (but not en) See [1] below. Thus the {mlang en} ...{mlang} part is not used.

I ignore the reason why the above "surprising behavior" was decided. But according to my "git archeology" work, it's been like that for a long time (at least since MDL-22015, commit moodle/moodle@fb6b53724c, from 2010.04.04). And I couldn't find any stated reason for the decision, neither in the commit logs, nor in the tracker discussion.

Which leaves us with very little room for a fix, other than a "hack" heuristic that can fail in some cases. We could have a look at the value of current_language(), and if it begins with en_, assume that it is a language whose parent language is en. And add that extra en ourselves to the parent cache. But that heuristic breaks down the moment the child language is not named like that.

And probably breaks down too if the child language is actually two steps removed from English (i.e., en is the grandfather of the current language). And because I don't know why en was explicitly excluded from a language dependencies in the first place, I don't know what other unexpected side-effects we would be triggering. That is why I'm a bit hesitant to go that route.

On the other hand, you could use the feature added in version 1.1.1 as a workaround for this particular "pathological case". That is, use {mlang en,en_ca}....{mlang} instad of just {mlang en_ca}...{mlang}. I know it's not ideal, but at least it's a "known bad", as opposed to the potentially "unknown bad" of the heuristic I mentioned above.

[1]

$ cat > issue-42.php <<'EOF'
<?php
define('CLI_SCRIPT', true);

require(dirname(__FILE__).'/config.php');

$child_langs = array('fr_ca', 'en_ca');
foreach ($child_langs as $child_lang) {
    $parents = get_string_manager()->get_language_dependencies($child_lang);
    print('child language: ' .
          $child_lang .
          ' - parent languages: '.
          print_r($parents, true) .
          "\n");
}
EOF
$ php issue-42.php
child language: fr_ca - parent languages: Array
(
    [0] => fr
    [1] => fr_ca
)

child language: en_ca - parent languages: Array
(
    [0] => en_ca
)

$
michael-milette commented 11 months ago

Thanks for the feedback.

The problem is, as a consultant, I've created dozens of Moodle sites over the years, now each with dozens or sometimes even hundreds of courses. I would say that about 2/3 of them are multi-language sites that make use of multilang v2. Most of them use the root English language however, it would be great if I could start migrating them to English (Canada). I've had requests from time to time, especially in the Government of Canada, for English with Canadian spelling and Canadian date formats.

It would be most appreciated if you could figure out how to make {mlang en} work with English (Canada).

Best regards,

Michael

iarenaza commented 11 months ago

Hi @michael-milette

after some head-scratching and some Moodle code spelunking, I think I may have found a possible solution that doesn't have too many "unintended side-effects". One known side-effect is that the solution I've found triggers issue #25 for multilang blocks where multilang English blocks are involved. Something that doesn't happen with the standard multilang2 filter, as 'en' is never considered as a parent language of a given multilang block.

If you are confortable with the above caveat, then you can try my possible solution by applying the follwing patch:

diff --git a/filter.php b/filter.php
index 044a5a2..0d99299 100644
--- a/filter.php
+++ b/filter.php
@@ -152,7 +152,14 @@ class filter_multilang2 extends moodle_text_filter {
         $this->replacementdone = false;
         $currlang = current_language();
         if (!array_key_exists($currlang, self::$parentcache)) {
-            $parentlangs = get_string_manager()->get_language_dependencies($currlang);
+            $strmgr = get_string_manager();
+            $parentlangs = $strmgr->get_language_dependencies($currlang);
+            if (count($parentlangs) > 0) {
+                $realrootisen = $strmgr->get_string('parentlanguage', 'langconfig', null, $parentlangs[0]);
+                if ($realrootisen === 'en') {
+                    $parentlangs = array_merge(array('en'), $parentlangs);
+                }
+            }
             self::$parentcache[$currlang] = $parentlangs;
         }
iarenaza commented 10 months ago

Hi @michael-milette

could you test the possible solution suggested earlier?

michael-milette commented 5 days ago

Sorry, I know you are still waiting for me on this. It is still on my TODO list - I have not forgotten about this. I appreciate your patience.

Michael