Internacionalizar web por directorios según el país del usuario

En este articulo os voy a explicar como internacionalizar una aplicacion web redirigiendo al usuario al directorio segun el pais en el que se encuentre.

Os pongo el siguiente ejemplo: Imaginemos que queremos que los usuarios que viven en Mexico solo puedan ver los productos especificos de su pais, ya que estan segmentados por paises. Por lo que un usuario que acceda a la web española debera ser redirigido a la web de Mexico.

Para ello usaremos un bundle para las rutas muy util llamado : JMSi18nRoutingBundle:

1- Añadimos al composer.json

"jms/i18n-routing-bundle": "^2.0"

2- Inicializamos en AppKernel en bundle:

new JMS\I18nRoutingBundle\JMSI18nRoutingBundle(),

3- Configuramos el bundle(Existen mas opciones disponibles en el bundle pero en nuestro caso queremos esta)

jms_i18n_routing:
    default_locale: es
    locales: [es, mx]
    strategy: prefix

4- Instalamos el bundle para Geolocalizar por IP al usuario:

"maxmind/geoip": "~1.0.0",

5- Inicializamos en AppKernel

new \Maxmind\Bundle\GeoipBundle\MaxmindGeoipBundle(),

6- Este bundle necesita descargarse la base de datos interna para localizar la IP del usuario, para ello ejecutamos el siguiente comando:

php app/console maxmind:geoip:update-data 
http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz

Esto nos descargara un fichero .dat dentro del bundle pero si queremos moverlo para versionarlo o cualquier cosa, creamos esta configuracion de config.yml

maxmind_geoip:
    data_file_path: "%kernel.root_dir%/../app/GeoLiteCity.dat"

En mi caso lo he ubicado dentro de la carpeta app/

7- Creamos un Listener para capturar los eventos del Kernel y comprobar la IP, de la siguiente forma AppBundle/Listener/LocaleListener.php

<?php

namespace AppBundle\Listener;

use Maxmind\Bundle\GeoipBundle\Service\GeoipManager;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
use Symfony\Component\Security\Core\Authorization\AuthorizationChecker;

class LocaleListener implements EventSubscriberInterface
{
    const DEFAULT_LANGUAGE = 'es';

    private $avaliableLanguages;

    /** @var TokenStorageInterface */
    private $context;

    /** @var  Router $router */
    private $router;

    /** @var GeoipManager */
    private $geoIp;

    /** @var AuthorizationChecker */
    private $authChecker;

    /**
     * LocaleListener constructor.
     *
     * @param TokenStorageInterface $context
     * @param Router $router
     * @param GeoipManager $geoIp
     * @param AuthorizationChecker $authorizationChecker
     * @param $languages
     */
    public function __construct(TokenStorageInterface $context, Router $router, GeoipManager $geoIp, AuthorizationChecker $authorizationChecker, $languages)
    {
        $this->context = $context;
        $this->router = $router;
        $this->geoIp = $geoIp;
        $this->authChecker = $authorizationChecker;
        $this->avaliableLanguages = $languages;

    }

    /**
     * @param GetResponseEvent $event
     */
    public function onKernelRequest(GetResponseEvent $event)
    {
        /** @var Request $request */
        $request = $event->getRequest();
        $localeRequest = $request->getLocale();

        $clientIp = $request->getClientIp();
        $geoip = $this->geoIp->lookup($clientIp);

        if($geoip){
            $geoIpLocale = strtolower($geoip->getCountryCode());

            if(in_array($geoIpLocale, $this->avaliableLanguages)){
                $request->setLocale($geoIpLocale);
            }else{
                $request->setLocale(self::DEFAULT_LANGUAGE);
            }
        }elseif (!in_array($localeRequest, $this->avaliableLanguages)){
            $request->setLocale(self::DEFAULT_LANGUAGE);
        }else{
            $request->setLocale($localeRequest);
        }
    }

    public static function getSubscribedEvents()
    {
        return array(
            KernelEvents::REQUEST => array(array('onKernelRequest', 1))
        );
    }
}

8- Añadimos dentro del parameters.yml los idiomas disponibles:

languages:
    - es
    - mx

9- Creamos el servicio para que se enganche al subscribe del Kernel dentro del archivo /app/services.yml

service:
//....
myapp.locale_listener:
    class: AppBundle\Listener\LocaleListener
    arguments: ["@security.token_storage", "@router", "@maxmind.geoip", "@security.authorization_checker" ,"%languages%"]
    tags:
        - { name: kernel.event_subscriber }

Con estos cambios ya tendremos practicamente todo montado, ahora si accedemos a cualquier ruta de la web, debera setear el idioma que le toque o si no existe poner el idioma por defecto.

Tambien podemos añadir en el footer de nuestra web, varios enlaces a los idiomas posibles de la siguiente forma:

  • <a href=”{{ path(‘homepage’, {‘_locale’: ‘mx’}) }}”>Mexico</a>
  • <a href=”{{ path(‘homepage’, {‘_locale’: ‘es’}) }}”>España</a>

Espero que os haya gustado y recordar compartir este articulo.

Saludos ¡¡

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión /  Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión /  Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión /  Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión /  Cambiar )

w

Conectando a %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.