This patch adds a language switcher block into locale module. The intention of this is to allow anonymous users to switch the interface language, and also to allow other modules to replace these links with different ones that may be translations of the current one:

- It builds a collection of links, with native names of languages as text
- Invokes 'drupal_alter('translation'...) to allow modules to change the link for each translation. it may be a node translation, it may link to an external site for some languages, etc...
- Provides two theme functions, 'language_item_list' and 'language_link'. The first one may be used i.e. to remove current language from the list if desired. The second one will allow link by link theming, adding i.e. a language icon...

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

Gábor Hojtsy’s picture

Status: Active » Needs review

As far as I see, this is one of the simple low hanging fruit tasks, which in turn help raise awareness that Drupal is becoming a multilanguage system. Creative use of drupal_alter() to allow modification of the links by contributed modules, to link to translations of the same content for example :)

Dries’s picture

Screenshot? Might help those that are not eager to setup a multi-language site just to test this patch. ;-)

Dries’s picture

Btw, we don't use underscores in class names ...

   // Allow modules to provide translations for specific paths
+    drupal_alter('translation', $links, $_GET['q']);

Is that how we are going to deal with all links? Shouldn't we have a generic solution?

Gábor Hojtsy’s picture

Dries, the "generic solution" for paths themselfs already exists. You pass a "language" key in the array to url() and you get the URL proper for that language (depending on the language negotiation settings). Drupal 6.x-dev has no concept of "node translation" yet (and because object translation needs significant core modifications and node translation requires close to zero code modification, we are pushing with object translation first).

The code in url() expects that prefix swapping (path or domain) and path alias lookup by language is enough to provide a language version of one Drupal path. If a node translation system is in place, where different translations of the same content are on different paths, that does not stand anymore. But there is nothing in core yet, which would require it. We might as well go with some generic extension of url(), as with the language prefix swapping implementation, but via a contrib hook/callback, because we have no rule to do the replacement in Drupal core.

Jose Reyero’s picture

FileSize
10.62 KB

Attached screenshot as Dries suggested. It's a simple block.

Dries, about class names you mean just

'attributes' => array('class' => 'language_link')

right?

Also as Gabor mentions in #1, this is not a critical feature and it's about Drupal 6 starting to look & feel multilingual, so I can maybe simplify the first version and remove some theming stuff if we can get this done faster.

A language switcher for anymous users has been long time missed in Drupal though.

Dries’s picture

Goba: if there is a dependency on node translations, we might want to work on that first?

Gábor Hojtsy’s picture

Dries, this language switcher block would work for anonymous visitors to change the language on any page. On node pages, it would need to look up the URL for the translation node, sure. If node translation is supported. We have a simple and small patch for node translations (actually no changes to Drupal core but a module with an info, an install and a module) file waiting for reviews: http://drupal.org/node/142280

Jose Reyero’s picture

About node translations, they can be done using the hook_alter. Besides nodes, it is an open solution that will allow any other module to translate other kind of links. I.e. someone may implement a taxonomy translation solution, or a link to external translations using that hook.

Though the block feature is not specially critical, as any contributed module can provide a new block, I've realised with current i18n module -it provides a simple language switcher and a translation blocks- that having more than one similar blocks is a major mess for many users.

That's why I'm proposing this single block, with links that may be rewritten by any other module.

Gábor Hojtsy’s picture

Jose, Dries probably meant: What about links printed out of the block? How will those be transformed to point to translated versions?

We already have a "link translator" in url() reusing language.inc, so it might as well be logical to do the transformation there (via a hook or callback to an external transformation implementation) if a specific language version of a link was requested.

Dries’s picture

Status: Needs review » Needs work

I'm getting a bit confused here.

My (original) question was: what does "drupal_alter('translation', $links, $_GET['q']);" enable that l()/url() can't do already?

The various answers that I've read, don't seem to clarify this point. I'd like to see the answer documented in the code as well.

+    // Allow modules to provide translations for specific paths
+    drupal_alter('translation', $links, $_GET['q']);

should become:

+    // Allow modules to provide translations for specific paths.  This
+    // enables to do A, B or C.  Neither of these tasks can be 
+    // accomplished by either l() or url(), hence the special handling
+    // of these links and the requirement of this drupal_alter() hook.
+    drupal_alter('translation', $links, $_GET['q']);

In other words: I'd like to know what A, B or C are, and maybe also why this can't be accomplished by l() or url().

The underlying architectural question (which isn't answered in the documentation either) is why we can't generate the correct links in the first place. I was hoping to get some non-confusing answers for this. ;)

The question that underlies the underlying question is: why do we want to use non-predictable paths? What is wrong with using well-structured paths?

PS: we don't use underscores in CSS class name.

Jose Reyero’s picture

Assigned: Unassigned » Jose Reyero
FileSize
2.36 KB

Sorry Dries, I was missing the sense of your question.

In the l() and url() functions we are just aliasing, using the right path alias which may depend on the language of the link target.

To produce 'translation links' on the other side, we will be making decisions on the kind of link it is, the kind of object it points to, and also whether there's a translation for this object/page -may be a node- or not. This is really some more complex logic and we don't need it for most of the links in the page, which will be straight links to things in the current language, and that's why we better accomplish it with a more targetted hook, that also is not called for the hundreds of links a page may have, just for a few of them, the ones referencing translations.

Also, as it's not clear yet, how we are going to handle translation links for things different of nodes, we are also contemplating the possibility of allowing other contributed modules to add solutions here and that is why the solution is open; we pass the links along, we will handle node translations if the translation module gets into core for Drupal 6, but the rest will be up to other modules...

Here's the patch with that class name fixed and some more explanations

moshe weitzman’s picture

subscribe. maybe output the list via theme_links(). see http://api.drupal.org/api/HEAD/function/theme_links. just an idea.

Owen Barton’s picture

Subscribing

David Lesieur’s picture

Someone reported: "This block only works when you select either of the two path prefix options in Language negotiation. We didn't test it with the domain prefix options."

This seems more like a usability problem than a bug. Should a message be displayed if the block is enabled when Language negotiation set to None?

meba’s picture

subscribe

Gábor Hojtsy’s picture

Jose, Dries tried to point out that if we do a url('node/12', array('language' => 'it')); what would we do? The problem with only solving this problem in the translation links block is that others cannot link to translations if they wish.

Jose Reyero’s picture

moshe,

The theme_links function would work, yes, but these are very specific kind of links that may need specific themeing, like playing with language icons, not displaying icon, not displaying text, just icon, etc.... So I think these additional theme functions make sense.

Gabor,

Not sure what you are talking about, but if it is linking to a translation that doesn't exist yet, we are linking to the page with the switched interface, blocks, etc, but the same content. I don't see anything wrong with that.

Gábor Hojtsy’s picture

The url('node/12', array('language' => 'it')); example was meant as a pointer to how would people be able to generate node translation links outside of this block. What if node 12 is a French node and it has an Italian translation? So when I do this url() call, it would change the link to point to the Italian node I guess, if it would be possible to have such functionality outside of the language switcher block.

Quoting Dries:

... what does "drupal_alter('translation', $links, $_GET['q']);" enable that l()/url() can't do already? ...
... why we can't generate the correct links in the first place? ...

So as far as I see, his question is: how would we generate translation links out of the block? Why is l()/url() not capable of that?

Jose Reyero’s picture

So as far as I see, his question is: how would we generate translation links out of the block?

i think that should be a problem for translation.module, not for a simple language switcher. But basically, the answer is that how we translate each link depends on the kind of link it is and the kind of object it links to, so this is not a trivial question and may need to be handled by several modules.

All we do here is to pass the link to hook_alter('translation'...) so each module that knows about a specific kind of path has a chance to translate it. But maybe we'll be able add some api function into translation module.

Why is l()/url() not capable of that?

In short, performance. I think this one is better explained in #11

Gábor Hojtsy’s picture

This patch is really simple and people had two issues with it so far:

- the translation callback: as you said performance implications make it hard to do it in url(), as we need to call out to hooks which implement translation for different Drupal objects, which would be a big performance hit for most links

- using theme_links(): I looked into http://api.drupal.org/api/HEAD/function/theme_links, and it does a nice set of cool stuff, allows non-links even with span wrapping, so it would indeed be nice to reuse this. As you pass on the language-link class anyway, and the hooks you call can add even more distinguishing information, your theme implementation of theme_links() can easily tell if it works with language dependent links.

As far as I see, we can reuse theme_links() here, but as it seems implementing translation links with url() does not seem to be likely.

Dries?

druvision’s picture

Hope this is the right place.

I've installed the Language switcher patch, and activated the block, but somehow it remains invisible.

Amnon
-
Professional: Drupal Search | Drupal Israel | Web Hosting Strategies
Personal: Hitech Dolphin: Regain Simple Joy :)

Gábor Hojtsy’s picture

Assigned: Jose Reyero » Gábor Hojtsy
Status: Needs work » Needs review
FileSize
3.21 KB

To help this patch get in, I updated the patch with the issues raised and some others that come up while coding:
- only show the block if we have more then one enabled languages
- only show the block if we have language dependent URLs, so we can actually link to different languages
- tried to add a help text to this block's config form to explain this, but it is not showing up (help appreciated to find out why!)
- only show links to enabled languages
- renamed the alter function from 'translation' to 'translation_link', because this does not do *translation*, it "only" alters links
- removed the custom theme functions and reused theme_links

The patch also needed to be rerolled against current Drupal 6.x-dev.

Issues to resolve:
- whether it is fine to go with the alter method used here
- make the help text for the block show up on the config page

Please discuss/help!

Gábor Hojtsy’s picture

Levavie now runs a test site with this patch and the bluemarine RTL patch applied, so you can see how Drupal can handle RTL sites out of the box with these two patches: http://groups.drupal.org/node/4256 This also means that he has no issues with the block anymore (expect that he would like to see an option to remove languages from the list, but I don't think that belongs in here, as we are linking to all enabled languages).

Jose Reyero’s picture

Issues to resolve:
- whether it is fine to go with the alter method used here
- make the help text for the block show up on the config page

For the alter method, I think it's fine given that we don't have a generic solution for translation links -yet.
About the help text, it looks like a bug in help system implementation that doesn't really provide page information for block settings, it just passes 'admin/build/block'...

I think it would be nice to have a minimum block switcher into Drupal just to make visible the low level multilingual capabilities we've implemented so far. This is quite basic, but we can extend it later if needed, can't we?

Gábor Hojtsy’s picture

Thanks Jose for the pointer, the help display problem was indeed in menu_get_active_help(). Unfortunately it did support paths provided only in the menu hook, so it was really not possible to provide help for the actual $_GET['q'] at hand, only for the rather generic menu item string. A quite straightforward fix included, and updated the patch to latest Drupal 6.x.

pwolanin’s picture

Status: Needs review » Needs work

$_GET['q'] is not the answer for the menu part, since you may have additional elements in the path that are not part of the router path. I'd suggest instead that we borrow from the way the menu link is constructed, and put the un-mapped router path into $item['router_path']- or even into $item['help_path'].

Gábor Hojtsy’s picture

Well, we are about to put help text on "admin/build/block/configure/locale/0" which has a menu item defined for path "admin/build/block/configure". What would the router path be in this case? We need it to contain locale/0 since we are presenting help text for the locale block specifically. How is a router path different from $_GET['q']? (I envisioned $_GET['q'] would be too simple here, but it would be nice to understand how the router path would help us more).

pwolanin’s picture

Hmmm, perhaps I'm confused about what you want to do.

The router path is what is defined in hook_menu. I thought you wanted to present the help same help for all dynamic paths (e.g. for node/%/edit).

In your case, if only 'admin/build/block/configure' is the defined in hook_menu, than that's the path. The menu item should also have a component corresponding to the $_GET['q'] - I think this is in $item['href'].

In the past, hook_help has been based only on what's in define in hook_menu. I can think of a couple approaches- modify hook_help to take 2 arguments (path and href). Or pass the menu item as a whole to hook_help.

Gábor Hojtsy’s picture

Yes, node/%node/edit as $section in hook_help() does limit the usefulness of the help hook considerably (you can't set up a help tip for your about page for example, so the secretary knows some hard rules when updating it :). There is a user help module (don't know the real name), which allows you to tie custom help texts to paths on the web interface, and this becomes a real limitation. Menu paths used to be more telling, before these nice wildcards came in.

Anyway, the issue at hand here is that we would like to add a help text directly to the block admin page, which would need the whole $_GET['q']. But the help discussion is unrelated here. Will open another quick issue tomorrow with a simple patch. Will post a link here, and we make this issue blocked on that (if the help text on the block is desired at all).

(I need to prepare for a final exam for tomorrow, so I'll try to concentrate to that for now :)

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
5.57 KB

Here is an updated patch, which includes the node translation part moved to here as suggested by yched. After some testing and fixing smaller issues, this one works nicely with simply language URL modification and node URL swapping on node URLs. Reviews, testing is welcome.

The patch still includes a "dummy" fix for the help hook, which makes it possible to provide help text for the block.

I should note that the translation links did not check whether you have permission to view the pointed translated nodes. It might be logical to check that.

A question is still up: what to do if we don't have translation of a node in a language (or we don't have permission to that node)? Omit the translation link?

pwolanin’s picture

Status: Needs review » Needs work

I don't really think it makes sens to pass in $_GET['q'] instead of path, since $_GET['q'] is global anyhow. You could use $item['href'], or again, pass in the whole menu item.

Also, like the recent tabs patch, that code doesn't actually work if there is more than one level of tabs. The smart thing to do would be to refactor function menu_local_tasks() so that the correct 'href' value for any default local task is available and filled automatically by _menu_translate().

Gábor Hojtsy’s picture

Well, here is a spin-off patch: http://drupal.org/node/154064 I really believe this should not be a so complex issue to chew at for weeks. I'd love to look at much more important patches, but as long as I need to nurse my own patches from day to day, I cannot look into lots of innovative stuff. We already have a half baked language system in Drupal 6, and I got a note not to leave it at that. I can chew this on for another two weeks and leave the other important Drupal 6 issues in the dust, but I am not sure this is a good idea.

You help me to have time to review core patches by helping take off at least a few of the core patches I nurse myself... These issues are not something I have the exclusive know-how to do, rather the contrary. Drupal could be better if I take my time with more innovative stuff, don't you think?

pwolanin’s picture

http://drupal.org/node/154064 should be RTBC, if that's blocking progress on this issue.

Gábor Hojtsy’s picture

Status: Needs work » Needs review
FileSize
5.17 KB

OK, now we have no blocking issue, so here is an updated patch.

1. Fixed how the help is associated to the block page, as it is possible now with the new help hook params.
2. Remove language links from the translation block on a node page, if node translations are not available or no permission is granted to view them.

These are very small fixes as discussed earlier, so I hope with some testing we can get this little functionality in. (It is even smaller then the previous patch :)

Jose Reyero’s picture

Status: Needs review » Reviewed & tested by the community

Applies and works fine, just as advertised.
Also, the code looks good to me.

I think this patch is ready

Gábor Hojtsy’s picture

Status: Reviewed & tested by the community » Fixed

Thanks, committed.

Anonymous’s picture

Status: Fixed » Closed (fixed)
webchick’s picture

Version: 6.x-dev » 7.x-dev
Category: feature » bug
Priority: Normal » Critical
Status: Closed (fixed) » Active

hook_translate_link_alter() was never documented. Please fix.

zeal’s picture

Hello everyone,

Can anybody help me in this issue :

I am using i18n module for language translation.

I want to set only one flag in a Language switcher block. When user click on that flag, language needs to change accordingly.

For example right now flag is of english language and language is spanish. when i click on flag of english then language must be convert in english and now flag of spanish will display.

Anybody done anywhere like my requirement the please give some suggestion or tell me the way how u do that.

Thanking you in advance ! :)

keuvain33’s picture

Hello everyone,

Can anybody help me in this issue :

I would like to remove current language from the list in Language switcher block, I had patched my locale.module but I don't understand how I can use it. I don't see anything else. My block is empty.

Thanking you in advance !

Edit : I just use CSS with display:none on a:activate and it work perfectly

abdul87’s picture

I am using i18n module...:)
No problem till now:)
In my view drupal is the best and ever seen website...

Regards
Complete SEO & Computer tricks

keuvain33’s picture

Look at the post #40

RussianManFromMoscow’s picture

Version: 7.x-dev » 6.4
Category: bug » support

How do I get in the choice of language through block "switch language" URL type "http://example.com/ru/node/" looks like "http://example.com/ru/"?

catch’s picture

Version: 6.4 » 7.x-dev
Category: support » bug

This issue is open for documenting a function, and for no other reason. If you need support, or think you've found a bug, please open a new issue for that.

drewish’s picture

To be clear what this issue is open for, we need docs for hook_translate_link_alter().

Dave Reid’s picture

And we also need to fix the PHPdocs for translation_translation_link_alter since it says it's an "Implementation of hook_alter_translation_link()." Not sure how that got through.

Dave Reid’s picture

Status: Active » Fixed

I'm going to post the follow-up documentation issue in #344661: Document hook_translation_link_alter so this can be marked as 'closed' once and for all and we won't keep hitting e-mails to everyone.

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for two weeks with no activity.