Multilingual Symfony2 website - php

I have a huge problem that I couldn't resolve in the last few days. I don't expect you to give me a final solution because I think the problem is not so simple.
So I have a huge Symfony2 application that was built with the idea to work only with one language. All routes are in their responsible controllers. Now I want to prefix all routes with the selected language so could have:
myapp.com/en/news
myapp.com/fr/news
etc...
And if it is possible the default language should not be shown in the route - if English is my default language I want only myapp.com/news. The problem is that I can't just go through all routes and make them work both with optional parameter about the language and also work without that parameter. If it is not possible I am ok en to be presented in the route too.
I tried the jmsi18nroutingbundle because many other people suggested it but when I setup the config.yml as it is said only some of the routes get prefix when I check them with app/console debug:router. And because of that I am either not configuring it well or it has some limitations.
My question is how do you handle multilingual websites and their routes - do you start with the idea about multilingual system from the beginning and create at least two routes for each action one with optional parameter about the language and one without that parameter or you have more global solution to handle all routes?

Related

complex routing with symfony

Looking for best practice of Symfony (4) routing action for my URL schema.
Let's say I'm detecting GEO IP and showing different language for web users even in URL.
So what best practice would be to develop routing?
link examples,
when a user comes from the USA:
example.com/static_link_in_en/additional_static_element_in_en/special_static_element_in_en/extra_static_attribute_in_en
example.com/product_name_in_en/additional_element_of_product_in_en/special_element_for_this_item_in_en/extra_attribute_in_en
when a user comes from France:
example.com/static_link_in_fr/additional_static_element_in_fr/special_static_element_in_fr/extra_static_attribute_in_fr
example.com/product_name_in_fr/additional_element_of_product_in_fr/special_element_for_this_item_in_fr/extra_attribute_in_fr
another, maybe better example:
example.com/tag - static route, generates a tag cloud in EN
example/tag/ - static route, but displays an error or 404 page, because we are not searching in the database with an empty string in EN
example.com/tag/red - searching in the database with keyword 'red'
example.com/tag/blue - exceptional keyword, we have reserved tag 'blue' so the script will not be searching in the database, the static route will be used in EN
the same actions just translated in the French language:
example.com/marque
example.com/marque/
example.com/marque/rouge
let's say URL deep level can be up to 10 elements, any suggestions?
A better policy is to include the locale in the URL. This is fully-supported by the routing system using the special _locale parameter.
# config/routes.yaml
contact:
path: /{_locale}/contact
controller: App\Controller\ContactController::index
requirements:
_locale: en|fr|de
When using the special _locale parameter in a route, the matched locale is automatically set on the Request and can be retrieved via the getLocale() method. In other words, if a user visits the URI /fr/contact, the locale fr will automatically be set as the locale for the current request.
You can now use the locale to create routes to other translated pages in your application.
Source : https://symfony.com/doc/current/translation/locale.html
Symfony doesn't support defining routes with different contents depending on the user language. In those cases, you can define multiple routes per controller, one for each supported language; or use any of the bundles created by the community to implement this feature, such as JMSI18nRoutingBundle and BeSimpleI18nRoutingBundle.
Source : https://symfony.com/doc/current/routing.html#translating-routes

Symfony2 - What is the point of specifying your own route names?

Currently learning Symfony. Just wondering about route names, which the book doesn't really seem to say in advance what they are for.
As I understand it, #Route annotations are given a default name based on the bundle, controller and action name. So what's the point in specifying your own route names?
Is it good practice to either leave all routes to have a default name?
Is it better practice to specify your own name for every route?
What if two routes have the same name?
How am I expected to know if I'm using a route name which is already taken, perhaps in another bundle?
Route names are important because your code will often need to build url's. The route name is how you specify which url to construct. Names are also handy for listeners (such as authentication) which process specific url's.
Annotation generated default names are fine but tend to be long and could change on you.
Yes, I would give every route a custom name for convenience and readability. Plus, I don't use annotations. To me at least, storing routes in a central file make the code easier to maintain. It avoids the need to search through multiple controller files trying to determine which code handles which request.
Routes with the same name will replace any previously loaded route. It's useful if you wish to override a route from a third party bundle.
Namespace your route by using some form of your bundle name as a prefix.

Use cases for generated URLs in Symfony2?

Coming from a straight PHP and Drupal background, I am recently learning the Symfony2 framework. Currently I am in the routing chapter of the book. This is probably a simple question.
What are some real world use cases for why one would want to generate URLs in a Symfony app? I understand the code but I'm having a bit of trouble determining its practical applications.
I'm referring to this section should you need a refresher.
As always, thank you!
P.S. Symfony is amazing. :)
Basically, you need to generate a URL whenever you need to link to anywhere in your application.
Let's say that you have an application that needs to manage some users. This means that you will probably have URLs like /user/create, /user/edit/(user id) and /user/remove/(user id).
Whenever you display a link to edit a user you need to know on what URL you can find the page that allows you to edit a user. So you need to link to /user/edit/(user id). One solution would be to have this as a fixed link so that in your code you could just write
edit this user
But what if you want to change this URL scheme? Let's say someone is unhappy with the term "user", after all the humans managed by this system are not only users, they are actually "person"s! So now you need to change all the URLs containing "user". Probably there are quite a few places in your app where you have had to hardcode these URLs and now you will need to find and change all of them. Eugh.
But fear not, for Symfony routing comes to the rescue!
Instead of hardcoding these URLs, we can simply let the Symfony router generate them for us. This means that we first need to tell Symfony which routes we have, e.g. by adding the following YAML code to our routes config file:
user_edit:
path: /user/edit/{userId}
defaults: { _controller: AppBundle:User:edit }
requirements:
userId: \d+
This tells our application "Okay, whenever somebody requests a page that looks like /user/edit/{userId}, then you need to call the editAction method in our UserController class in the AppBundle namespace and you need to pass the userId as a parameter. Oh, and also you should only call the controller if userId is a valid integer with at least one number."
So this is how Symfony knows how to map URLs to controllers. But the goodness that comes along with it is that we can use this information for the reverse way as well.
Usually, in our application we do not really care about what the URL looks like for a certain action we want to perform. All we know is that when clicking a certain link, then the browser should jump to a page that allows me to edit a user. And since we just defined a route that takes us right there, we can have Symfony generate the correct URL to achieve just that.
So in your view you can now discard the hardcoded URL from earlier and instead replace it with a route generated by the Symfony router:
edit this user
Now whenever you need to change what the URL actually looks like all you need to do is edit your routing config and not a lot of separate views.
Because, imagine you want to change a given page URL and you've hardcoded it in 10 Twig templates. You will have to modify all these files. On the opposite, when using the routing component:
You would only have to change the URL where the route is defined.
The routing component "takes" care of the current environment you are using (dev, prod...)
Also note that is a bad practice to "switch environment", a typical issue is to hardcode an URL in a Javascript. In this case you can expose your Symfony2 routes in the Javascript by using a bundle like FOSJsRoutingBundle.
I almost immediately realized their use and now I feel silly. :) For those who stop by this question in the future:
Notes about Generating URLs:
Similar to the Drupal l() function, sometimes you need to generate links inside your application based on a variety of parameters.
You don't always want to hardcode your links in case you decide to change paths sometime down the line.
In summary: Think of this as an alternative to using straight anchor tags with href elements all over the app and, instead, keeping things dynamic.
Use case
In the project I'm working I use generateUrl to redirect the user
after creating, editing an entity.
For example after creating a Service entity, I redirect the user to the view
of the just created Service.
Controller
return $this->redirect($this->generateUrl('myentity_view', array('id'=> $id)));
Additional note
In twig files, you can use the path function which call the routing component and generate url with given route name and parameters.

Laravel localization, redirect to the right view

I'm using laravel and mcamara/laravel-localization package to manage a bilingual site (french/english).
In the package documention https://github.com/mcamara/laravel-localization
they don't explain how to point an URL to the right view depending on which language is set as local.
For example, if the URL is /en/contact load the view en.contact (en is the subdirectory for views written in english) and id the URL is /fr/contact load the view from the subdirectory fr.
The same for the URL that needs translation /en/products for english needs to load /fr/produits when the local language is set to french.
Disclaimer: I have never used the package...
That's because the package (and also the localization of laravel) assume that you are using Laravel's translations. So the package basically only worries about setting the application locale right and Laravel does the rest of the job.
However if you need different views (or don't want to use translations) you can just retrieve the current locale and use it to build the name of the view
View::make(App::getLocale().'.contact');
You have to change the view-path dynamically, so you dont have to prefix your views by hand.
Just create a new Middleware and register it in Kernel.php.
I've created a gist for that.
https://gist.github.com/vanderb/80dea9a8039dd60962c5cb291eae7b75
Now, all you have to do is to reference the view-name, without adding the lang-code every time.
I also recommend to use named-routes
https://laravel.com/docs/5.4/routing#named-routes
I don't see why you would want to use different views for each language. That would double your code. Just use one view with Laravels own translation features to translate your strings. The package handles the naming of routes (/products vs /produits). The views should stay the same.
If you really want different views for different languages, #lukasgeiter has the answer. Sounds like a code-duplication, though.
Side-note: Laravel 5.4s new JSON translation feature together with langman is really great.

How access to database on routing file with Symfony2?

I have to manage a multilingual routing as part of a Symfony2 project.
In order to get the whole URL translated i have to access the EntityManager from the PHP routing file to get the proper translation and the translated slugs.
Does anyone know how to do that ?
Thanking you,
Antoine.
May be you have to make separate third-level domain for each language (ru.site.com, fr.site.com) and generate routes using your database translation table from template?
What I could suggest you is to check the JMSI18nRoutingBundle. This bundle let you define localized routes. Here ta copy of the overview text for the bundle taken from the documentation:
Overview
This bundle allows you to create i18n routes. Key points:
uses the Translation component; translate URLs just like you would translate any other text on your website
allows you to use different hosts per locale
does not require you to change your development processes
can translate all routes whether they are coming from third-party bundles, or your own application
I did not use it myself and I'm not the developer of this bundle and I don't know if it will work for your slug. But I hope this will help you in some ways.
Regards,
Matt

Categories