Today I've been working on making Hotspots multilingual ready. Since joomla 1.6 creating multilingual websites started to look like a piece of cake. There are several tutorials that explain how website administrators could do that:
http://magazine.joomla.org/issues/issue-nov-2011/item/593-Build-a-Multilingual-Site-in-Joomla-1-7
And there is also a very good webinar that CloudAccess organised and recorded:
http://www.youtube.com/watch?v=gnhVVtyejPg
So, now if you are a developer and you have an extension that needs to be multilingual - it is for the most part easy. If you don't do ajax stuff. But since hotspots is heavily relying on ajax requests to get the data and present it on the map I had to figure out what is going on, why it is not working & how to fix it.
The problem:
Let us say that our website has 2 versions - one in English and one in German. The urls would look like this:
http://example.com
http://example.com/de
Now how do you normally do an ajax request? You send it through index.php like this:
http://example.com/index.php?option=com_mycomponent&format=raw&task=...
This works perfectly fine if "System - Language Filter" plugin is not enabled (and that is not the case on multilingual websites). So if I'm on the german version of the website and I try to start an ajax request pointing to:
http://example.com/index.php?option=com_mycomponent&format=raw&task=...
it will be redirected to:
http://example.com/de/index.php?option=com_mycomponent&format=raw&task=...
Now this may not look like a huge problem to some people -> but this is actually a second request that takes place to serve the same data that we need. This is something that you absolutely don't want to happen on a production server.
To the rescue!
Now how do we normally create the path for our Ajax request. What we normally do - generate a javascript variable that holds the base URL for the website and then we'll use that variable to construct the URL to send ajax requests to. In one of our php files we'll have something similar to this:
$document = JFactory::getDocument();
$script = "window.addEvent('domready', function(){"
$script = "var baseURL = '" . Juri::base() . "'";
$script = 'do our ajax stuff here';
$script = "});"
$document->addScriptDeclaration($script);
So basically this code will create a <script type="text/javascript"> tag in your html head and baseURL will have the value of the baseURL that the site has. Later when we create the url for the request we'll do something like this in javascript:
baseURL + 'index.php?option=com_mycomponent...";
As we said - this works! And it works fine! But it doesn't work that fine on muiltilingual websites. So here is what I found that works best so far. Instead of using Juri::base(); one should use:
$uri = JUri::getInstance();
$uri->toString(array('scheme', 'user', 'pass', 'host','port', 'path'));
This will output the website url together with the path. So on websites that have SEF urls on -> the path will be
http://example.com/de/whatever-the-name-of-the-item
On sites that doesn't have SEF urls on - it will output just the example.com part (As the variable that holds the information for the language is then part of the query (&lang=de)). What we then need to change in our javascript is then the way we construct the url:
baseURL + '?option=com_mycomponent..."
And that's it! By doing this on the german version of the site -> our request will go to the german version and we won't experience a redirect in the background.
Other ways to do that?
Well, there is a way to go around that problem by aways sending POST requests and aways having something in the post array of that request. If you look at the languagefilter plugin you'll see the following line of code:
// Redirect only if not in post
if (!empty($lang_code) && $app->input->getMethod() != "POST" || count($app->input->post) == 0)
Now I tried this, but I ended up in a situation where I needed to use GET (hotspots tiles...) so you can decide what is the best thing for your project & do that.