Steps to reproduce:
1. Create a two-language site (en,ru).
2. Bring a language switcher block on the screen (to content region for example).
3. Create a English node node (without translation).
4. Look to the language swithcher.
Expected results:
"English" link exists, "Russian" disabled (as plaintext).
Actual results:
Both links are present.
Additional details:
If you'll try to add Russian translation and than remove it, everything will work go as expected.
The reason of the bug is that we don't save tnid for newly created node. The translation_path_get_translations() function thinks that node is "All languages" and aren't disabling the language switcher links. If we'll save it as equal to nid, everything will work fine. I made a hook_nodeapi() work-around in my module to make this thing work as expected, but I think it should be fixed in core.
Comments
Comment #1
neochief CreditAttribution: neochief commentedOkay, after two days of testing I found that the better solution is to fix the Language switcher and do not touch tnid. Here's a patch, which fix Language switcher, so it correctly shows languages for nodes with only one language.
Comment #3
neochief CreditAttribution: neochief commentedupdate for tb.
Comment #4
quasi CreditAttribution: quasi commentedThanks neochief, your patch works as expected, it hides the language link if the content isn't translated.
Would it be possible to keep the language links and make them link to the frontpage?
Comment #5
neochief CreditAttribution: neochief commented> Would it be possible to keep the language links and make them link to the frontpage?
Well, yes, but I think you should create another issue for this.
Comment #6
webchickThe original post has a wonderful test case for replicating this bug. Let's please get this captured as a SimpleTest so that we don't ever break this again.
Comment #7
fabius CreditAttribution: fabius commented6.14, two languages (es, en), two menus (one for each)
Another aspect of the language-switcher problem is language updates. Currently, my preferred method is delete the language you want to update, ignore the dire warnings and then add the language again. It works fine and nothing is lost but all nodes are set to "All languages" (logical but irritating) and weird things start happening to the switcher and menus. I edit all nodes and set them to the corresponding language and I have to edit the menu items as well. But it would be nice to just "add" the language a second time and overwrite the existing po. This is not possible because if a language is currently installed, it vanishes from the list of available languages.
If anyone wants a detailed description of the problems I would be happy to put one together.
fabius
Comment #8
Ryan Palmer CreditAttribution: Ryan Palmer commentedI think the language switcher is still useful in terms of switching the interface language. Maybe it's still too misleading, I'm not sure. But the multilingual elements of any given page extend much farther than the contents of the node itself.
Comment #13
MPeli CreditAttribution: MPeli commentedI have replaced code on line 325 in translation modul with code in patch. Now everything is working. When a page doesn't have translation, links in language switcher are hiden.
One exception is in the forum. When I create it in one language, language swicher shows links to all language verions (which are not exists). It is probably because variable "path" contains string "forum" and can't go trought the regular expression.
Comment #14
Stephen Scholtz CreditAttribution: Stephen Scholtz commentedI came across this issue because I was trying to solve the same problem for Drupal 6's language switcher.
Not displaying a link to the other languages on the system when a translation doesn't exist seems consistent with the way the translation links show up inside the $node->links list, so that seems best. But if the community decides the links should be present for some reason, I'd just suggest adding some CSS hooks so themers can determine what to do with those extra bits.
FYI, in an informal survey with my designer/IA friends, they suggested that the link should remain, even if a translation doesn't exist, as a language switching link is kind of a "utility" link that should always remain on the page. Clicking the link should take you to a "404" (there's a module for that - Translation404) that presents the user with information on why the page isn't translated. (maybe it just hasn't been translated yet, or the service/product offered in English is not available in other languages)
Cheers...
PS - here's the link for the D6 issue: #340527: Language Switcher links when there is no translation. This is my first time looking into core code, so I'm not sure what the protocol is for requesting backports? :P
Comment #15
plachActually this is a bug. I rerolled the patch with a couple of fixes, we still need tests though.
Related issue: #631928: Language switcher block does not handle a single link correctly.
Comment #16
plachComment #17
Ryan Palmer CreditAttribution: Ryan Palmer commentedRe #14:
I agree, language switcher links should appear whether the node is available translated or not. The language switcher block is provided by Locale module, which is about interface translation and not really content translation.
translation_language_switch_links_alter() runs translation_path_get_translations() to modify the language switcher links to reflect translated content. I think unset($links[$langcode]); in the translation_language_switch_links_alter function is meant to unset language links when a translation doesn't exist, but this won't happen as far as I can tell because the unset only runs on the $links array contents in the foreach loop.
Perhaps those lines should be removed? Patch updated, take a look.
Comment #18
Ryan Palmer CreditAttribution: Ryan Palmer commentedOne other thing..
I don't think node links should contain language switcher links if the translation doesn't exist. The problem is the interface switcher links for the block currently come from the same set of functions.
http://api.drupal.org/api/function/translation_node_view/7
translation_node_view() seems to care about what translation_node_get_translations() has to say -- and this works for sites with only 2 languages, and for content with no translation. But for sites with more than 2 languages, if a piece of content is translated into any one of the other languages, switcher links will be shown for ALL other languages. I've verified this on the latest HEAD.
Steps to reproduce:
- install 3 or more languages
- create content in any language.
-- No node links are displayed for switching languages
- translate the content into one other language.
-- Language switcher links for ALL languages, even the 3rd language the content has not yet been translated into, are shown when, IMHO, it should not be.
Comment #19
Ryan Palmer CreditAttribution: Ryan Palmer commentedHey test bot
Comment #21
gowriabhaya CreditAttribution: gowriabhaya commentedCode sprint tag
Comment #22
plach@Ryan Palmer:
Thanks for helping, I tried to reproduce #18, but I could only by applying your patch from #17.
Anyway, I think we should clarify some aspects before going on with working on a fix. Please follow up on #778528: Define the language switcher's correct behavior.
Comment #23
GiorgosKAdding to the original post discussion
another reason why tnid should be defined when node created is Uberact stock
#618150: Stock level for views filters of translated products
Comment #24
GiorgosKSince the tnid is needed to be defined for language switcher + other modules/functions (ubercart I have personally discovered) why can't it be set at the time of the creation of node (set it to nid)
workaround that works for me until a proper solution is found (since this behaviour creates A LOT of duplicate content with google and I just discovered it)
Created a simple module and enable
run an sql query to create tnid for all nodes with tnid as 0
and redirect by hand in .htaccess all duplicate content (global redirect or path redirect modules could not handle that)
Comment #25
good_man CreditAttribution: good_man commentedI think displaying a disabled link for languages that have no translation in node view is better than not displaying them at all. Language Switcher should remain as consistent as possible IMHO.
Comment #26
plach#15: translation-518364-15.patch queued for re-testing.
Comment #27
plachRerolled after the latest commits. I am planning to implement a complete test covering the translation links' expected behavior, so we need just someone reviewing and testing this.
Moreover with the changes introduced #780316: Missing node translation links when no language detection is configured we are able to unbind the language switcher links from the available translations by just changing the
'translation_language_type'
system variable toLANGUAGE_TYPE_CONTENT
.Comment #28
plachSee #778528-12: Define the language switcher's correct behavior.
Comment #29
sun1) There should be a space after (int).
2) It looks like the PCRE pattern can be simplified:
Wrong string concatenation coding style here.
As @plach just explains me that this is targeting the scenario of a difference in interface and content languages, we should really put that information into code.
Lastly, we need to add tests to prevent this bug from appearing again. Also, it would be nice to see a better issue title; a short summary of the actual bug.
Powered by Dreditor.
Comment #30
plachThanks sun! The attached patch implements #30.
The PCRE has been simplified but the trailing segment has not been removed to keep line 491 working:
WRT tests, as I said in #27, I'd like to provide a unique, comprehensive, set of tests covering the translation switch links behavior. #366768: Translation links link to unpublished translation already went in without testing coverage.
Here is a summary of this issue: there is an inconsistency between the behavior of nodes with more than one translation and nodes having translation enabled but not having been translated yet. In the former case language switch links for which a translation is not available are removed from the language switcher, in the latter case language switcher is left untouched. This is the expected behavior when the node is not assigned a language, but when it has one it should affect the language switcher.
The correct behavior should be: either completely hiding the language switcher if we have a single translation available and the current language matches the node one, since we have no translation to switch to, or showing a single language switch link pointing to the translation language (the right language). E.g.:
-
node/1
is a French node-In
/fr/node/1
we should have no language switcher block-In
/it/node/1
we should show a language switch link pointing to/fr/node/1
Some people here were arguing that the presence (or absence) of translations should not affect the language switcher block at all, as it concerns interface language and not content language. This is a very good point, AAMOF we introduced a system variable in #780316: Missing node translation links when no language detection is configured allowing to choose which language type the translations should affect. If configured properly this variable allows to have a language switcher block which is completely independent from node translations.
Comment #31
sunHm, I see. So to make sure we capture the entire path suffix, we'd have to do:
@^node/(\d+)(/.+)?$@
"Change the language switcher links to point to the node translations. Also show a (single) switch link, in case no translations exist, but the current language differs from the source node language."
Additionally, it would be nice to flip the secondary conditions around to match that comment; i.e., check $translations->status first, and empty($translations) second.
Powered by Dreditor.
Comment #32
webchickplach took a good half hour or so to explain this issue to me on IRC. For those not in the know, here's what happens:
In D6, if you have 3 active translations (english, french, italian) and create an english node, the language switcher block shows up and has 3 links in it (/en/node/12, /fr/node/12, /it/node/12). The links don't actually show the node in french/italian, since there aren't translations for those yet, but they do switch the interface. To me, that seems frightfully confusing because I would expect when I click a link called "French" it would start telling me "bonjour" in my content, not just in my interface. It gets even worse, because when you *do* post the French translation of the node, the "Italian" link goes away. WTF?
This patch would change behaviour so if there was only one translation (English), it would remove the language switcher block altogether so people don't get dumb links. I understand the rationale for this change and why it's an improvement, but it creates a sub-optimal browsing experience. It's going to appear to the end user as though the site is buggy, because sometimes that block appears and sometimes it doesn't. It's also going to make the site harder to theme because you have to allow for both visual representations on the page.
To me (someone who doesn't do i18n sites, so take that for whatever it's worth), what makes the most sense is for the block to always be there, showing three items in the list, but only link those with an active translation. So when I've created just an English verison, the block would show:
When I have English and French, it would show:
...and so on.
To me, the behaviour in D6 is clearly buggy (or at least "buggish"), and the proposed patch just substitutes one buggish behaviour for another. If we're going to fix this, I prefer we fix this properly, in a way that respects both UX and i18n best practices.
Now, while normally it's quite clear in my mind of what is/isn't appropriate in the Post Beta Drupal 7 World, I'm really not sure whether in this case it's too late for this change or not, because I don't feel I can judge the impact this has on people building i18n sites. So I would prefer to defer to others more closely involved on that as to whether this is D7 or D8 material. My hunch is that most people won't be building i18n sites until RC1 when we hit a "hard" string freeze, so we probably still have a little bit to make this subtle change, but I of course won't disagree with someone more closely involved who says otherwise.
Comment #33
plachPersonally I agree with the solution proposed by webchick. I would adopt it myself if I didn't think it was too late to implement this change. Other people here suggested to have a link to a 404 page explaining that the node has not been translated yet, but this would be quite a bigger change, while a link to the front page would be as confusing as a disappearing one.
Since we would retain the ability to disconnect the language switch links from the available translations, I think this is the most promising solution. AAMOF, as webchick pointed out in IRC, we could always make the language switcher block disappear when only one link is available through a PHP block visibility condition.
Comment #34
sunwebchick's suggestion seems to be in line with the expectation of the original poster. Since there is no working i18n module for D7 yet, I don't think that there are any multilingual sites in the wild yet. Also, the resulting difference will be minimal, as the content actually remains the same, there's just no link.
Comment #35
Jose Reyero CreditAttribution: Jose Reyero commentedI'd say the only bug here is inconsistent behavior, that it shows all language links when there's no translation, shows not all if there's one translation, etc...
So IMHO every solution proposed here is ok as long as it is consistent. Then how it should work depends on whether you want an interface language switcher or not, want it to be the same as the content switcher or not.
It is also confusing for users navigating multilingual sites that language switching links go on and off on every page. I think I suggested on some other thread I cannot find that we should separate interface languages and content language blocks, or just implement one or the other but not 'both in one'.
How I think it should work?
1. Having all language links on every page.
2. When no translation is present just switch the interface + a message on top like "This content is not yet translated to xxx, you can see the (default language) version here."
Whatever you do is going to be confusing because while hiding language links is confusing, redirecting to main page when the user expects a translation is confusing too.
From my experience, the real problem is: there's no stablished behavior through the web so users just don't have consistent expectations about it. This would be a clear case for some UX testing, running both options and deciding by majority's expectations.
One example. If a run a commerce web site, I want the guy to see the article on whatever language (Better buy English than nothing) but still having the shopping cart links in their language. While if I run a community documentation site, what I want there is some 'There's no translation, create one' page.
(Note that on both cases redirecting to home page would screw up either my sale or my translation, and possibly let the user wondering 'wtf have I clicked')
How I would like this to be fixed? I really don't mind as long as it is consistent (either all links for all pages, or just translated content for all pages), either show translated interface with node in default language, or show nothing (that shouldn't depend on whether the node has a language or not in the first place)
The thing is, whatever we get here, we're going to need the other option for some site so we'll need to implement the other block into i18n. If we have already one that works for some people would be some help though. So better no middle ways here, just go for one of the options, someone will take care of the other one. Adding a block is no big deal anyway.
Comment #36
webchickI'd have to -1 that. That creates inconsistent behaviour for users. Sometimes when I click that "French" link, I get a message. Other times when I click that "French" link I get French. There's no way for me to tell in advance what I'm going to get when I click it, and there's no way for me to get a visual clue when the translation /has/ been added after the fact, so chances are I'll never go back and click it again and will instead just be irritated that your site lies to me and says French is there when it isn't. Unless we start naming these links "English (translation available)" or something, and that's a major change so I'd have to -1 that, as well.
"Whatever you do is going to be confusing because while hiding language links is confusing, redirecting to main page when the user expects a translation is confusing too."
If we're redirecting to the main page when I click "French," I agree that's totally confusing. Only links labeled something like "Home", "Front page", etc. should link to the front page.
But I'm not sure it's confusing for links to be there sometimes and other times not; I would argue the inverse. There's a post about this at http://www.ixda.org/node/18595 (there are others like it elsewhere on the web), and the guideline agreed there looks like a pretty solid one:
So in the case of a translation link, which may currently be unavailable, but which may become available later on when the system changes state (has a translation available), the correct course of action is to disable it, which, for links, means removing the link and leaving only the link title.
But in the case of something like the "Edit" tab on other peoples' nodes, or the "Administer" page, those should always be hidden to people who can't ever access them. And that's what we already do in Drupal via the permissions system.
"While if I run a community documentation site, what I want there is some 'There's no translation, create one' page."
This is indeed a valid use case, but I think is a great argument for contrib filling in holes that don't meet 80% of sites' needs. Perhaps i18n can include this block, or maybe more appropriate for something like L10n client/server.
Comment #37
GiorgosK+1 for webchick's solution on #32
This is what I would expect from a "Content Language switcher"
it could go in D7 as well as D6
Perhaps a configuration option "display NON translated languages ?" would be useful
Comment #38
Jose Reyero CreditAttribution: Jose Reyero commented@webchick,
Well, yes, I think you are right, but also everybody else is right here (me included :-) ), because it all comes down to user expectations and we don't have the numbers for that (Also no one here is a 'typical web user' I'm afraid raising hands would be mostly a waste of time).
So, about what you describe, as I said above, I just want a consistent behavior, and it looks consistent to me. So Drupal core language block will at least cover one user story.
I'm really ok with that (and I'm also ok with the patch).
I hope I will be able to collect some numbers for the upcoming Drupal 8 discussion about the very same issue ;-)
As a side note, just for whom it may interest (really I don't want to go on with the discussion here, just close the issue asap), expectations from people in a bilingual country may differ from people around the world. They actually may get angry if they don't get the translation in their language..... While on other places we may be happy enough if the site has "Spanish" link though we never actually click on it because you usually get a really bad outdated translation most of the time. (Though there are bilingual regions in Spain too and yes, I can tell you they get angry all the time...). Then hiding the links, sure is a good 'angry prevention' policy.
Comment #39
plach@webchick:
I may be wrong but my interpretation of the cited paragraph is slightly different: the control should be disabled when the user can take some action to enable it. In our case the user can do nothing but wait for the translation to be published; since the user should not see controls he won't be able to work with, IMO we fall back to the initial solution: removing the links. Alternatively we might set up a tooltip through the
title
attribute on a disabled link warning the user that the translation is not available yet.@Jose Reyero:
I fully agree that we cannot cover all the use cases with the core language switcher.
Just a side note: in D7 Locale provides a language switcher block for each configurable language type available in the system. In core the only one is interface language, but we introduced a system variable letting the site builder decide which language switcher block the presence/absence of content translations should affect. By default we get the behavior described in #32, but we can untie content translations from the language switcher and get a simple UI language switcher.
In the Translation project also content language is made configurable so we have two language switcher blocks a user can choose between.
Comment #40
plachHere is a patch implementing the approach suggested in #32. The only difference is that language switcher items corresponding to missing translation have a strikethrough style to provide a visual clue besides color that the item is not clickable (see the attached screenshots). The CSS style was already there, the patch simply reuses it.
@sun:
The patch does not include the suggestion above as using the "| empty string" form allows to always have a
$matches[2]
element defined (albeit empty). Otherwise we'll have to add a check to avoid notices when the trailing segment is missing.Comment #41
sunWorks for me.
Comment #42
plachrerolled
Comment #43
plachWhile writing the tests for this in #778528: Define the language switcher's correct behavior I discovered that the previous patch was not behaving as intended. Here is a working one.
Comment #44
plachwrong string concatenation
Powered by Dreditor.
Comment #45
sunThanks!
Comment #46
webchickWanted to let this sit for a few days to see if anyone was opposed to the strikeout styling of the block on non-translated languages, but since only plach and sun have responded, I'm guessing either this isn't contentious or else people are slackers and not reviewing this patch. ;) Well, it'll be easier to review when it's in HEAD I suppose.
Committed #44 to HEAD.
Comment #48
comfused CreditAttribution: comfused commentedwill there be a backport for D6 ?
Comment #49
plach@comfused:
Honestly I don't think so: it's a significant UI change for a stable branch.
Comment #50
Andrew Answer CreditAttribution: Andrew Answer commentedMay be my last patch can help to D6 users, see http://drupal.org/node/237696#comment-3798330
Comment #51
egon.ojamaa CreditAttribution: egon.ojamaa commentedHey drupal fans..
Here is the fix you need.. http://drupal.org/node/995500
No core hacking, and no waiting for backports.
Comment #52
Dret CreditAttribution: Dret commentedModule posted by egon.ojamaa work fine only on Drupal 6.19.
But after some bug fixes in Drupal 6.20 about 'tnid' that module start to break the translation system: every new translation are considered "stand alone" nodes not related to the same "translation group".
Waiting for a patch...!
Comment #53
Dret CreditAttribution: Dret commentedSorry, I forgot to reopen the status!
Comment #54
miro_dietikerRemoving tag.
Dret: There's no official module from egon.ojamaa.
Drupal core issue queue is NOT the right location to refer to custom modules. Please first start maintaining the module and provide custom issue queue. Or describe a simple case to reproduce the issue happening in core.
Without your custom module drupal core does it perfectly right, building translation groups.
It even also releases tnid after deleting the last translation (not the source language) in a translation set.
I've just tested many sequences i can think (add, update, delete) of with the result that i consider this rock solid clean core behaviour.
Comment #55
Dret CreditAttribution: Dret commentedThe real problem is one indicated in the first post by neochief, still present in Drupal 6.20 core without a clean solution (avoiding core haking). The unofficial module indicated in #51 was a good solution for 6.19 core version.
Comment #56
egon.ojamaa CreditAttribution: egon.ojamaa commentedmiro i know i know... i also dont know how much time it takes to make / maintain a module properly here... and no time to learn cvs at this year. But i know how to use a forum and i alrdy got the fix.
Anyone is welcome to make my module into project.
Anyway.. wanted to say i fixed it for 6.20 happy using.
http://drupal.org/node/995500
Also.. this isse (1) and (2) i talk about in my posting is very well documented and it has many patches for core. But it's not just implemented and i dont got time.. the module fixes all issues without waiting a patch to make it to the real core release.
Comment #57
plachFollow-up issue: #1060246: Translation alters language switch links even if node translation is disabled.
Comment #58
neochief CreditAttribution: neochief commentedHere's a backport from D7 with slight modification (there's no LANGUAGE_NONE in D6, so we need additional check in the alter function).
Tested on D6.20. Could somebody test as well?
Comment #59
neochief CreditAttribution: neochief commentedI forgot that D6 code standards are slightly different. Here's a new version without a space after '
Comment #61
neochief CreditAttribution: neochief commentedComment #62
plachWe should take into account the followup patch: #1060246-13: Translation alters language switch links even if node translation is disabled. Probably we should wait for it to be committed to D7.
Comment #63
neochief CreditAttribution: neochief commentedThanks, I already reviewed your patch but there's nothing related to D6 version left in it. I handle your edge cases in mine (it's a bit different in D6). Let's commit this one, as it D6 stuck here for 18 months already.
Comment #64
knalstaaf CreditAttribution: knalstaaf commentedI'm a bit confused because the topic started as a D6 issue, but in the details of the translation-518364-44.patch I find "Branch: Drupal core - 7.x", and the Nodes-with-one-language-dont-affect-the-language-switcher-block-518364.patch seems to have failed the SimpleTest.
Is there a stable D6 version available of the patch or is it not being released so far? Thanks for the clarification :)
Comment #65
dagomar CreditAttribution: dagomar commented2 years and still no fix :-S
Comment #66
mohamadaliakbari CreditAttribution: mohamadaliakbari commented#1: translation-fix-language-switcher-to-work-with-single-translation.patch queued for re-testing.
Comment #67
Jon Nunan CreditAttribution: Jon Nunan commented#61 works for me in D6.
Comment #68
danilou CreditAttribution: danilou commented#61 Appear to work for me too in D6
Thank you ;)
Comment #69
ohadgolan CreditAttribution: ohadgolan commentedPlease help applying the patch, i am new at this and think a step by step guide can help a lot of people.
Thanks
Comment #71
Bertjuh CreditAttribution: Bertjuh commentedI have this multilanguage thing on my D7 website and the language switcher worked perfectly. The links were not clickable and had a strikethrough when the translation was not available, or when content was not yet translated.
Then I did something and now the language switcher will show only the node's title for content that is not translatable. And it throws an 'Access denied' for content that is not yet translated.
I think this has something to do with Entity translation module. Maybe it is conflicting with this module, since it has an option 'Enable language fallback'. Although it is disabled in my installation.
* MY FIX:
- Disable and uninstall the Entity translation module.
- edit the content-type and disable the multi lingual support and then re-enabled it.
- Fixed.
* Break it again:
- re-enable Entity translation module.
Apparently there is some more info here: http://drupal.org/node/1147046#comment-4526326
Comment #72
operinko CreditAttribution: operinko commented58: Nodes-with-one-language -dont-affect-the-language-switcher-block-518364.patch queued for re-testing.