Estoy usando Silex y Twig para un sitio web y quiero permitir que el usuario cambie el idioma del sitio.

Mi problema

En este momento, funciona si cambio la configuración regional en la URL:

/my-account: el contenido de mi página está en inglés (predeterminado _locale)

/fr/my-account: el contenido de mi página está en francés

/en/my-account: el contenido de mi página está en inglés

¿Cómo puedo hacer lo mismo haciendo clic en un elemento html?

Estoy buscando alguna idea para resolver mi problema y algunas buenas prácticas para hacer esto "de la manera correcta" si es posible.

Mi código

Aquí está el componente Silex que uso para administrar el multilangue:

// TRANSLATION
$app->register(new Silex\Provider\LocaleServiceProvider());
$app->register(new Silex\Provider\TranslationServiceProvider());
$app->register(new \Pmaxs\Silex\Locale\Provider\LocaleServiceProvider(), [
    'locale.locales' => ['en', 'fr'],
    'locale.default_locale' => 'en',
    'locale.resolve_by_host' => false,
    'locale.exclude_routes' => ['^_']
]);
$app->extend('translator', function($translator, $app) {
    $translator->addLoader('yaml', new YamlFileLoader());

    $translator->addResource('yaml', __DIR__.'/../src/locales/en.yml', 'en');
    $translator->addResource('yaml', __DIR__.'/../src/locales/fr.yml', 'fr');

    return $translator;
});

Aquí está mi html para que el usuario cambie el idioma:

<li id="drop-langue" data-lg="en">
    <span id="current-lg">EN</span> // My current langue
    <div class="drop-langue">
        // The list of langage the user can choose : here ONE -> FR
        <div id="list_langue">
          <a class="change_langue" href="#" data-lg="fr"> <span>FR</span></a> // Could be nice to change the langue staying on the same page
        </div>
    </div>
</li>

Ahora mi jQuery para obtener el valor:

$(document).ready(function() {
    $(".change_langue").on("click", function() {
        var new_langue = $(this).data("lg");

        $.ajax({
            url: "{{ path('new-langue') }}",
            type: 'POST',
            data: {'langue': new_langue},
            success: function (resp) {
                console.log(resp);
            },
            error: function (resp) {
                console.log(resp);
            }
        });
    });
});

Mi controlador Ajax:

$app->match('/new-langue', function (Request $request) use ($app) {
    $new_langue = $request->get('langue');

    // some code to change the langage

    return New Response($new_langue);
})->bind('new-langue');

Si hago esto, mi éxito con Ajax console.log(resp); me da en como quiero.

Algunas ideas / preguntas sobre cómo hacerlo

  1. ¿Es una buena idea hacerlo con una llamada Ajax?
  2. Si cambio fr por en en mi url, funciona, ¿es una buena idea intentar hacerlo en JavaScript usando window.location.href por ejemplo? (Creo que no pero aún preguntando)
  3. Vi esta solución para otro problema e intento en mi controlador, pero obtengo esto error: 500 (Internal Server Error) (Hice lo mismo, con $new_langue en lugar de $app['defaultLanguage'] y con el nombre correcto para mi página de inicio).

Es la primera vez que creo un sitio web completo con Silex y soy principiante con php framework, así que si alguien puede ayudarme a lograr lo que quiero ... ¡gracias de antemano!

EDITAR:

Según la respuesta que obtengo y lo que quiero lograr, ¿es posible cambiar la configuración regional y permanecer en la misma página con Silex / Twig?

Por ejemplo, esto me da la ruta actual: global.request.get('_route') y esto global.request.get('_locale') me da la configuración regional.

Si tomo el ejemplo de mi página de inicio, así es como se ve mi controlador en este momento (solo muestro la plantilla):

$app->match('/', function (Request $request) use ($app) {
    return $app['twig']->render('home.html.twig');
})->bind('home');

Como puede ver, no tengo el parámetro {_locale} en mi URL. Entonces, ¿puedo mantener esta "URL limpia" sin {_locale} y hacer un clic que permanezca en la misma página + cambiar el idioma actual?

Me gustaría hacer algo como esto: <a href="{{ path(global.request.get('_route')), global.request.set('_locale', 'FR') }}">FR</a>

Pero no funcionará con seguridad ... ¿puedo hacer esto?

4
Mickaël Leger 1 mar. 2018 a las 20:15

4 respuestas

La mejor respuesta

Finalmente encuentro una solución para hacer lo que quiero, usando pmaxs/silex-locale (https: // github. com / pmaxs / silex-locale).

Como dije en mi pregunta, ya lo usé para mi traducción pero no usé la "Generación de URL" como debería ... Así que aquí hay un resumen de cómo usarlo (lea la documentación si usa Silex v1 .X):

1 / Proveedor de carga

$app->register(new \Pmaxs\Silex\Locale\Provider\LocaleServiceProvider(), [
    'locale.locales' => ['en', 'fr'],  //I want to translate my site in English and French
    'locale.default_locale' => 'en',   // By default, the locale is "en"
    'locale.resolve_by_host' => false,
    'locale.exclude_routes' => ['^_']
]);
$app->register(new Silex\Provider\LocaleServiceProvider());

2 / Uso

Aquí está mi controlador de ruta de origen:

// this page is accessible by urls '/', '/fr/' or '/en/'
$app->match('/', function (Request $request) use ($app) {

    // my code

     return $app['twig']->render('home.html.twig');
})->bind('home');

Como puede ver, no tengo ninguna variable {_locale} en mi enrutamiento, pero aún así puedo usarla para cambiar el idioma de mi página.

3 / Generador de URL

Ahora, así es como cambio mi idioma:

{% set locale_list = ["en", "fr"] %} // the list of all langage in my website
{% set current_locale = global.request.getLocale() %} // the current langage of my page

<li id="drop-langue">
    // I display the current langage
    <span id="current-lg">{{ current_locale|upper }}</span> 
    <div class="drop-langue">
        <div id="list_langue">
            {% for locale in locale_list %}
                {% if locale != current_locale %}
                    // I create one link to change the langage according to all the langage I want, minus the current langage
                    <a class="change_langue" href="{{ locale_generate(locale , global.request.get('_route')) }}" >
                        <span>{{ locale|upper }}</span>
                    </a>
                 {% endif %}
             {% endfor %}
         </div>
     </div>
 </li>

Estoy usando el "Generador de URL", funciona así: locale_generate('es', $name, $parameters = array(), $referenceType = UrlGeneratorInterface::ABSOLUTE_PATH) (más detalles en la documentación).

De esta manera, cuando entro en mi sitio web, estoy en inglés (mi configuración regional predeterminada) con mi "URL limpia" /. Luego, al hacer clic en FR mi URL se convierte en /fr/ y mi contenido se traduce al francés con un nuevo menú de selección (current-langue = FR y puedo seleccionar "EN").

0
Mickaël Leger 12 mar. 2018 a las 12:43

En su caso, es solo cuestión de agregar enlaces adecuados para permitir a los usuarios que puedan cambiar de idioma. El resto del trabajo ya lo has hecho tú. El menú desplegable del conmutador de idiomas debe contener todos los idiomas admitidos, incluido el inglés. Vea a continuación una imagen de ejemplo.

enter image description here

En lugar de redirigir a los usuarios a http://yourwebsite.com/[fr]/my-account, debe redirigir a un método especial como http://www.yourwebsite.com/language_change?lang=fr. Obtendrá HTTP_REFERRER en la variable $_SERVER para que pueda redirigir a los usuarios a la página original en la que se encontraban. De esta forma, puede preservar la página / url actual de los usuarios.

En segundo lugar, Ajax vs Redirect: es mejor usar una redirección en lugar de AJAX. Si usa AJAX, aumentará la complicidad para usted mismo.

Al trabajar con un sitio web multilingüe, debemos seguir estas mejores prácticas.

  • Rutas específicas por idioma

  • Menús, etiquetas y formularios.

  • El contenido del sitio web.

  • Extra: traducir FOSUserBundle

1
elegant-user 5 mar. 2018 a las 06:45

La idea simple aquí es: cómo su aplicación determina el idioma que se utilizará para representar las páginas.

solución # 1 (su solución actual) basada en un parámetro de URL (eso es _locale), y recurrir a algún valor predeterminado en caso de que no se proporcione un parámetro de URL.
Entonces, en esta solución, el componente de traducción siempre busca el idioma seleccionado en la bolsa de parámetros preparada por el componente de enrutador.

Solución # 2 ponga su identificador de idioma dentro de una variable de sesión. Su página /new-langue tendrá que establecer esta variable de sesión con el valor que recibe. y su enrutador completará el parámetro _locale de esa variable de sesión.

Es posible que pueda proporcionar algunos fragmentos de código un poco más tarde.

0
Ahmad Tawila 11 mar. 2018 a las 15:29

Entonces, de su mensaje, puedo extraer que su objetivo es permitir que se cambie el idioma cuando hace clic en un elemento HTML .

El uso de la etiqueta a define un hipervínculo, que se utiliza para vincular de una página a otra y se puede utilizar para lograr lo que desea.

He hecho sitios de múltiples idiomas anteriormente y puedes lograr esto de varias maneras.

/////////////////////////////// Método 1: defina la ubicación en el atributo HTML href

En su código HTML ha utilizado hash - # dentro del hipervínculo.

Los hipervínculos requieren la propiedad href, porque especifica una ubicación.

Al mirar su código, tiene la etiqueta pero le falta el enlace a la ubicación específica a la que desea redirigir al usuario.

Digamos que desea que vaya a la página my-account en francés.

Entonces, su código HTML debe ser:

<li id="drop-langue" data-lg="en">
    <span id="current-lg">EN</span> // My current langue
    <div class="drop-langue">
        // The list of langage the user can choose : here ONE -> FR
        <div id="list_langue">
          <a class="change_langue" href="http://yourwebsite.com/fr/my-account" data-lg="fr"><span>FR</span></a> 
        </div>
    </div>
</li>

Para tener en cuenta: sustituya yourwebsite.com con el dominio de su sitio web.

/////////////////////////////// final del Método 1

En tu código HTML mencionas // Could be nice to change the langue staying on the same page.

Eso se puede hacer usando AJAX, sí.

Pero no le sugiero que haga eso porque al mirar compañías más grandes que también tienen sitios web en varios idiomas, como SAP o Apple todos redirigen a una página diferente.

/////////////////////////////// ACTUALIZACIÓN: la respuesta hasta ahora fue creada porque pensé que su la necesidad era simplemente permitir que se cambiara el idioma al hacer clic en un elemento HTML.

Aparentemente, tu objetivo es un poco más complejo que eso.

De acuerdo con la documentación de Silex, el uso de _locale es el camino a seguir.

En esta pregunta puede ver el código de trabajo:

<?php

require_once __DIR__.'/../vendor/autoload.php';

$app = new Silex\Application();
$app['debug'] = true;

$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
$app->register(new Silex\Provider\TwigServiceProvider(), array(
    'twig.path' => __DIR__.'/../views',
));

$app->register(new Silex\Provider\TranslationServiceProvider(array(
    'locale_fallbacks' => array('hr'),
)));


$app['translator'] = $app->share($app->extend('translator', function($translator) {

    $translator->addLoader('xlf', new \Symfony\Component\Translation\Loader\XliffFileLoader());

    $translator->addResource('xlf', __DIR__.'/../locales/hr.xlf', 'hr');
    $translator->addResource('xlf', __DIR__.'/../locales/en.xlf', 'en');
    $translator->addResource('xlf', __DIR__.'/../locales/sl.xlf', 'sl');

    return $translator;
}));


$app->get('/', function () use ($app) {

    $app['translator']->setLocale('hr');

    return $app['twig']->render('home.twig', array('d' => $app['translator']->getLocale()));

});


$app->get('/{_locale}/', function() use ($app) {
    $app['translator']->setLocale($app['request']->get('locale'));

    return $app['twig']->render('home.twig', array('d' => $app['translator']->getLocale()));
});



$app->run();
4
molecoder 11 mar. 2018 a las 15:42