04/02/2017 - SYMFONY
Bu örnekte symfony ile çok dilli uygulama yapmayı öğreneceğiz. İngilizce en ve Türkçe tr dillerinde sabit ve değişken mesajlar kullanacağız. Mesaj kodlarını insanların okuyabilecekleri mesajlara çevirmek için, twig şablonlarında trans fonksiyonunu, controller içinde ise translator servisini kullanacağız.
Yaptığınız değişikliklerden sonra, sık sık önbelleği temizlemeniz gerekecek. Bu tüm ortamlar için geçerlidir.
Kullanımda olan InanzzzApplicationBundle paketindeki en dili için mevcut olan tüm mesajları $ php bin/console debug:translation en InanzzzApplicationBundle komutu ile listeleyebilirsiniz.
Aşağıda da gördüğümüz gibi URL en ve tr parametrelerini kullanıyor.
http://myapp.dev/app_dev.php/en/
http://myapp.dev/app_dev.php/tr/
http://myapp.dev/app_dev.php/en/translator
http://myapp.dev/app_dev.php/tr/translator
Her URL _locale parametresini en veya tr olarak barındırmak zorundadır. Eğer bir kullanıcı içinde en veya tr parametresi olmayan bir URL'ye ulaşmaya çalışırsa, event listener isteğin yolunu kesip en veya tr ekleme işlemini yapıp, kullanıcı yönlendirme işlemini yapacaktır. Birazdan bu işlemin nasıl yapıldığını göreceksiniz.
parameters:
locale: en
default_locale: en
valid_locales: en|tr
framework:
translator: { fallbacks: ["%locale%"] }
inanzzz_application:
resource: "@InanzzzApplicationBundle/Controller/"
type: annotation
prefix: /{_locale}/
requirements:
_locale: "%valid_locales%"
defaults:
_locale: "%default_locale%"
_wdt:
resource: "@WebProfilerBundle/Resources/config/routing/wdt.xml"
prefix: /{_locale}/_wdt
_profiler:
resource: "@WebProfilerBundle/Resources/config/routing/profiler.xml"
prefix: /{_locale}/_profiler
_errors:
resource: "@TwigBundle/Resources/config/routing/errors.xml"
prefix: /{_locale}/_error
_main:
resource: routing.yml
#src/Inanzzz/ApplicationBundle/Resources/translations/messages.en.xlf
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="en" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="application.greeting">
<source>application.greeting</source>
<target>Welcome to our multilingual application!</target>
</trans-unit>
<trans-unit id="user.greeting">
<source>user.greeting</source>
<target>Hello %name% %surname%!</target>
</trans-unit>
<trans-unit id="page.translator.header">
<source>page.translator.header</source>
<target>Translator</target>
</trans-unit>
</body>
</file>
</xliff>
$ php bin/console debug:translation en InanzzzApplicationBundle
---------- ---------- ------------------------ ------------------------------------------
State Domain Id Message Preview (en)
---------- ---------- ------------------------ ------------------------------------------
messages application.greeting Welcome to our multilingual application!
unused messages user.greeting Hello %name% %surname%!
unused messages page.translator.header Translator
---------- ---------- ------------------------ ------------------------------------------
#src/Inanzzz/ApplicationBundle/Resources/translations/messages.tr.xlf
<?xml version="1.0"?>
<xliff version="1.2" xmlns="urn:oasis:names:tc:xliff:document:1.2">
<file source-language="tr" datatype="plaintext" original="file.ext">
<body>
<trans-unit id="application.greeting">
<source>application.greeting</source>
<target>Çok dilli web uygulamamıza hoşgeldiniz!</target>
</trans-unit>
<trans-unit id="user.greeting">
<source>user.greeting</source>
<target>Merhabe %name% %surname%!</target>
</trans-unit>
<trans-unit id="page.translator.header">
<source>page.translator.header</source>
<target>Çevirmen</target>
</trans-unit>
</body>
</file>
</xliff>
$ php bin/console debug:translation tr InanzzzApplicationBundle
---------- ---------- ------------------------ -----------------------------------------
State Domain Id Message Preview (tr)
---------- ---------- ------------------------ -----------------------------------------
messages application.greeting Çok dilli web uygulamamıza hoşgeldiniz!
unused messages user.greeting Merhabe %name% %surname%!
unused messages page.translator.header Çevirmen
---------- ---------- ------------------------ -----------------------------------------
namespace Inanzzz\ApplicationBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Response;
/**
* @Route("", service="inanzzz_application.controller.default")
*/
class DefaultController
{
private $templating;
public function __construct(EngineInterface $templating)
{
$this->templating = $templating;
}
/**
* @Method({"GET"})
* @Route("/")
*
* @return Response
*/
public function indexAction()
{
return $this->templating->renderResponse(
'InanzzzApplicationBundle:Default:index.html.twig'
);
}
}
namespace Inanzzz\ApplicationBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Translation\TranslatorInterface;
/**
* @Route("/translator", service="inanzzz_application.controller.translator")
*/
class TranslatorController
{
private $templating;
private $translator;
public function __construct(
EngineInterface $templating,
TranslatorInterface $translator
) {
$this->templating = $templating;
$this->translator = $translator;
}
/**
* @Method({"GET"})
* @Route("/")
*
* @return Response
*/
public function indexAction()
{
return $this->templating->renderResponse(
'InanzzzApplicationBundle:Translator:index.html.twig',
[
'page_header' => $this->translator->trans('page.translator.header'),
'user_greeting' => $this->translator->trans(
'user.greeting',
[
'%name%' => 'Inanzzz',
'%surname%' => 'Zzznani',
]
)
]
);
}
}
services:
inanzzz_application.controller.default:
class: Inanzzz\ApplicationBundle\Controller\DefaultController
arguments:
- '@templating'
inanzzz_application.controller.translator:
class: Inanzzz\ApplicationBundle\Controller\TranslatorController
arguments:
- '@templating'
- '@translator'
#src/Inanzzz/ApplicationBundle/Resources/views/Default/index.html.twig
{% extends '::base.html.twig' %}
{% block body %}
<h3>{{ 'application.greeting'|trans }}</h3>
{% endblock %}
#src/Inanzzz/ApplicationBundle/Resources/views/Translator/index.html.twig
{% extends '::base.html.twig' %}
{% block body %}
<h3>{{ page_header }}</h3>
<p>{{ user_greeting }}</p>
{% endblock %}
Eğer URL içinde en veya tr yoksa, uygulama 404 NotFoundHttpException hatası verecektir. Bu gibi durumlarda event listener devreye girip, aşağıdaki işlemleri yapacaktır.
NotFoundHttpException hatasını yakalar.en ve tr parametrelerinin eksik olup olmadığını kontrol eder.en veya tr) onu kullanır, değilse uygulamanın varsayılan dilini (en) kullanır.en veya tr) parçalanan URL'nin başına ekler.Eğer URL içinde en veya tr varsa ve de uygulama 404 NotFoundHttpException hatası veriyorsa, event listener hiçbir şey olmamış gibi davranır çünkü, kullanıcı mevcut olmayan bir sayfaya ulaşmak istiyor demektir ki bu da normal birşeydir.
namespace Inanzzz\ApplicationBundle\EventListener;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\HttpKernelInterface;
class LocaleRedirectListener
{
private $validLocales;
public function __construct($validLocales)
{
$this->validLocales = explode('|', $validLocales);
}
public function onKernelException(GetResponseForExceptionEvent $event)
{
// 1
if (!$event->getException() instanceof NotFoundHttpException) {
return;
}
// 2
if ($event->getRequestType() != HttpKernelInterface::MASTER_REQUEST) {
return;
}
// 3
$request = $event->getRequest();
$uriParts = explode('/', $request->getPathInfo());
// 4
if ($this->isLocaleMissing($uriParts)) {
// 5
$response = new RedirectResponse($this->constructRedirectUri($request));
// 6
$event->setResponse($response);
}
}
private function isLocaleMissing(array $uriParts)
{
return !isset($uriParts[1]) || !$uriParts[1] || !in_array($uriParts[1], $this->validLocales);
}
private function constructRedirectUri(Request $request)
{
// 5.1
$browserLanguage = $request->getPreferredLanguage($this->validLocales);
// 5.2
$locale = in_array($browserLanguage, $this->validLocales)
? $browserLanguage
: $request->getDefaultLocale();
// 5.3
$find = str_replace('/', '\/', $request->getPathInfo());
// 5.4
return preg_replace(
'/'.$find.'$/',
'/'.$locale.'/'.trim($request->getPathInfo(), '/'),
$request->getUri()
);
}
}
services:
inanzzz_application.listener.locale_redirect:
class: Inanzzz\ApplicationBundle\EventListener\LocaleRedirectListener
arguments:
- "%valid_locales%"
tags:
- { name: kernel.event_listener, event: kernel.exception, method: onKernelException }