Comment créer des itinéraires traduits en plusieurs langues à Laravel

je voudrais créer une application avec de nombreuses routes traduites en fonction de la langue choisie. J'ai déjà décrit à 3 méthodes de création D'URLs dans les sites Web multilingues.

Dans ce cas, il doit être la première méthode de sujet mentionné donc:

  1. j'ai une langue par défaut
  2. je peux avoir de nombreuses autres langues
  3. la langue courante ne doit être calculée que par URL (sans cookies/sessions) pour le rendre vraiment convivial aussi pour les moteurs de recherche
  4. Pour la langue par défaut il devrait y avoir pas de préfixe de l'URL pour d'autres langues devraient être préfixe de langue après de domaine
  5. chaque partie de l'url doit être traduite selon la langue courante.

supposons que j'ai défini le langage par défaut pl et 2 autres langues en et fr. Je n'ai que 3 pages - de la page d'accueil, page de contact et a propos de la page.

Url pour le site devrait examiner ensuite de cette façon:

/
/[about]
/[contact]
/en
/en/[about]
/en/[contact]
/fr
/fr/[about]
/fr/[contact]

alors que [about] et [contact] doit être traduit selon la langue choisie, par exemple en anglais il doit être laissé contact mais pour le polonais il devrait être kontakt et ainsi de suite.

Comment faire aussi simple que possible?

37
demandé sur Community 2014-08-01 18:09:38

2 réponses

Première étape:

app/lang annuaire et créez ici des traductions pour vos itinéraires pour chaque langue. Vous devez créer 3 routes.php fichiers-chacun dans un répertoire de langues séparé (pl/en / fr) Parce que vous voulez utiliser 3 langues

Pour Le Polonais:

<?php

// app/lang/pl/routes.php

return array(

    'contact' => 'kontakt',
    'about'   => 'o-nas'
);

Pour L'Anglais:

<?php

// app/lang/en/routes.php

return array(
    'contact' => 'contact',
    'about'   => 'about-us'
);

Pour Le Français:

<?php

// app/lang/fr/routes.php

return array(
    'contact' => 'contact-fr',
    'about'   => 'about-fr'
);

Deuxième étape:

app/config/app.php fichier.

Vous devriez trouver la ligne:

'locale' => 'en',

et de le changer en un langage qui devrait être votre langue principale du site (dans votre cas, polonais):

'locale' => 'pl',

Vous devez également mettre dans ce fichier les lignes suivantes:

/**
 * List of alternative languages (not including the one specified as 'locale')
 */
'alt_langs' => array ('en', 'fr'),

/**
 *  Prefix of selected locale  - leave empty (set in runtime)
 */
'locale_prefix' => '',

alt_langs config vous pouvez définir d'autres langues (dans votre cas en et fr) - ils doivent être les mêmes que les noms de fichiers de la première étape où vous avez créé des fichiers avec des traductions.

Et locale_prefix est le préfixe de vos paramètres régionaux. Vous ne vouliez pas de préfixe pour votre locale par défaut donc elle est définie pour vider la chaîne. Cette configuration sera modifiée à l'exécution si une autre langue que la langue par défaut est sélectionnée.

Troisième étape

Aller à votre app/routes.php classez et mettez leur contenu (c'est tout le contenu de app/routes.php fichier):

<?php

// app/routes.php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/


/*
 *  Set up locale and locale_prefix if other language is selected
 */
if (in_array(Request::segment(1), Config::get('app.alt_langs'))) {

    App::setLocale(Request::segment(1));
    Config::set('app.locale_prefix', Request::segment(1));
}


/*
 * Set up route patterns - patterns will have to be the same as in translated route for current language
 */
foreach(Lang::get('routes') as $k => $v) {
    Route::pattern($k, $v);
}


Route::group(array('prefix' => Config::get('app.locale_prefix')), function()
{
    Route::get(
        '/',
        function () {
            return "main page - ".App::getLocale();
        }
    );


    Route::get(
        '/{contact}/',
        function () {
            return "contact page ".App::getLocale();
        }
    );



    Route::get(
        '/{about}/',
        function () {
            return "about page ".App::getLocale();

        }
    );

});

comme vous voyez d'abord vous vérifiez si le premier segment d'url correspond au nom de vos langues - si oui, vous changer la locale et le préfixe de la langue courante.

puis dans la boucle minuscule, vous définissez des exigences pour vos noms de tous les itinéraires (vous avez mentionné que vous voulez avoir about et contact traduit en URL) Donc ici vous les définissez comme identiques à ceux définis dans routes.php fichier pour la langue courante.

enfin vous créez le groupe Route qui aura le même préfixe que votre langue (pour la langue par défaut il sera vide) et à l'intérieur du groupe vous créez simplement des chemins mais ces paramètres about et contact vous traiter comme variables si vous utilisez {about} et {contact} syntaxe pour eux.

vous devez Vous rappeler que, dans ce cas {contact} dans toutes les routes sera cochée si elle est la même que celle que vous avez définie dans la première étape pour la langue courante. Si vous ne voulez pas de cet effet et que vous voulez configurer les routes manuellement pour chaque route en utilisant où, il y a une alternative app\routes.php fichier sans boucle où vous définissez contact et about séparément pour chaque itinéraire:

<?php

// app/routes.php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the Closure to execute when that URI is requested.
|
*/

/*
 *  Set up locale and locale_prefix if other language is selected
 */
if (in_array(Request::segment(1), Config::get('app.alt_langs'))) {

    App::setLocale(Request::segment(1));
    Config::set('app.locale_prefix', Request::segment(1));
}


Route::group(array('prefix' => Config::get('app.locale_prefix')), function()
{
    Route::get(
        '/',
        function () {
            return "main page - ".App::getLocale();
        }
    );


    Route::get(
        '/{contact}/',
        function () {
            return "contact page ".App::getLocale();
        }
    )->where('contact', Lang::get('routes.contact'));



    Route::get(
        '/{about}/',
        function () {
            return "about page ".App::getLocale();

        }
    )->where('about', Lang::get('routes.about'));


});

Quatrième étape:

vous n'en avez pas parlé, mais il y a une chose en plus que vous pourriez considérer. Si quelqu'un utilise url /en/somethingsomething n'est pas correct Route, je pense que la meilleure solution pour faire de la redirection. Mais vous devez faire redirection pas à / parce que c'est la langue par défaut, mais /en.

Alors maintenant, vous pouvez ouvrir app/start/global.php le fichier et créer ici redirection 301 pour l'inconnu url:

// app/start/global.php

App::missing(function()
{
   return Redirect::to(Config::get('app.locale_prefix'),301);
});
62
répondu Marcin Nabiałek 2014-09-03 11:47:09

Marcin Nabiałek nous a fourni dans sa réponse initiale est une solution solide au problème de localisation de route.

Le Mineur Bugbear:

le seul vrai inconvénient de sa solution est que nous ne pouvons pas utiliser les routes mises en cache, ce qui peut parfois être d'un grand bénéfice selon Laravel's docs:

si votre application utilise exclusivement des routes basées sur le contrôleur, vous devrait prendre avantage de la cache route de Laravel. Utiliser le cache de route diminuera drastiquement le temps qu'il faut pour enregistrer tous des itinéraires de votre demande. Dans certains cas, votre itinéraire enregistrement peut-être même jusqu'à 100 fois plus rapide. Pour générer un cache, exécutez simplement: route:cache Artisan de commande.


pourquoi ne pouvons-nous pas cacher nos routes?

Parce que Marcin Nabiałek's la méthode génère de nouvelles routes basé sur le locale_prefix dynamiquement, les mettre en cache donnerait un 404 erreur lors de la visite d'un préfixe Non stocké dans le locale_prefix variable au moment de la mise en cache.


que gardons-nous?

La fondation semble vraiment solide et on peut garder la plupart de!

nous pouvons certainement conserver les différents fichiers de route spécifiques à la localisation:

<?php

// app/lang/pl/routes.php

return array(

    'contact' => 'kontakt',
    'about'   => 'o-nas'
);

nous pouvons aussi garder tous les app/config/app.php variables:

/**
* Default locale 
*/
'locale' => 'pl'

/**
 * List of alternative languages (not including the one specified as 'locale')
 */
'alt_langs' => array ('en', 'fr'),

/**
 *  Prefix of selected locale  - leave empty (set in runtime)
 */
'locale_prefix' => '',

 /**
 * Let's also add a all_langs array
 */
'all_langs' => array ('en', 'fr', 'pl'),

nous aurons aussi besoin du bit de code qui vérifie les segments de route. Mais puisque le but de ceci est d'utiliser le cache, nous devons le déplacer à l'extérieur du routes.php fichier. Celui-ci ne sera plus utilisé une fois que nous aurons caché les routes. Nous pouvons pour le moment le déplacer vers app/Providers/AppServiceProver.php par exemple:

public function boot(){
  /*
   *  Set up locale and locale_prefix if other language is selected
   */
   if (in_array(Request::segment(1), config('app.alt_langs'))) {
       App::setLocale(Request::segment(1));
       config([ 'app.locale_prefix' => Request::segment(1) ]);
   }
}

N'oubliez pas:

use Illuminate\Support\Facades\Request;
use Illuminate\Support\Facades\App;

mise en place de nos routes:

Plusieurs changements à l'intérieur de notre app/Http/routes.php fichier.

tout d'Abord, nous avons à faire un nouveau tableau contenant tous les alt_langs ainsi que la valeur par défaut locale_prefix, qui serait probablement '':

$all_langs = config('app.all_langs');

pour pouvoir mettre en cache tous les différents préfixes lang avec les paramètres de route traduits, nous avons besoin de les enregistrer tous. Comment pouvons-nous faire?

*** Laravel aside 1: ***

regardons la définition de Lang::get(..):

public static function get($key, $replace = array(), $locale = null, $fallback = true){
      return \Illuminate\Translation\Translator::get($key, $replace, $locale, $fallback);
}

le troisième paramètre de cette fonction est un $locale variable! La Great - nous pouvez certainement l'utiliser à notre avantage! Cette fonction nous permet en fait de choisir de quelle localité nous voulons obtenir la traduction!

La prochaine chose que nous allons faire est de parcourir les $all_langs array et de créer un nouveau Route groupe pour chaque préfixe de langue. Non seulement cela, mais nous allons aussi se débarrasser de l' where chaînes et patterns que nous avions besoin auparavant, et n'enregistrons que les routes avec leur traductions (d'autres pourront jeter 404 sans avoir à vérifier pour elle plus):

/**
* Iterate over each language prefix 
*/
foreach( $all_langs as $prefix ){

   if ($prefix == 'pl') $prefix = '';

   /**
   * Register new route group with current prefix
   */
   Route::group(['prefix' => $prefix], function() use ($prefix) {

         // Now we need to make sure the default prefix points to default  lang folder.
         if ($prefix == '') $prefix = 'pl';

         /**
         * The following line will register:
         *
         * example.com/
         * example.com/en/
         */
         Route::get('/', 'MainController@getHome')->name('home');

         /**
         * The following line will register:
         *
         * example.com/kontakt
         * example.com/en/contact
         */
         Route::get(Lang::get('routes.contact',[], $prefix) , 'MainController@getContact')->name('contact');

         /**
         * “In another moment down went Alice after it, never once 
         * considering how in the world she was to get out again.”
         */
         Route::group(['prefix' => 'admin', 'middleware' => 'admin'], function () use ($prefix){

            /**
            * The following line will register:
            *
            * example.com/admin/uzivatelia
            * example.com/en/admin/users
            */
            Route::get(Lang::get('routes.admin.users',[], $prefix), 'AdminController@getUsers')
            ->name('admin-users');

         });
   });
}

/**
* There might be routes that we want to exclude from our language setup.
* For example these pesky ajax routes! Well let's just move them out of the `foreach` loop.
* I will get back to this later.
*/
Route::group(['middleware' => 'ajax', 'prefix' => 'api'], function () {
    /**
    * This will only register example.com/api/login
    */
    Route::post('login', 'AjaxController@login')->name('ajax-login');
});

Houston, nous avons un problème!

comme vous pouvez le voir je préfère utiliser les routes nommées (la plupart des gens le font probablement):

Route::get('/', 'MainController@getHome')->name('home');

ils peuvent être très facilement utilisés à l'intérieur de vos gabarits de lame:

{{route('home')}}

mais il y a un problème avec ma solution jusqu'à présent: les noms de routes se supplantent les uns les autres. foreach boucle ci-dessus n'Enregistrez que les dernières routes préfixées avec leurs noms.

En d'autres termes example.com/ serait lié à l' home route locale_perfix a été le dernier élément de l' $all_langs array.

nous pouvons contourner cela en préfixant les noms de routes avec la langue $prefix. Par exemple:

Route::get('/', 'MainController@getHome')->name($prefix.'_home');

nous devrons le faire pour chacune des routes de notre boucle. Cela crée un autre petit obstacle.


Mais mon le projet massif est presque terminé!

comme vous l'avez probablement deviné, vous devez maintenant retourner à tous vos fichiers et préfixer chacun route fonction helper appeler avec lelocale_prefix chargé à partir du app config.

Sauf que ce n'est pas!

*** Laravel aside 2: ***

regardons comment Laravel met en œuvre il est route méthode de l'aide.

if (! function_exists('route')) {
    /**
     * Generate a URL to a named route.
     *
     * @param  string  $name
     * @param  array   $parameters
     * @param  bool    $absolute
     * @return string
     */
    function route($name, $parameters = [], $absolute = true)
    {
        return app('url')->route($name, $parameters, $absolute);
    }
}

comme vous pouvez le voir Laravel vérifiera d'abord si un route fonction il existe déjà. Il enregistrera son route la fonction que si l'autre n'existe pas encore!

ce qui signifie que nous pouvons contourner notre problème très facilement sans avoir à réécrire chaque route appel fait jusqu'ici dans notre Blade modèles.

prenons un app/helpers.php fichier très rapide.

assurons-nous que Laravel charge le fichier avant qu'il ne charge son helpers.php en mettant la ligne suivante dans la section bootstrap/autoload.php

//Put this line here
require __DIR__ . '/../app/helpers.php';
//Right before this original line
require __DIR__.'/../vendor/autoload.php';

Tout ce que nous avons maintenant à faire est de faire notre propre route fonction au sein de nos app/helpers.php fichier. Nous allons utiliser l'original de mise en œuvre de la base:

<?php
//Same parameters and a new $lang parameter
function route($name, $parameters = [], $absolute = true, $lang = null)
{
    /*
    * Remember the ajax routes we wanted to exclude from our lang system?
    * Check if the name provided to the function is the one you want to
    * exclude. If it is we will just use the original implementation.
    **/
    if (str_contains($name, ['ajax', 'autocomplete'])){
        return app('url')->route($name, $parameters, $absolute);
    }

   //Check if $lang is valid and make a route to chosen lang
   if ( $lang && in_array($lang, config('app.alt_langs')) ){
       return app('url')->route($lang . '_' . $name, $parameters, $absolute);
   }

    /**
    * For all other routes get the current locale_prefix and prefix the name.
    */
    $locale_prefix = config('app.locale_prefix');
    if ($locale_prefix == '') $locale_prefix = 'pl';
    return app('url')->route($locale_prefix . '_' . $name, $parameters, $absolute);
}

C'est ça!

donc ce que nous avons fait essentiellement est enregistré tous les groupes de préfixes disponibles. Créé chaque route traduite et avec son nom aussi préfixé. Et puis en quelque sorte remplacé le Laravel route fonction pour préfixer tous les noms de routes (sauf certains) avec le locale_prefix pour que les urls appropriées soient créées dans nos modèles de lame sans avoir à taper config('app.locale_prefix') à chaque fois.

Ah oui:

php artisan route:cache

les routes de mise en cache ne devraient être réellement faites qu'une fois que vous déployez votre projet car il est probable que vous allez les brouiller pendant le développement. Mais vous pouvez toujours vider le cache:

php artisan route:clear

Merci encore Marcin Nabiałek pour sa réponse originale. C'était vraiment utile pour moi.

13
répondu PeterTheLobster 2017-05-23 12:18:12