I would suggest making the “admin” check a little more strict:
// Make sure this isn't a CP request
if (!isset($_GET['p']) || strncmp($_GET['p'], 'admin', 5) !== 0)
{
// ...
(Assuming you’re using the recommended .htaccess redirect rule, by the time the request hits index.php, the original request URI will be available as $_GET['p']
.)
The Accept-Language header can actually include multiple languages, so you might want to consider looking at all of them, sorted by weight. HttpRequestService::getBrowserLanguages() has some example code on how to do that.
A 302 redirect would probably be more appropriate than 301. You wouldn’t want Google to think that http://example.com/ should always really be http://example.com/en/ or whatever this script might end up sending it to, and people could theoretically change their browser’s language preferences.
You also might want to include $_GET['p']
in your redirect location. Right now you’re just sending all traffic off to the locale-specific homepage, which is why 404s aren’t working as expected.
To put it all together, here’s what you might want to do:
<?php
// Make sure this isn't a CP request
if (!isset($_GET['p']) || strncmp($_GET['p'], 'admin', 5) !== 0)
{
// Language paths
$paths = array(
'de' => '/de/',
'it' => '/it/',
'en' => '/en/'
);
// Get the browser's preferred languages
if (isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) && preg_match_all('/([\w\-_]+)\s*(?:;\s*q\s*=\s*(\d*\.\d*))?/', $_SERVER['HTTP_ACCEPT_LANGUAGE'], $matches, PREG_SET_ORDER))
{
$languages = array();
$weights = array();
foreach ($matches as $match)
{
$languages[] = strtolower(substr($match[1], 0, 2));
$weights[] = !empty($match[2]) ? floatval($match[2]) : 1;
}
// Sort the languages by their weight
array_multisort($weights, SORT_NUMERIC, SORT_DESC, $languages);
// Find the first match
foreach ($languages as $language)
{
if (isset($paths[$language]))
{
$matchingLanguage = $language;
break;
}
}
}
// Default to German
if (!isset($matchingLanguage))
{
$matchingLanguage = 'de';
}
// Redirect
$url = $paths[$matchingLanguage].(isset($_GET['p']) ? $_GET['p'] : '');
header('Location: '.$url, true, 301);
}
else
{
// Path to your craft/ folder
$craftPath = '../craft';
// Do not edit below this line
$path = rtrim($craftPath, '/').'/app/index.php';
if (!is_file($path))
{
exit('Temporary error. Could not find the CMS folder.');
}
require_once $path;
}