views:

326

answers:

7

I'm very much not a javascript/html/css person.

Even so I find myself in the position of having to do a webpage. It's static the only thing you can do on it is click on flags to change dispay-language based on a cookie.

If the cookie says "this" I write text in one language, and if the cookie says "that" I write in another language. This works perfectly but I have to use lots of document.write statements and it's ugly and cumbersome.

Right now I type the text I want and use a macro in emacs to fold the text at about 80 chars and put document.write(" in the beginning of each line and "); at the end. I then paste it into the web page in a if(cookie_this) { } else { }.

There must be a better way to do it... Please?
Edit:
I was looking workaround for the limitations in document.write

Constraints:

  • No server side magic, that means no ruby/php/perl
  • One page only, or rather only one visible url
  • The solution should be simpler than the working one I have
A: 

The detection should be on the server (preferably based on the Accept-Language header the client sent), and you should send a static file that has already been localized.

Hank Gay
What if he wants something like Wikipedia's language options?
strager
I haven't looked, but I feel safe in saying that Wikipedia does *NOT* use JavaScript and cookies to provide it's language options.
Hank Gay
A: 

This does not fit the (edited) criteria of the original question, but may be useful regardless.

Use a server-side script. What you're looking for can easily be done in PHP. You'd probably want a hierarchy of documents based on language, and would look up given that. For example, a directory tree:

/en/
/en/page1.html
/en/page2.html
/es/
/es/page1.html
/es/page2.html

In PHP it's as simple as

$language = $_GET['lang'];
$page = $_GET['page'];
include($language . '/' . $page);
// URL is: /whatever.php?lang=LANGUAGE_HERE&page=PAGE_HERE

However, that has many security issues along with it. Sanitize your input and make sure the directory and file exist. Fuller example:

$contentRoot = './';      // CHANGE ME.  Do include trailing /.
$defaultLanguage = 'en';  // CHANGE ME.
$defaultPage = 'home';    // CHANGE ME.

if(isset($_GET['lang']))
    $language = $_GET['lang'];
else
    $language = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 2);

if(isset($_GET['page']))
    $page = $_GET['page'];
else
    $page = $defaultPage;

$languageDir = basename($_GET['lang']) . '/';
$pageFile = basename($page) . '.html';

if(!file_exists($contentRoot . $languageDir) || !is_dir($contentRoot . $languageDir))
    $languageDir = $defaultLanguage;

$fullFileName = $contentRoot . $languageDir . $pageFile;

if(!file_exists($fullFileName) || !is_file($fullFileName) || !is_readable($fullFileName))
    $pageFile = $defaultPage;

readfile($fullFileName);
// Or, if you want to parse PHP in the file:
include($fullFileName);

You may also want to use mod_rewrite (Apache) to allow URL's such as http://www.mysite.com/en/page1. (Just be sure to hide the actual page.)

// TODO mode_rewrite rules

Another approach is putting the above hierarchy into the document root and handing out URL's directly. This gives you less power (e.g. templating is more difficult), however, and you have to worry about external media being referenced properly.

If you're looking for a dynamic approach, on the client side use Javascript to fetch the data using Ajax. This is also trivial, and does not require a dynamic server backend. I recommend a Javascript framework such as jQuery to make this as easy as possible.

strager
A: 

There is no good way to do this in JS. Best way is to use VERY simple PHP code. But, if you want, there is a way in JS - prepare pages like these:

  • some pages with different language versions, like index_en.html, index_ru.html
  • main index.html page, where you have code like if(cookie) windows.location.replace('index_en.html') else ...
Thinker
+1  A: 

jQuery can do this with I lot less ease, but you could create an element then set that elements innerHTML property. You may have to change your call slightly so that you append the child element. See createElement function for more info. For example

<script type="text/javascript">
  function writeElement(language, elementId) {
    var newElement = document.createElement("span");
    if (language = "this") {
      newElement.innerHTML = "text for this";
    }
    else {
      newElement.innerHTML = "text for that";
    }
    var element = document.getElementById(elementId);
    element.appendChild(newElement);
  }
</script>

Usage

<span id="data1"></span>
<script type="text/javascript">
  writeElement("this", "data1")
</script>

Add a comment if you can support jQuery and you want a sample of that instead.

bendewey
How long can the newElement.innerHTML string be?
Nifle
i haven't heard of any limitations to innerHTML
nickf
I'm not sure if there is a limitation to the innerHTML property
bendewey
+1  A: 

I think that the right way to approach this is to parse the Accept-Language header, and do this server-side.

But in the instance that you are stuck with client-side scripting. Say your content was marked like this

<script type="text/javascript">
if(cookie_this) { 
document.getElementById('esContent').style.display = 'block';
} else {
document.getElementById('enContent').style.display = 'block';
}
</script>

<div id="esContent" style="display:none">
Hola, mundo.
</div>

<div id="enContent" style="display:none">
Hello, world.
</div>

This does not degrade for people with CSS enabled, and JavaScript disabled. Other approaches might include using Ajax to load content based on a cookie value (you could use jQuery for this).

artlung
If you have JS disabled but CSS enabled this method is flawed (no content).
strager
I like this, it's looks very simple. I'll try this tomorrow.And I *am* stuck with client side scripting for this page for now. The reason being it works well enough with lots of document.write statements.
Nifle
Also, the <script> tag should go at the bottom of the page, or the script should be executed onload. Otherwise, nothing is hidden.
strager
strager, this page does not work without javascript anyway.
Nifle
strager, I noted the deficiency of this technique in my response. It is not "the best case" -- but it is an answer to the original question. The correct, in my opinion, method if we're allowing the user to make his or her language choice, is to generate the page based on the cookie on the server.
artlung
+3  A: 

Expanding on artlung's answer:

You can display or hide things given a lang attribute (or any other criteria, such as a class name). In jQuery and HTML:

<p>Language:
    <select id="languageSelector">
        <option value="en">English</option>
        <option value="es">Espa&ntilde;ol</option>
    </select>
</p>

<div lang="en-us">
Hello
</div>

<div lang="es">
Hola
</div>

<script type="text/javascript">
var defaultLanguage = 'en';
var validLanguages = ['en', 'es'];

function setLanguage(lang, setCookie) {
    if(!$.inArray(languages, lang))
        lang = defaultLang;

    if(typeof(setCookie) != 'undefined' && setCookie) {
       $.cookie('language', lang);
    }

    // Hide all things which can be hidden due to language.
    $('*[lang]').filter(function() { return $.inArray(languages, $(this).attr('lang')); }).hide();

    // Show currently selected language.
    $('*[lang^=' + lang + ']).show();
}

$(function() {
    var lang = $.cookie('language'); // use jQuery.cookie plugin
    setLanguage(lang);

    $('#languageSelector').change(function() {
        setLanguage($(this).val(), true);
    });
});
</script>
strager
Thank you. I'll look at this to after my first coffee tomorrow morning.
Nifle
+1  A: 

If you just want one visible URL, but can host multiple pages on the server you could also try XHR. I use jQuery because I am most familiar with it although it would be possible to implement in javascript alone:

<html>
 <head>
  <script type="text/javascript" src="path/to/jquery.js"> </script>
  <script type="text/javascript">
   $(document).ready(function () {
       if (cookie_this) {
           $("body").load("onelanguage.html body");
       } else {
           $("body").load("otherlanguage.html body");
       }
   });
  </script>
 </head>
 <body>
 </body>
</html>
cobbal
Would that require onelanguage.html and otherlanguage.html to be publicly visible as well?
strager
it depends on the meaning of publicly visible I guess: if you mean 'one URL, no redirection' this works, if you mean 'the public can list the directory and see/access all the files', then these will be visible
cobbal