Support for Drupal 7 is ending on 5 January 2025—it’s time to migrate to Drupal 10! Learn about the many benefits of Drupal 10 and find migration tools in our resource center.
Currently in drupal_lookup_path()
we use $language_content
as a default if a language is not explictly passed. This seems a sensible choice as the (node) path alias is tied to the node language, but actually this causes a severe misbehavior: as content language is inherited from interface language, if we get it from a language provider different from URL, path aliases will stop working.
Steps to reproduce:
- Enable locale
- Add French language
- Enable URL and user language detection and move User on top
- Edit user account andt set French as preferred language
- Enable multilingual support for articles
- Create an English article with a path alias
- After saving the node you get a 404 page
(found while discussing #817114: Deprecate the session language detection method)
Comment | File | Size | Author |
---|---|---|---|
#10 | language-855380-10.patch | 9.56 KB | plach |
#8 | language-855380-8.patch | 8.53 KB | plach |
#6 | language-855380-6.patch | 7.51 KB | plach |
#4 | language-855380-4.patch | 7.49 KB | plach |
#1 | language-855380-1.patch | 5.78 KB | plach |
Comments
Comment #1
plachThe fix is pretty obvious: use URL language as default. The attached patch provides a test that defines which the correct behavior should be.
Comment #2
plachRelated issue: #684982: Audit of global language variable use.
Comment #4
plachTests should pass now.
Comment #5
sunThat's not a quick fix.
This should be $this->web_user. I actually thought that $this->user would be a backup of the local user running simpletest.
Please bear with me. I'm a crazy old man.
1) We are testing two different URLs for the same $french_alias here. First with an additional "fr/" prefix, afterwards without. Somehow, but I've to admit that I never really checked this, I assumed that, when storing language-specific aliases, then that entire alias would be used; without path prefix, as that prefix, like the name implies, belongs to the path, not the alias...? Am I horribly mistaken?
2) This test enables both user language and URl language negotiation, preferring user language over URL language. It's configuring the user's preferred language to French. Afterwards, it disables URL language negotiation. Keeping user language negotiation enabled. Lastly, it directly visits the English node page. -- I totally thought that one of the following would happen:
a) As the user still has a preference, user language negotiation is still enabled, and there is a French translation, he gets or is redirected to the French node.
b) Basically same as a), but the test should have visited a node listing page (such as the front page), where language negotiation actually happens, so the French translation (the user's preference) actually appears.
No? Am I nuts? :)
1) Missing "when" after "even".
2) Typo in "negotiation".
Powered by Dreditor.
Comment #6
plach@sun:
It's correct. The alias is stored without the prefix. We check the unprefixed version because we disabled URL language one moment before. In this situation (as in D6) only english and language neutral aliases (should) keep working.
If we take into account language negotiation for paths when URL language is disabled the problem described in the OP may occur: the french language is selected for UI an content, english is selected for URLs (as no prefix is found we fallback to the default language); if we pick the content language we have no way to check that the path alias is valid: there is no path alias for french matching the english alias, so we can't get the english node and we can't get its french translation. So we have to pick URL language.
By the way, if I'm not mistaken, nowhere in core we perform redirects based on language negotiation values.
This way we wouldn't explictly check that the french alias is not recognized (I'm using D6 behavior as reference).
Comment #7
andypostsubscribe
Comment #8
plachUpdated the
url()
phpdoc to match the switch to$language_url
.Comment #9
sunThanks for the thorough explanation!
Given that this is a critical issue and contains quite some explanation and reasoning, it would be good to transfer the major information building blocks into a in-code comment, explaining why the fallback is $language_url and not something else, so as to prevent breaking this again in the future.
Let's append your explanation to the comment:
"Check the unprefixed alias, because we disabled URL language negotiation above. In this situation, only English and language neutral aliases should keep working."
(although... "English"...? Did you mean the site's default language?)
Furthermore, let's additionally append:
"If URL language negotiation is disabled, then French will be the active UI and content language (the user's preference), and English the active URL language, as no prefix was found and we fall back to the site's default language. [NOTE: needs tweaking:] In this case, drupal_lookup_path() needs to use the URL language to check whether a URL alias is valid."
[TWEAK WITH THIS: if we pick the content language we have no way to check that the path alias is valid: there is no path alias for french matching the english alias, so we can't get the english node and we can't get its french translation. So we have to pick URL language.]
46 critical left. Go review some!
Comment #10
plachHere it is. Hope the comments are good.
Comment #12
plachOnly comments added since tests passed and I can't see the tests failing on my box.
#10: language-855380-10.patch queued for re-testing.
Comment #13
plach@sun: is #10 ok?
Comment #14
sunAwesome! Much much better now. With these, no one needs to read this issue to understand what's going on.
Comment #15
andypostAlso related to drupal_path_alias() bugs
#829968: drupal_lookup_path() documentation and return mismatch
#863318: Wrong sort order of aliases for different languages
Comment #16
Dries CreditAttribution: Dries commentedThis looks good and the code comments make it easy to grok. Great work. Committed to CVS HEAD.
Comment #18
donquixote CreditAttribution: donquixote commented