Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to redirect based on Accept-Language with Apache / mod_rewrite

For language redirects we currently create folders in the web root containing an index.php file which checks the HTTP_ACCEPT_LANGUAGE server variable. e.g. for the url www.example.com/press/

in /var/www/site/press/index.php:

<?php
  if ($_SERVER["HTTP_ACCEPT_LANGUAGE"] == "en")
    header("location: ../press_en.php");
  else 
    header("location: ../press_de.php");
?>

As the site has grown, we now have many such folders. I am trying to clean this up by moving the redirects to a single .htaccess file:

RewriteEngine on

# Set the base path here
RewriteBase /path/to/site/

# The 'Accept-Language' header starts with 'en'
RewriteCond %{HTTP:Accept-Language} (^en) [NC]

# EN redirects
RewriteRule press(/?)$   press_en.php [L,R]

# DE redirects (for all languages not EN)
RewriteRule press(/?)$   press_de.php [L,R]

The idea is the same as the php file, but it doesn't work. I have tried all the possible language settings / orders in Firefox preferences, and checked the headers are correct, but it always serves the press_de.php file.

What am I doing wrong, or is there a better way? (not including content negotiation / multiviews or anything that requires renaming files, this is not currently an option).

like image 681
meleyal Avatar asked Jan 24 '23 01:01

meleyal


1 Answers

I would put the language indicator at the start of the URL path like /en/… or /de/…. Then you can use a single script that checks the preferred language and redirects the request by prepending the language indicator:

// negotiate-language.php
$availableLanguages = array('en', 'de');
if (!preg_match('~^/[a-z]{2}/~', $_SERVER['REQUEST_URI'])) {
    $preferedLanguage = someFunctionToDeterminThePreferedLanguage();
    if (in_array($preferedLanguage, $availableLanguages)) {
        header('Location: http://example.com/'.$preferedLanguage.$_SERVER['REQUEST_URI']);
    } else {
        // language negotiation failed!
        header($_SERVER['SERVER_PROTOCOL'].' 300 Multiple Choices', true, 300);
        // send a document with a list of the available language representations of REQUEST_URI
    }
    exit;
}

And the corresponding rules:

RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^/]+)$ negotiate-language.php [L]
RewriteRule ^([a-z]{2})/([^/]+)$ $2_$1.php [L]

Note that you need a proper someFunctionToDeterminThePreferedLanguage function as Accept-Language header field is not a single value but a list of qualified values. So there might be more than just one value and the first value is not always the prefered value.

like image 87
Gumbo Avatar answered Jan 31 '23 08:01

Gumbo