Реализация автоопределения языка по GeoIP для сайта

Наша компания занимается разработкой, поддержкой и обслуживанием сайтов любой сложности. От простых одностраничных сайтов до масштабных кластерных систем построенных на микро сервисах. Опыт разработчиков подтвержден сертификатами от вендоров.

Разработка и обслуживание любых видов сайтов:

Информационные сайты или веб-приложения
Сайты визитки, landing page, корпоративные сайты, онлайн каталоги, квиз, промо-сайты, блоги, новостные ресурсы, информационные порталы, форумы, агрегаторы
Сайты или веб-приложения электронной коммерции
Интернет-магазины, B2B-порталы, маркетплейсы, онлайн-обменники, кэшбэк-сайты, биржи, дропшиппинг-платформы, парсеры товаров
Веб-приложения для управления бизнес-процессами
CRM-системы, ERP-системы, корпоративные порталы, системы управления производством, парсеры информации
Сайты или веб-приложения электронных услуг
Доски объявлений, онлайн-школы, онлайн-кинотеатры, конструкторы сайтов, порталы предоставления электронных услуг, видеохостинги, тематические порталы

Это лишь некоторые из технических типов сайтов, с которыми мы работаем, и каждый из них может иметь свои специфические особенности и функциональность, а также быть адаптированным под конкретные потребности и цели клиента

Предлагаемые услуги
Показано 1 из 1 услугВсе 2065 услуг
Реализация автоопределения языка по GeoIP для сайта
Средняя
~1 рабочий день
Часто задаваемые вопросы

Наши компетенции:

Этапы разработки

Последние работы

  • image_website-b2b-advance_0.png
    Разработка сайта компании B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Разработка веб-приложения для компании FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    874
  • image_ecommerce_furnoro_435_0.webp
    Разработка интернет магазина для компании FURNORO
    1094
  • image_crm_enviok_479_0.webp
    Разработка веб-приложения для компании Enviok
    831
  • image_bitrix-bitrix-24-1c_fixper_448_0.png
    Разработка веб-сайта для компании ФИКСПЕР
    851

Реализация автоопределения языка по GeoIP для сайта

Автоопределение языка и региона позволяет показывать пользователю контент на его языке без явного выбора. Комбинирует GeoIP (определение страны по IP) и заголовок Accept-Language браузера для точного определения предпочтительного языка.

Источники данных

GeoIP базы:

  • MaxMind GeoLite2 — бесплатная, требует регистрации, обновляется еженедельно
  • MaxMind GeoIP2 — платная, точнее
  • ip-api.com — API, бесплатно до 45 req/min
  • ipinfo.io — API с планами

Accept-Language header — браузер сам передаёт список предпочтительных языков:

Accept-Language: ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7

Установка MaxMind GeoLite2

# Скачать базу данных
mkdir -p /usr/share/GeoIP
wget "https://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country&license_key=YOUR_KEY&suffix=tar.gz" \
     -O GeoLite2-Country.tar.gz
tar -xzf GeoLite2-Country.tar.gz -C /usr/share/GeoIP/
// composer require maxmind-db/reader
use MaxMind\Db\Reader;

class GeoIpService
{
    private Reader $reader;

    public function __construct()
    {
        $this->reader = new Reader('/usr/share/GeoIP/GeoLite2-Country.mmdb');
    }

    public function getCountryCode(string $ip): ?string
    {
        try {
            $record = $this->reader->get($ip);
            return $record['country']['iso_code'] ?? null;
        } catch (\Exception) {
            return null;
        }
    }
}

Определение языка (комбинированная логика)

class LanguageDetectionService
{
    // Маппинг страна → язык
    private array $countryToLanguage = [
        'RU' => 'ru', 'BY' => 'ru', 'KZ' => 'ru',
        'UA' => 'uk',
        'DE' => 'de', 'AT' => 'de', 'CH' => 'de',
        'US' => 'en', 'GB' => 'en', 'AU' => 'en', 'CA' => 'en',
    ];

    private array $supportedLanguages = ['ru', 'en', 'de', 'uk'];

    public function detect(Request $request): string
    {
        // 1. Явный выбор пользователя (приоритет)
        if ($lang = $request->cookie('locale')) {
            if (in_array($lang, $this->supportedLanguages)) {
                return $lang;
            }
        }

        // 2. Accept-Language header
        $acceptLanguage = $request->header('Accept-Language', '');
        $preferred = $this->parseAcceptLanguage($acceptLanguage);

        foreach ($preferred as $lang) {
            $short = substr($lang, 0, 2);
            if (in_array($short, $this->supportedLanguages)) {
                return $short;
            }
        }

        // 3. GeoIP
        $ip = $request->ip();
        $countryCode = app(GeoIpService::class)->getCountryCode($ip);

        if ($countryCode && isset($this->countryToLanguage[$countryCode])) {
            return $this->countryToLanguage[$countryCode];
        }

        // 4. Дефолт
        return config('app.locale', 'en');
    }

    private function parseAcceptLanguage(string $header): array
    {
        preg_match_all('/([a-z]{1,8}(?:-[a-z]{1,8})*)(?:;q=([0-9.]+))?/i', $header, $matches);

        $langs = array_combine($matches[1], array_map(
            fn($q) => $q === '' ? 1.0 : (float) $q,
            $matches[2]
        ));

        arsort($langs);
        return array_keys($langs);
    }
}

Middleware для применения языка

class SetLocale
{
    public function handle(Request $request, Closure $next): Response
    {
        $lang = app(LanguageDetectionService::class)->detect($request);
        App::setLocale($lang);

        $response = $next($request);

        // Сохранить в cookie (без изменений Accept-Language)
        if (!$request->cookie('locale')) {
            $response->withCookie(cookie('locale', $lang, 60 * 24 * 365));
        }

        return $response;
    }
}

Редирект на языковой поддомен или субдиректорию

// Редирект при первом визите
if (!$request->cookie('locale') && !$request->is('*/')) {
    $lang = $this->detect($request);
    $localizedUrl = url("/{$lang}" . $request->getPathInfo());
    return redirect($localizedUrl)->withCookie(cookie('locale', $lang, 525600));
}

Кеширование GeoIP

GeoIP-запрос быстрый (чтение файла), но при высокой нагрузке кешируют в Redis:

$country = Cache::remember("geoip:{$ip}", 3600, fn() =>
    app(GeoIpService::class)->getCountryCode($ip)
);

Автоматическое обновление базы GeoLite2

# Cron: обновлять базу каждую неделю
0 4 * * 2 /usr/local/bin/update-geoip.sh

# update-geoip.sh
wget -qO /tmp/GeoLite2.tar.gz "https://download.maxmind.com/..."
tar -xzf /tmp/GeoLite2.tar.gz -C /tmp/
mv /tmp/GeoLite2-Country_*/GeoLite2-Country.mmdb /usr/share/GeoIP/

Срок реализации

2–3 дня: настройка MaxMind + middleware + логика приоритетов + тестирование с VPN из разных стран.