4

When visiting the website www.example.com/ the visitor should be redirected to the correct language version, e.g. www.example.com/en for english and www.example.com/es for spanish.

My current implementation only works when visiting www.example.com/index.var and redirects to www.example.com/index.en. Now I want to rewrite this to www.example.com/en/

My implementation is based on https://httpd.apache.org/docs/2.4/content-negotiation.html.

.htaccess

Options -MultiViews
RewriteEngine On
RewriteBase /
AddHandler type-map .var
LanguagePriority en es de
ForceLanguagePriority Fallback

index.var

URI: index; vary="language"

URI: index.en.html
Content-type: text/html
Content-language: en

URI: index.es.html
Content-type: text/html;charset=utf-8
Content-language: es

URI: index.de.html
Content-type: text/html;charset=utf-8
Content-language: de

Important: MultiViews are disabled

Looking forward to your great solutions.


to explain this a little more in detail...
Here's an example of my file structure:

   File                     should be rewritten or redirected to
 - index.var          -->   /
 - index.en.html      -->   /en/
 - index.es.html      -->   /es/
 - about.var          -->   /about
 - about.en.html      -->   /en/about
 - about.es.html      -->   /es/about
 - images/img_1.jpg   -->   /images/img_1.jpg
 - images/logo.var    -->   /images/logo.png (not a file)
 - images/logo.en.png -->   /en/images/logo.png
 - images/logo.es.png -->   /es/images/logo.png

Rewriting of images and other resources is optional. It's only important to get rewriting of html files right.

The Apache Documentation is a working example of this (using content negotiation).

  • Do you have a way to detect the browser's set language? – Michael d Feb 23 '18 at 9:18
  • That's already done by type-maps (like index.var in my example). – x21 Feb 23 '18 at 9:27
  • Why did you disable multiviews? I think that feature is supposed to handle this for you. – Stephen Ostermiller Feb 23 '18 at 10:29
  • I have to disable it because it breaks a module that I run in a subdirectory. Furthermore multiviews will show different files under the same URL which is not good for SEO. – x21 Feb 23 '18 at 10:38
  • Why does about.var get redirected while images/logo.var does not? – Stephen Ostermiller Feb 23 '18 at 11:18
1

I think I've found the solution on Apache's SVN repository. (I haven't tested it yet)

Configuration for Multilingual Site
Configuration for Multilingual Error Pages
Configuration with Languages and Encodings Setup

The implementation here uses the .html extension for type-map files instead of .var. That means, if you want to use html files with the extension .html instead of .html.en, you have to replace

AddHandler type-map .html

with

AddHandler type-map .var

like I did.

0

I would just do this in PHP. I'm not sure how to do it in htaccess.

I would make index.php :

<?php
header("Status: 200 OK");
$lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
switch ($lang){
    case "fr":
        //echo "PAGE FR";
        include("index_fr.php");//include check session FR
        break;
    case "it":
        //echo "PAGE IT";
        include("index_it.php");
        break;
    case "en":
        //echo "PAGE EN";
        include("index_en.php");
        break;        
    default:
        //echo "PAGE EN - Setting Default";
        include("index_en.php");//include EN in all other cases of different lang detection
        break;
}
?>

Or if you want the redirect you can do:

    <?php
    $lang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2);
    switch ($lang){
        case "en":
          header('Location: http://www.example.com/en/', true, 302);
    exit;
        case "es":
             header('Location: http://www.example.com/es/', true, 302);
  exit;
        case "de":
            header('Location: http://www.example.com/en/', true, 302);
  exit;       
        default:
            //echo "PAGE EN - Setting Default";
            include("index_en.php");//include EN in all other cases of different lang detection
            break;
    }
    ?>
  • This would only work if www.example.com/en/ would already show the content of www.example.com/index.en. Also it must work for all pages, not only for the index. – x21 Feb 23 '18 at 9:41
0

I would use rewrite rules to issue 301 permanent redirects:

RewriteEngine on

# First handle the index.XX.html files
# where the language code is moved to the front directory
# and the index and html are removed
RewriteCond %{REQUEST_URI} !^/?([a-z]{2})/
RewriteRule ^/?(.*/)?index\.([a-z]{2})\.html$ /$2/$1 [L,R=301]

# Then handle other file.XX.html files
# where the language code is moved to the front directory
# the file name is preserved, but the html is removed
RewriteCond %{REQUEST_URI} !^/?([a-z]{2})/
RewriteRule ^/?(.*)\.([a-z]{2})\.html$ /$2/$1 [L,R=301]

# Handle all other file.XX.xyz
# where the language code is moved to the front directory
# and the file name and extension are preserved
RewriteCond %{REQUEST_URI} !^/?([a-z]{2})/
RewriteRule ^/?(.*)\.([a-z]{2})\.([a-z]+)$ /$2/$1.$3 [L,R=301]

This detects a two character language code using the regular expression ([a-z]{2}). You could instead using something like (en|es|de) with a specific list of supported languages. Doing so could reduce mistakes based on two digit codes used for something other than language (like maybe a gzipped javascript file: .js.gz.) It would also allow you to expand the rules to include country info if needed (like en-us.)

All the rules have a RewriteCond that makes sure they don't apply in the language subdirectories. That should help prevent infinite loops or other problems

The rules start with /? which consumes any leading slash so the rules can be used either in .htaccess or in an Apache .conf file.

The first rule makes the directory path preceding index optional using a question mark in the section (.*/)?. It allows that rule apply to the root index.XX.html files.

I didn't put in a rule for the .var files because it sounds like you already have something in place for them. You would need to continue to handle those files as you do now.

I tested these rules on my local Apache server by putting them in .htaccess and hitting the site with curl. They seem to do the right thing:

$ curl -s --head 'http://example.com/index.en.html'
HTTP/1.1 301 Moved Permanently
Location: http://example.com/en/

$ curl -s --head 'http://example.com/index.es.html'
HTTP/1.1 301 Moved Permanently
Location: http://example.com/es/

$ curl -s --head 'http://example.com/about.en.html'
HTTP/1.1 301 Moved Permanently
Location: http://example.com/en/about

$ curl -s --head 'http://example.com/about.es.html'
HTTP/1.1 301 Moved Permanently
Location: http://example.com/es/about

$ curl -s --head 'http://example.com/images/logo.en.png'
HTTP/1.1 301 Moved Permanently
Location: http://example.com/en/images/logo.png

$ curl -s --head 'http://example.com/images/logo.es.png'
HTTP/1.1 301 Moved Permanently
Location: http://example.com/es/images/logo.png
  • The URL is actually rewritten but it returns Error 404. And If I go to www.example.com/index it redirects first to /index.var and then to /en/index?lang=en&lang=en&lang=en&lang=en... and so on and results in a redirection loop. Thank you for your work and detailed explanations so far. – x21 Feb 23 '18 at 12:32

Your Answer

By clicking "Post Your Answer", you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.