Endless loop with translation (D6)
steinmb - January 31, 2008 - 11:40
| Project: | Global Redirect |
| Version: | 6.x-1.x-dev |
| Component: | Code |
| Category: | bug report |
| Priority: | critical |
| Assigned: | Unassigned |
| Status: | patch (code needs review) |
Description
With globalredirect module installed on D6 and with the Content translation turned on (i18n), the non-default (but enabled) language pages won't load and run into endless loop. You will find more details here, I also posted a article on internationalization group trying to bring this issue to attention.
Test environment:
- Global redirect module 6.x-1.x-dev ver. 30.12.2007
- Drupal 6 dev snapshot 26.1.08
- OS X 10.5.1 and MAMP
--
Stein Magne
http://smbjorklund.com

#1
Well, Global redirect does the redirects, so it needs to be aware of the language. Is this true for all non-default languages?
#2
I have not tested all languages Drupal supports :) But all 8 lang. I have tested have the same problem.
If the frontpage is anything else then http://example.com/?q= the bug is triggerd. Like if I choose Chinese Simplified as default lang. it will fail to open the frontpage http://example.com/?q=zh-hans.
I if we used http://example.com/?q=en to display english language instead of http://example.com/?q= we wouldn't had this problem today, or I'm I wrong?
--
Stein Magne
#3
I have a site with 3 languages and 3 nodes. And in my settings.php I added:
$conf['i18n_variables'] = array( 'site_frontpage' );German (default): no prefix, site_frontpage: home (url: node/1)
English: en, site_frontpage: home (url alias: node/2)
Portuguese, Portugal: pt, site_frontpage: node/3 (no alias)
(Aliases are language specific)
http://example.com/ -> node/1
http://example.com/home -> node/1 (redirect to /)
http://example.com/node/1 -> node/1 (redirect to /)
http://example.com/node/2 -> node/2 (no redirect)
http://example.com/en/node/2 -> Error
http://example.com/en/home -> Error
http://example.com/en/ -> Error
http://example.com/node/3 -> node/3 (no redirect)
http://example.com/pt/node/3 -> node/3 (no redirect, should be redirected to /pt)
http://example.com/pt/ -> Error
Error: Browser detects endless loop of redirects
Michael
#4
After playing a little bit with php code I think that the missing redirect of http://example.com/pt/node/3 is a problem of the i18n module.
So to fix this for my website I added the alias "home" for node/2 and added a hack to function globalredirect_init() in globalredirect.module by changing the if statement which handels frontpage urls:
old:
<?phpif (!empty($_REQUEST['q']) && drupal_is_front_page()) {
drupal_goto('', $query_string, NULL, 301);
}
?>
new:
<?phpif (!empty($_REQUEST['q']) && drupal_is_front_page()) {
// 1 if statement would be enough, but so it's nicer to read;)
if (!(module_exists('i18n') && array_key_exists($_REQUEST['q'], i18n_supported_languages(FALSE)))) {
drupal_goto('', $query_string, NULL, 301);
}
}
?>
Only a hack, but worked for me:)
(All 4 Errors and the missing redirect are "solved".)
Michael
#5
MichaelK - Thanks for looking into this. Are you using the i18n project for Drupal 6 or the built in translation stuff?
#6
I'm using both of them.
#7
The modules I use are
core: Content translation, Locale
i18n: Content Types, i18n - views, Internationalization, Language Icons, Multilingual Menu, Multilingual Profile, Multilingual taxonomy, Mutilingual Blocks, Strings, Translation Synchronization
That means every i18n module except for Multilingual Poll
So now I have some more nodes (type: page).
http://www.examle.com/node/4 <-> http://www.examle.com/impressum
http://www.examle.com/en/node/5 <-> http://www.examle.com/en/about-us
node/4 is redirected to impressum but en/node/5 is not redirected to en/about-us
And if someone wants to use /en/node/5/ he gets /en/en/node/5 (same when using /en/about-us/ => /en/en/about/us
So, the problem is the path prefix (here: en) in $_REQUEST['q'].
The path prefix can be found in:
<?phpglobal $language;
$language->prefix;
?>
Is there any easy way to get the same as in $_REQUEST['q'] but without the language prefix?
#8
I suppose the question is - what do people want the actions to be... 3 example paths:
Say Node 4 is the 'about-us' page and defaults to English ('en'). I assume, if this were the case, you'd setup some aliases like:
I also assume, in this case, en/node/4 should redirect to node/4 (and therefore 'about-us').
I ALSO assume that the language code can also be toggled so SUFFIX instead of PREFIX (eg, node/4/en)?
Thoughts?
#9
Ok, let us use your 3 example paths. Then i think fr/node/4 should not redirect to fr/about-us-french (which would be for example be equivalent to fr/node/5).
Staying at fr/node/4 does make sense because you can use the path specified language for the user interface (l10n). That's not necessary for the site visitor but for the author.
Although my native language is German and the website i administer uses German as default I prefer using an English interface while editing nodes.
en/node/4 can not be found (Error 404) while there is no language path prefix "en". But it would be nice if it redirects to about-us. (Not important for the moment I think).
I don't know if it's possible to use language suffixes instead of prefixes with drupal 6. I did not find such an option.
Best way would be to get a language suffix/prefix free version of the original path from drupal core and give another suffix/prefix free path to drupal_goto().
Another cool feature would be to eliminate double slashes like example.com//about-us
Here is my current version (based on globalredirect-6.x-1.x-dev.tar.gz)
<?php
// Get the Query String (minus the 'q'). If none set, set to NULL
$query_string = drupal_query_string_encode($_GET, array('q'));
if (empty($query_string)) {
$query_string = NULL;
}
//NEW
global $language;
$request_untrimmed = $_REQUEST['q'];
// eliminate prefix
if($language->prefix == substr($request_untrimmed, 0, strlen($language->prefix))) {
$request_untrimmed = substr_replace($request_untrimmed, '', 0, strlen($language->prefix));
}
//END NEW
// If current path is also the frontpage, redirect to ht tp://www .example.com
if (!empty($request_untrimmed) && drupal_is_front_page()) { // <- $_REQUEST['q'] => $request_untrimmed
drupal_goto('', $query_string, NULL, 301);
}
// Trim any trailing slash off the end (eg, 'node/1/' to 'node/1')
$request = rtrim($request_untrimmed, '/'); // now rtrim instead of trim (endless loop!)
// (...)
?>
All below "$_REQUEST['q']" should be replaced by "$request_untrimmed"
#10
May be a redirect like fr/node/4 to fr/about-us-french (= fr/node/5) would make sense if the user is anonymous.
Or generating an options page where the admin can choose what to do.
Where a redirect absolutely does make sense would be fr/about-us. Because if the aliases are about-us for the english version and about-us-french for the french version fr/about-us would cause an 404 error.
But I didn't find a way yet to check whether a url is correct or not.
At the moment I found 4 cases which produce a 404 error and where a redirect would be nice:
The first 2 and the last 2 are very similar. The first a about switching to the right language and the last are about eliminating the not existant prefix. Only for case 2 I have something like a idea.
My biggest problem is: how do detect that a path causes a 404 error (cases 1, 3, 4) and how to check if another path would be correct?
#11
Here is a patch with my code from March 26.
Can anyone test it with a non multilanguage site?
What if using different domains instead of language prefixes?
I'm not willing to test this (at the moment) because having to less time till May. Sorry about that.
#12
Looks good MichaelK - thanks... Although I have issues with the ways you handle the slashes.
(1) No need to trim the slash off the front manually, surely
trimfunction following that will handle removing slashes off the front and end?(2) Why do you need to check for double slash (the // test)? Where would that ever come up?
#13
1 and 2 are related to each other. Without 2 you should use rtrim. When using trim you get different string with $_REQUEST['q'] == '/fr/what-ever'.
$request_untrimmed == '/what-ever'
$request == 'what-ever'
Another solution could be:
<?phpif ($language->prefix == $request_untrimmed) {
$request_untrimmed = '';
} else if($language->prefix .'/' == substr($request_untrimmed, 0, strlen($language->prefix)+1)) {
$request_untrimmed = substr_replace($request_untrimmed, '', 0, strlen($language->prefix)+1);
}
?>
Now I think this is even the better way because it causes no error for $_REQUEST['q'] == '/fr-what-ever'.
The // is not really necessary. It would only come up if anyone make a typing mistake;) When I wrote this code I was just searching for more features to implement because i was angry about my inability of finding a solution for the above mentioned redirect 'fr/node/4 =>fr/about-us-french' (#10)... May be the way I did it in #9 is better for the official release;)
#14
And here is the patch with the #13-code and without the //-test.
#15
#153950: Endless loop with i18n deals with the same issue in D5.
- Please use
diff -upto create patches. See http://drupal.org/patch/create for further information.-
global $languageshould be at the top of this function.- To ensure that
$language->prefixwon't be changed during this function, it should be copied into a new variable$prefix.- A single
preg_replace('@^'. $prefix .'/?@')would be much faster than multiple string comparisons,substr_replace(), andstrlen()in the first if condition.- Wrong indentation for
drupal_goto()in the second if condition.-
$request_untrimmedis poorly named, because it gets trimmed in this function.#16
Sun - you should work for DrupalToughLove!
I'm going to try knock this one on the head this week (along with D5)...
#17
on my D6
i applied the #14 MichaelK's patch, nothing..
then #4 MichaelK, nothing..
then i replaced all the
$_REQUEST['q']based on these lines:global $language;$request_untrimmed = $_REQUEST['q'];
and working well..
on the D5 just the #4 MichaelK's things was necessary..
thanks.. good job!
#18
Re-rolled patch in #153950: Endless loop with i18n for D6.
#19
Hi all
System:
- Drupal 6.2
- PHP 5.1.x
- Apache 2.0.x
- Clean URL on
- Language English and Norwegian (nb)
- Default language en
- Frontpage http://example.com/node
Rolled patch #18 on my test server, and I still get endless loops BUT I only get it loading the frontpage. Any thing I can help you debug?
Cheers
Stein Magne
#20
Are there any updates on this issue? I would use Global Redirect, but I have multiple languages (D6). (subscribing).
#21
I am also having this issue, using i18n, any updates? thanks for your work! I can test stuff if you tell me what to do. (subscribe)
#22
There is a identical issue running against D5 http://drupal.org/node/153950. Most of the work is done towards the D5 tree and when it is fixed it get ported to D6 (as far I can see). So If any of you have a D5 test-installation running, install the i18n-module, global redirect and help testing the patch. The more people that are testing/commenting on this issues the faster we get it into D6.
--
Stein Magne
#23
The patch in #18 actually completely works for me. I get no errors whatsoever.
I have a Drupal 6.2 site with 3 languages, and language negotiation set to 'domain name only'. I access the site through 3 different top-level domains.
Well, this just works for me, thanks. Hopefully there will be a D6/i18n ready GlobalRedirect soon ;)
#24
the patches above don't work for me on drupal 6.3. here's my solution. it's very simple, just modified one line in file language.inc, see below:
// Search prefix within enabled languages.
foreach ($languages as $language) {
if (!empty($language->prefix) && $language->prefix == $prefix) {
// Rebuild $GET['q'] with the language removed.
$_GET['q'] = implode('/', $args);
return $language;
}
}
to:
// Search prefix within enabled languages.
foreach ($languages as $language) {
if (!empty($language->prefix) && $language->prefix == $prefix) {
// Rebuild $GET['q'] with the language removed.
$_REQUEST['q'] = $_GET['q'] = implode('/', $args);
return $language;
}
}
i think this solution is more essential. please test it. thank you.
#25
I've committed a version as 6.x-1.0 and I've tested it on my dev environment pretty thoroughly and cant break it.
http://drupal.org/node/290943
Please let me know if this doesn't work for you and we can try adjusting it.
Marking as fixed as I cannot reproduce any endless loops anymore with the 6.x-1.0 version.
#26
Sorry but has to reopen as this not seem to be fixed. I get hit by this bug on a fresh install of 6.3, apart from defaults only book and blog modules activated, however I installed using Swedish as the default language, hence locale is activated as setup did that. The only languages I have is swedish and english.
Activating the module globalredirect-6.x-1.0 (or the dev version) immediately result in Firefox trowing a page load error:
and the only way to get my site back is to manually edit the db file to inactivate globalredirect. So there is still something missing in that patch. I use clean URL's, and have tried to switch them off as well, but no change.
#27
poop...
yettyn could you explain your locale configuration fully please and I'll try to replicate the issue.
#28
explain? not sure what you mean by that but anyway... I will take it from the beginning.
I untar my 6.3 tarball in web root, so drupal lives at /, I untar the tarball for Swedish translation on top of that, run install and choose Swedish as install language. Everything goes fine. In language I have listed first english, then swedish and swedish is marked as default (standard in swedish). So I have a totally swedish GUI. In locale settings (Inställningar) I have None (Ingen) selected for what in swedish is called "språkförhandling" which literary would come out as something like "language negotiation", not sure that is what it says in english version though.
Anything else you need to know? Just tell me what you want me to do to dig up necessary info and I will try it.
#29
Just some update, I switched to English as default language (keeping swedish as an option) and then I have no problems with activating Globalredirect. but this may already be known.
#30
some further info, and partly solution.
In Language config, if I change language negitiation from None to the 3rd alternative (haven't tested the others), Global redirect now works. I am not sure if that's how I want to have it though, just started to build the site, so not sure yet if I even will have it multilang or just swedish.
#31
Ahh so the issue appears to be language negotiation!
Which option are you trying to use? I'm wondering if sites will also break with a language domain too...
#32
Initially I used the None option, and that's when Global redirect doesn't work. I have now tested all of them and the only one that seem to work is "Path prefix with language fallback. ", all the others give the redirect loop error.
That should pinpoint it I guess, or at least hope.
#33
I think there is more to it as I decided to build my site in Swedish only, hence disabling English. Now Global redirect causes a redirection loop error, no matter which option for language negotiation is used. So it seem somehow module doesn't like other languages then english, but maybe this is an i18n flaw really, I don't know.
#34
Ok, I'm having the same issue and did some testing.
I'm using drupal 6.3 with spanish as the default language and english deactivated (only those 2 languages installed).
With: "None" option in language negotiation.
That configuration gave me endless loop.
I tryed using the: "Path prefix with language fallback".
Endless loop.
I don't really need english in my site but i wanted to try having 2 languages activated so i installed portuguese translation and activated it.
This gave me endless loop with the "none" option (in language negotiation)... but it worked great with "Path prefix with language fallback".
The problem is that it changes all my links from example.com to example.com/es
The second option: "Path prefix only" just shows the frontpage and endless loop for all the others.
#35
bugger. Will have to do some testing. I thought I had this licked! :-(
Cheers for the info guys.
#36
This will probably not solve it, but I noticed that you forgot do do the hook_help change from 5.x to 6.x, it's just 2 lines in globalredirect.module
function globalredirect_help($section) {switch ($section) {
need to change to
function globalredirect_help($path, $arg) {switch ($path) {
as it's such a trivial thing I don't bother to open a new issue for it.
#37
Getting this issue to with french as default language and english disabled.
Using drupal 6.3
Content translation disabled
Global redirect 1.0
I get endless loop with all pages.
#38
I'm bumping the priority of this, at it will render a fresh site (ie., one that hasn't changed any language settings) unusable.
#39
If it helps, I was running into a similar problem until I updated my Global Redirect Module to the latest version (8-5-08 I believe the date on it is). After updating, I no longer get endless loop errors. Also, I am using the path prefix, ie http://example.com/es/node, and Drupal 6.3 with the Content translation and Locale core modules enabled.
#40
I encounter exactly the same issue. I use drupal 6.3 and I have franch as default language ant english, which i don't use.
When the former globalredirect module was activated, i had no problem. Since i updated the module to 6.x-1.0 i have endless loop.
Thank you for your help
#41
I'm having a similar issue and am torn about whether it should be open in a new queue or not. The difference is that I'm not running any form of internationalization.
Upgraded a site from Drupal 5.9 to Drupal 6.3.
Things seem to work ok for a time. At some point (the one time I tracked it for sure it was when I turned off Site Maintenance) all pages but except the front page stop responding. I've looked at the url_alias table and unlike some other issues there don't seem to be duplicate paths in there. This, however, affects all URL's including admin pages and /node/##/edit.
One interesting distinction is that it happens in browsers as Anonymous or a logged in user. However requesting a URL with CURL is at least able to successfully get the access denied page that Safari and Firefox are not shown. Disabling Global Redirect causes the site to begin functioning again.
Here is my current module set which will cause the problem if Global Redirect is on... It will with most of these off as well but this is what's running at the moment:
Drupal core
Drupal 6.3
Includes: Aggregator, Block, Blog, Comment, Database logging, Filter, Garland, Menu, Node, OpenID, Path, Ping, Profile, Search, System, Taxonomy, Update status, Upload, User
Modules
Drupal Administration Menu 6.x-1.0
Includes: Administration Menu
Amazon 6.x-1.0-beta3
Includes: Amazon API, Amazon Filter
Content Construction Kit (CCK) 6.x-2.0-rc4
Includes: Content, Node Reference, Option Widgets, Text, User Reference
FileField 6.x-3.0-alpha2
Includes: FileField
ImageAPI 6.x-1.0-alpha2
Includes: ImageAPI, ImageAPI GD2
ImageCache 6.x-1.0-alpha2
Includes: ImageCache, Imagecache UI
ImageField 6.x-3.x-dev (2008-Aug-08)
Includes: ImageField
Mollom 6.x-1.3
Includes: Mollom
Pathauto 6.x-1.1
Includes: Pathauto
Token 6.x-1.11
Includes: Token
Themes
Nitobe 6.x-1.6
Includes: Nitobe
#42
same issue here. using drupal 6.4, core locale module enabled, 2 languages (en & tr) activated, tr is the default.
#43
Same issue after Global Redirect upgrade to 6.x-1.0.
Environment: Drupal 6.4, all of contirbuted modules disabled but Global Redirect; just Polish translation enabled and set to default, language selection set to none (site is not multilingual, not using prefixes or any other method to select language). Clean urls enabled, rewrite base set to "/" (as it should be).
Trying to visit "www.example.pl/aaa" gives a redirect loop.
None of:
- undefining rewrite base,
- changing language selection method (to any of four available),
- disabling Content translation & Locale
helps.
Disabling Global Redirect or commenting out lines 82-84 in globalredirect.module does help.
These lines are:
if ((empty($language->prefix) ? $alias : $language->prefix .'/'. $alias) != $_REQUEST['q']) {
drupal_goto($alias, $query_string, NULL, 301);
}
For the example address above, values of variables before the statement are:
$_REQUEST['q']="aaa"
$language->prefix = "pl" (should it be defined, there's no prefix in the request?)
$alias="aaa"
$query_string=""
So basically, it checks that the request doesn't start with a prefix, it does not, and redirects again to the same place (without the prefix). Not sure if this is the real problem or not, maybe this will help understand what's going wrong nevertheless.
#44
subscribe
#45
haven't anyone try my solution at #24 (http://drupal.org/node/216271#comment-928145)? that's the essential solution to this bug. i think somebody with the right permission should commit it to the core.
#46
@wilson98:
Doesn't work for me (neither does replacing $_REQUEST['q'] with $_GET['q'] in the globalredirect.module; also it can only help when using prefix negotiation which is not the case), however you seem to have found another problem ;)
$_REQUEST doesn't automatically update on changes to $_GET, a test of that. So, updating just one can cause trouble.
Nevertheless, isn't $_REQUEST supposed to equal merged $_GET, $_POST, and $_COOKIE (with a possibility to define overwriting order)? If so, rebuilding based only on a value from $_GET still seems risky to me, unless 'q' won't be ever defined through a form here. Separately updating q in all four arrays (where defined) would be safer.
#47
I am using Locale. After setting Russian language as default i cannot enter /admin page. Problem is "redirect loop".
#48
it seems that the system use $_GET['q'] as system path and $_REQUEST['q'] as request original path for other modules such as globalredirect to use if needed, so it won't work if you just replace $_REQUEST['q'] with $_GET['q'] in globalredirect.module.
#49
subscribing...
#50
The problem I think lies in the fact that the following line of code in globalredirect.module does not account for the language_negotiation variable:
<?phpif ((empty($language->prefix) ? $alias : $language->prefix .'/'. $alias) != $_REQUEST['q']) {
?>
I have to little experience with the locale module to be sure what to change, but when language_negotiation is set to none, the language prefix should not be applied, even when it's non-empty.
#51
There was some discussion of the i18n_frontpage at the top of this issue. I'd just like to point out that i18n_frontpage does not work as an internationalised variable at the moment so don't rely on that in your tests. This doesn't change most of what is written here but might help some readers (see #249694: Multilingual front page and a "page not found" error).
#52
Does anyone have a plan of action in mind to fix this critical bug? Where do we start? Should we try to build a modified version of the patch at #153950: Endless loop with i18n (same problem in D5)?
Various comments show the the cause seems unclear... can anyone spell out what the patch should do to fix the issue or is it back to square 1: lots of testing still required?
#53
I can try to find a solution if I have time. I just need to know from everyone that has problems, the following data:
- List of languages that are active
- Links to the translations you are using
- Default language
- Your value for the language_negotiation setting (find it at admin/settings/language/configure) (None, Path prefix only, Path prefix with language fallback, Domain name only)
For me it would be:
- Dutch, English
- Dutch: http://drupal.org/project/nl
- Dutch
- None
#54
I agree with the comment #50. The code assumes that when $language->prefix is set drupal_goto() will add the prefix. This doesn't happen in two cases: when language negotiation is none or domain; or even when the negotiation is path based, but the requested language is the default one (see: http://api.drupal.org/api/function/language_url_rewrite/6).
Attaching a patch that makes globalredirect use the same prefix logic as drupal_goto() does. Seems to work but definitely needs testing ;)
#55
Can we please get the patch in #54 reviewed and tested please. Thanks for working on this guys. I am personally at a loss with it, I dont get all this i18n stuff ;-)
#56
I can confirm that it works for my use case (as described above). Thanks for the patch!
#57
Hi guys,
I never really worked with globalredirect before thus I never really experienced the previous bug. However I tried this patch out on two different installs - one path language negotiation and one domain language negotiation. Both worked nicely.
The only thing is that under domain language negotiation, a node link will still work in the wrong language - eg. you have en.ex.com and de.ex.com and you create English node 1 then you can still access it at de.ex.com/node/1 - which is actually duplicate content - however I suspect globalredirect always worked this way so therefore it's not part of this bug.
So I say apply!
#58
May be true, but it still is a bug, as Global Redirect promises single urls for all content.
#59
Yes, it's a bug. But not a bug related to this issue; and we like to keep issues to one issue per issue now, don't we? ;) So, goto() #201675: Redirect to version in native language and help with getting this glitch fixed. :)
For this issue's patch, it might perhaps be nice with a comment saying that the logic was lifted off of
drupal_goto(), so that if it starts working funky, one can quickly go todrupal_goto()and see if the logic has changed there. Just a suggestion, and definitely not something I'd want to remove the RTBC for. :)#60
Extended the solution to front pages (module handles front pages separately, somehow skipped that before), added some comments and replaced a single tab with spaces :)
One interesting thing is that language_url_rewrite() takes a path and does not use it at all (maybe it should be called something like language_options() and just take one argument?).
Could someone truly using a multilingual front page test it, please.
#61
Could you please clarify what you mean by this? Can you give us an example of one?
#62
I don't have any page that has more than one version of the frontpage. Not sure if I can reproduce the setup that such a site would actually use.
My test was: point Drupal to the front page for the default language and create a language specific aliases for other pages (for example with the path negotiation www.example.com/en and www.example.com go to the (default) English version, while www.example.com/es gets you to the Spanish version). It works, no redirection loops, but i guess there are other methods of making a multilingual front page, so the test may not be sufficient.
#63
I think your test is satisfactory. There is only one simple way to make a multilingual front page and I think it's what you've described. Set front page as (e.g.) 'home' and then create node in each language with alias 'home'. I actually tested the last patch with this setup and it worked.
The i18n_frontpage variable doesn't work at the moment without custom modules/core hacks so I think we can reasonably ignore that case until it's fixed in i18n (if that ever happens).