В веб-разработке задача транслитерации возникает постоянно: нужно преобразовать русский текст в латиницу для ЧПУ-адресов, имен файлов, SEO-заголовков или отправки данных во внешние системы. В этой статье я покажу, как реализовать транслитерацию на PHP и в WordPress, используя только встроенные средства и простые функции, без внешних API и плагинов.
Зачем программисту транслитерация?
В веб-разработке транслитерация нужна для:
-
ЧПУ-адресов (Человеко-понятных URL): вместо ?id=12345 — o-kompanii.
-
Имен файлов: загрузка изображений с названиями на русском → автоматическое переименование в латиницу.
-
SEO: правильная транслитерация заголовков и мета-тегов.
-
Интеграций с внешними API: многие сервисы принимают данные только в латинице.
-
Формирования логинов и ников: автоматическая генерация username на основе ФИО.
Решение 1. Базовая транслитерация на чистом PHP
Самое простое решение — функция с ассоциативным массивом правил. Она не требует внешних библиотек и работает на любой версии PHP с поддержкой UTF-8.
<?php /** * Базовая транслитерация кириллицы в латиницу * * @param string $text Исходный текст * @return string Транслитерированный текст */ function transliterate($text) { // Карта замены (кириллица → латиница) $map = [ 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e', 'ю' => 'yu', 'я' => 'ya' ]; // Приводим к нижнему регистру $text = mb_strtolower($text, 'UTF-8'); $result = ''; $length = mb_strlen($text, 'UTF-8'); for ($i = 0; $i < $length; $i++) { $char = mb_substr($text, $i, 1, 'UTF-8'); $result .= isset($map[$char]) ? $map[$char] : $char; } return $result; } // Пример использования echo transliterate('Привет, мир!'); // privet-mir echo transliterate('SEO-заголовок'); // seo-zagolovok ?>
Важно: используйте mb_-функции (mb_strtolower, mb_substr, mb_strlen) для корректной работы с многобайтовой кодировкой UTF-8. Без них функция будет неправильно обрабатывать русские буквы.
Решение 2. Транслитерация для ЧПУ (URL)
Для генерации человекопонятных URL нужно не только заменить буквы, но и удалить лишние символы, заменить пробелы на дефисы и привести всё к нижнему регистру.
<?php /** * Транслитерация для создания ЧПУ-адресов * * @param string $text Исходный текст * @return string Готовый slug для URL */ function transliterateUrl($text) { $map = [ 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e', 'ю' => 'yu', 'я' => 'ya' ]; // Приводим к нижнему регистру $text = mb_strtolower($text, 'UTF-8'); $result = ''; $length = mb_strlen($text, 'UTF-8'); for ($i = 0; $i < $length; $i++) { $char = mb_substr($text, $i, 1, 'UTF-8'); if (isset($map[$char])) { $result .= $map[$char]; } elseif (preg_match('/[a-z0-9]/', $char)) { $result .= $char; } elseif ($char === ' ') { $result .= '-'; } } // Убираем лишние дефисы и спецсимволы $result = preg_replace('/-+/', '-', $result); $result = preg_replace('/[^a-z0-9\-]/', '', $result); $result = trim($result, '-'); return $result; } // Примеры использования echo transliterateUrl('Привет, мир!'); // privet-mir echo transliterateUrl('SEO-оптимизация 2024'); // seo-optimizatsiya-2024 echo transliterateUrl('Новый год!'); // novyy-god ?>
Что делает этот код:
-
Заменяет русские буквы на латинские.
-
Оставляет латинские буквы и цифры.
-
Заменяет пробелы на дефисы.
-
Удаляет все остальные символы (знаки препинания, спецсимволы).
-
Убирает повторяющиеся и лишние дефисы.
Решение 3. Генерация ЧПУ в WordPress
В WordPress транслитерация чаще всего используется для генерации ЧПУ (slug) заголовков записей. Встроенная функция sanitize_title() работает с кириллицей, но не идеально — она просто удаляет русские буквы, оставляя только латиницу. Чтобы исправить это, используйте фильтр.
Способ 1. Фильтр sanitize_title (рекомендуемый)
Этот способ перехватывает генерацию slug и применяет вашу функцию транслитерации.
<?php /** * Фильтр для генерации ЧПУ на основе транслитерации */ add_filter('sanitize_title', 'custom_transliterate_slug', 10, 3); function custom_transliterate_slug($title, $raw_title, $context) { // Применяем транслитерацию только при сохранении записей if ($context !== 'save') { return $title; } // Транслитерируем заголовок для URL $transliterated = transliterateUrl($raw_title); // Если результат не пустой, возвращаем его return !empty($transliterated) ? $transliterated : $title; } ?>
Способ 2. Генерация slug при сохранении поста (с проверкой уникальности)
Этот способ даёт больше контроля и позволяет проверить уникальность slug.
<?php /** * Генерация уникального slug при сохранении поста */ add_action('save_post', 'generate_transliterated_slug', 10, 3); function generate_transliterated_slug($post_id, $post, $update) { // Пропускаем автосохранения, ревизии и черновики if (defined('DOING_AUTOSAVE') && DOING_AUTOSAVE) { return; } if (wp_is_post_revision($post_id) || wp_is_post_autosave($post_id)) { return; } // Если slug уже задан вручную, не трогаем if (!empty($post->post_name)) { return; } // Генерируем slug из заголовка $new_slug = transliterateUrl($post->post_title); // Если ничего не получилось, выходим if (empty($new_slug)) { return; } // Проверяем уникальность slug $new_slug = wp_unique_post_slug($new_slug, $post_id, $post->post_status, $post->post_type, $post->post_parent); // Обновляем запись с новым slug wp_update_post([ 'ID' => $post_id, 'post_name' => $new_slug ]); } ?>
Решение 4. Расширенная транслитерация с поддержкой разных стандартов
Если ваш проект требует разных стандартов транслитерации (например, для загранпаспорта, ISO 9, URL), можно сделать функцию с выбором стандарта.
<?php /** * Получить правила транслитерации для выбранного стандарта */ function getTransliterationRules($standard = 'url') { $base = [ 'а' => 'a', 'б' => 'b', 'в' => 'v', 'г' => 'g', 'д' => 'd', 'е' => 'e', 'ё' => 'e', 'ж' => 'zh', 'з' => 'z', 'и' => 'i', 'й' => 'y', 'к' => 'k', 'л' => 'l', 'м' => 'm', 'н' => 'n', 'о' => 'o', 'п' => 'p', 'р' => 'r', 'с' => 's', 'т' => 't', 'у' => 'u', 'ф' => 'f', 'х' => 'kh', 'ц' => 'ts', 'ч' => 'ch', 'ш' => 'sh', 'щ' => 'shch', 'ъ' => '', 'ы' => 'y', 'ь' => '', 'э' => 'e', 'ю' => 'yu', 'я' => 'ya' ]; $standards = [ 'url' => [], 'passport' => ['щ' => 'shch', 'ъ' => 'ie', 'ы' => 'y', 'ё' => 'e'], 'gibdd' => ['ё' => 'e', 'ю' => 'iu', 'я' => 'ia', 'щ' => 'shch'], 'iso' => ['ё' => 'ë', 'ж' => 'ž', 'й' => 'j', 'х' => 'h', 'ц' => 'c', 'ч' => 'č', 'ш' => 'š', 'щ' => 'ŝ', 'ъ' => 'ʺ', 'ы' => 'y', 'ь' => 'ʹ', 'э' => 'è', 'ю' => 'û', 'я' => 'â'] ]; return array_merge($base, $standards[$standard] ?? []); } /** * Транслитерация с выбором стандарта */ function transliterateWithStandard($text, $standard = 'url') { $text = mb_strtolower($text, 'UTF-8'); $map = getTransliterationRules($standard); $result = ''; $length = mb_strlen($text, 'UTF-8'); for ($i = 0; $i < $length; $i++) { $char = mb_substr($text, $i, 1, 'UTF-8'); $result .= $map[$char] ?? $char; } // Для URL дополнительная очистка if ($standard === 'url') { $result = preg_replace('/\s+/', '-', $result); $result = preg_replace('/[^a-z0-9\-]/', '', $result); $result = preg_replace('/-+/', '-', $result); $result = trim($result, '-'); } return $result; } // Примеры использования echo transliterateWithStandard('Щукин Александр', 'url'); // shchukin-aleksandr echo transliterateWithStandard('Щукин Александр', 'passport'); // shchukin-aleksandr echo transliterateWithStandard('Юлия', 'passport'); // iuliia echo transliterateWithStandard('Ёлкин', 'iso'); // ëlkin ?>
Частые ошибки и их решение
При реализации транслитерации на PHP и в WordPress часто возникают одни и те же проблемы. Вот самые распространённые и способы их решения.
| Проблема | Причина | Решение |
|---|---|---|
| Вместо букв появляются вопросы (????) | Неправильная кодировка файла или данные не в UTF-8 | Убедитесь, что файл сохранён в UTF-8 без BOM. Используйте mb_-функции. |
| WordPress генерирует slug только из первого слова | Фильтр sanitize_title обрезает заголовок | Используйте sanitize_title с приоритетом 10 и проверяйте контекст (‘save’). |
| В URL появляются двойные слэши | Некорректная обработка слэшей | Используйте untrailingslashit() и trailingslashit() для путей. |
| Транслитерация работает на локалке, но не на сервере | На сервере отключено расширение mbstring | Установите расширение PHP mbstring на сервере. |
| Slug не генерируется для записей, созданных через API | WordPress пропускает фильтр sanitize_title для API-запросов | Используйте хук wp_insert_post_data для принудительной генерации slug. |
| Транслитерация удаляет символы, которые нужно сохранить | Слишком агрессивная очистка в preg_replace | Настройте регулярное выражение: разрешите точки, дефисы, нижние подчёркивания. |
Вывод: выбирайте решение под свою задачу
Для простых проектов достаточно базовой функции с массивом правил. Если нужно генерировать ЧПУ-адреса в WordPress — используйте фильтр sanitize_title. Для проектов, где важна точность (документы, госстандарты), добавьте поддержку разных стандартов через расширенную функцию.
Главное — не забывайте про кодировку UTF-8 и mb_-функции, проверяйте уникальность slug и обрабатывайте краевые случаи (пустые строки, спецсимволы).
Для разработчиков: Хотите быстро проверить, как транслитерируется ваш текст по разным стандартам? Используйте наш сервис Translit PRO — просто введите текст и выберите нужный стандарт из списка.