symfony l10n – going further

As you may know symfony offers localized objects out of the box. It gives you an easy way to have different data for different cultures.

Sometimes it is not enough. I needed two localized version of website but with completely different content – everything including users, admin and super admin. Both version were supposed to run under the same domain and to be distinguished just by locale part in the url. I was too lazy and didn’t want to copy applications or projects (moreover, it is a problem in the future, you’ll have to modify each copy). So, I decided to use different databases with exact schema for different cultures.

Here’s guide how to implement this.

First of all, I need to extract locale parameter from the url. That is easy, you’ll find it in the symfony docs.
Routes config (routing.yml):

action:
  url:   /:locale/:module/:action/*
  requirements: {locale: nl|be}

I needed only NL and BE locales.

Then, you need to setup two databases. I was using symfony 1.1 with doctrine, but it should be possible for 1.2 also and propel or whatever ORM you are convenient with. Doctrine is able to work with multiple connections. However, I don’t need multiple connections. I need them both defined but I need only one current connection for every request. So I’m defining two connections but not specifying any binding to connection in model schema.
Databases config (databases.yml):

all:
  belgium:
    class:          sfDoctrineDatabase
    param:
      dsn:          mysql://user_be:pass_be@host_be/db_be
  primary:
    class:          sfDoctrineDatabase
    param:
      dsn:          mysql://user_nl:pass_nl@host_nl/db_nl

If you check your application at this moment it will use connection last defined.

So, now I only need to switch between these connections. I can do it with filters.
filters.yml:

rendering: ~
security:  ~
l10n:
  class: l10nFilter
cache:     ~
common:    ~
execution: ~

And the filter itself:

class l10nFilter extends sfFilter 
{
  public function execute($filterChain) 
  {
    if ($this->isFirstCall())
    {
      $locale = $this->getContext()->getRequest()->getParameter('locale');
      //sanitize locale
      $this->getContext()->getUser()->setAttribute('locale', $locale);
      $connection = ($locale == 'be') ? 'belgium' : 'primary';
      Doctrine_Manager::getInstance()->setCurrentConnection($connection);
    }
 
    $filterChain->execute();
  }
}

That’s it.

The small issue is that if you are going to use symfony db tasks (e.g. migrations or data population) you’ll need to set additional environments:
databases.yml:

prod_be:
  primary:
    class:          sfDoctrineDatabase
    param:
      dsn:          mysql://user_be:pass_be@host_be/db_be
prod_nl:
  primary:
    class:          sfDoctrineDatabase
    param:
      dsn:          mysql://user_nl:pass_nl@host_nl/db_nl

And call your tasks twice for each pseudo-environment by adding –env=prod_be or –env=prod_nl.

Tags: , ,

AddThis Social Bookmark Button

One Response to “symfony l10n – going further”

  1. Symfony L10n | IT Blog Says:

    […] site, duas línguas, dois conteúdos separados. Easy: http://blog.o-x-t.com/2009/04/19/symfony-l10n-going-further This entry was posted in Symfony, Uncategorized. Bookmark the permalink. ← Solução […]

Leave a Reply