Управление русской локалью в URL на PHP: от index.php до роутинга
Основные подходы к обработке русской локали в URL через index.php
Как организовать поддержку русской локали, когда URL содержит её в начале пути, например /ru/index.php или /ru/категория/товар?
Наиболее эффективное решение - использовать единую точку входа index.php в связке с URL rewriting. Это позволяет отделить логику выбора локали от физической структуры файлов. Алгоритм:
- Все запросы направляются на
index.phpчерез.htaccess(Apache) или аналогичный механизм. - В
index.phpиз$_SERVER['REQUEST_URI']извлекается первый сегмент пути (например,ru). - Если сегмент соответствует одному из поддерживаемых языков (включая
ru), устанавливается локаль, а сегмент удаляется из дальнейшего маршрута. Если сегмент отсутствует или невалиден, применяется локаль по умолчанию. - Оставшаяся часть пути передаётся внутреннему роутеру или подключается соответствующий контроллер.
Ниже приведён пример реализации.
<?php
// index.php - front controller
$uri = $_SERVER['REQUEST_URI'];
$path = parse_url($uri, PHP_URL_PATH);
$segments = explode('/', trim($path, '/'));
// Поддерживаемые локали
$supportedLocales = ['ru', 'en', 'de'];
$defaultLocale = 'ru';
$locale = $defaultLocale;
$route = $path;
if (count($segments) > 0 && in_array($segments[0], $supportedLocales)) {
$locale = array_shift($segments);
$route = '/' . implode('/', $segments);
}
// Установка локали
setlocale(LC_ALL, $locale . '_RU.UTF-8');
putenv('LANG=' . $locale . '_RU.UTF-8');
// Дальнейшая маршрутизация по $route
// ...
Index php url ru (url index.php с русской локалью)
Этот подход чистый, легко расширяемый и не требует изменения структуры URL при добавлении новых языков.
Типичные ошибки:
- Забывают удалить сегмент с локалью из пути, из-за чего маршрутизатор пытается найти контроллер с именем
ru. - Не проверяют, что локаль действительно поддерживается - тогда нужно либо возвращать 404, либо перенаправлять на дефолтную.
- Игнорируют кодировку: setlocale может не сработать, если не установлены соответствующие локали в системе (проверка через
locale -a).
Вариант с параметром запроса: index.php?lang=ru
Простой способ - читать локаль из GET-параметра. Это не требует перезаписи URL, но такие адреса менее дружественны для SEO.
<?php
$lang = $_GET['lang'] ?? 'ru';
if (!in_array($lang, ['ru', 'en'])) $lang = 'ru';
setlocale(LC_ALL, $lang . '_RU.UTF-8');
Проблема: параметр lang может конфликтовать с другими GET-параметрами. Кроме того, этот способ плохо поддерживается поисковыми системами для многоязычных сайтов.
Вариант с поддоменом: ru.example.com
Локаль определяется по имени поддомена. В index.php нужно проанализировать $_SERVER['HTTP_HOST'].
<?php
$host = $_SERVER['HTTP_HOST'];
if (strpos($host, 'ru.') === 0) {
$locale = 'ru';
} elseif (strpos($host, 'en.') === 0) {
$locale = 'en';
} else {
$locale = 'ru';
}
// далее установка локали
Сложность: требуется настройка DNS и веб-сервера для каждого поддомена. Также необходимо правильно обрабатывать куки сессии между поддоменами.
Вариант с HTTP-заголовком Accept-Language
Автоматическое определение локали по заголовку браузера. Не зависит от URL, но не даёт пользователю явно выбрать язык через ссылку.
<?php
$acceptLang = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
preg_match('/(ru|en)/i', $acceptLang, $matches);
$locale = $matches[1] ?? 'ru';
setlocale(LC_ALL, $locale . '_RU.UTF-8');
Этот метод лучше использовать как резервный, а не основной, так как он не даёт пользователю явно зафиксировать выбор языка в URL.
Расширенные примеры кода с пояснениями
Полный index.php с роутингом, поддержкой русской локали и многоязычными текстами
<?php
// index.php
// 1. Определение локали
$locale = detectLocale();
setLocale($locale);
// 2. Загрузка языкового файла
$translations = include "lang/{$locale}.php";
// 3. Маршрутизация
$path = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
// удаляем сегмент с локалью, если он есть
$segments = explode('/', $path);
if (in_array($segments[0], ['ru','en','de'])) {
array_shift($segments);
}
$controller = $segments[0] ?? 'home';
$action = $segments[1] ?? 'index';
// 4. Подключение контроллера
$controllerFile = "controllers/{$controller}.php";
if (file_exists($controllerFile)) {
require $controllerFile;
$class = 'Controller\\' . ucfirst($controller);
$obj = new $class($translations);
$obj->$action();
} else {
http_response_code(404);
echo $translations['404'];
}
function detectLocale() {
$uri = $_SERVER['REQUEST_URI'];
$segments = explode('/', trim(parse_url($uri, PHP_URL_PATH), '/'));
$supported = ['ru','en','de'];
if (count($segments) > 0 && in_array($segments[0], $supported)) {
return $segments[0];
}
// fallback: проверяем куку, сессию, Accept-Language
return $_COOKIE['lang'] ?? $_SESSION['lang'] ?? 'ru';
}
function setLocale($locale) {
putenv('LC_ALL=' . $locale . '_RU.UTF-8');
setlocale(LC_ALL, $locale . '_RU.UTF-8');
// Для mb_ функций
mb_internal_encoding('UTF-8');
mb_language('uni');
}
Теперь пример языкового файла lang/ru.php:
<?php
return [
'welcome' => 'Добро пожаловать',
'404' => 'Страница не найдена',
'date_format'=> 'd.m.Y',
'currency' => 'руб.',
];
Вывод результата: при обращении к /ru/home/index вызывается контроллер Home, метод index, который использует массив $translations для вывода текста на русском.
Пример .htaccess для перенаправления всех запросов на index.php
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [QSA,L]
Этот код заставляет сервер обрабатывать любые URL (кроме существующих файлов и папок) через index.php. Без этого правила /ru/catalog вернёт 404, так как физической папки ru нет.
Пример настройки русской локали для дат
<?php
setlocale(LC_TIME, 'ru_RU.UTF-8');
echo strftime('%A %d %B %Y', time());
// Вывод: пятница 14 марта 2025
пятница 14 марта 2025
Если локаль не установлена, strftime вернёт английские названия.
Пример обработки ошибок кодировки при работе с русскими URL
<?php
// Если в URL встречаются кириллические символы (например, /ru/товар)
// необходимо правильно декодировать их из UTF-8
$uri = urldecode($_SERVER['REQUEST_URI']);
// Далее работа с $uri
Без декодирования русские буквы в URL будут выглядеть как процентные последовательности (%D1%82%D0%BE%D0%B2%D0%B0%D1%80).
Пример использования константы для локали
<?php
define('CURRENT_LOCALE', detectLocale());
// после этого константу можно использовать в любом файле
Такой подход упрощает доступ к активной локали без глобальных переменных.