Poste par Cedric Sadai, le 14/07/08 - Technologie

One of the recurring concern when developing an internationalized application, is to not let any element untranslated. This is natively complicated, even with the brand new symfony 1.1. You often end up with untranslated URLs or meta tags. But using the Framework in conjonction with the Yahoo!’s plugin ysfDimensionsPlugin will fill all the blanks you could have experienced once.

The role of the plugin is to let you define specific dimensions (can be cultures, can be themes, etc.), and to make it possible to override any part of your application (actions, templates, config) by simply adding a subdirectory, with the name of your dimension.

Let’s have a quick exemple.

First of all, you will have to link your existing project to the plugin SVN.

svn propedit svn:externals plugins/

Then append to the file:

ysfDimensionsPlugin http://svn.symfony-project.com/plugins/ysfDimensionsPlugin/branches/1.1/

Update everything:

svn up

Configuration

Let’s say we want to internationalize the application in english and french. That means we will add a “culture” dimension with two possibilities in it: en, and fr. To do that, create a /config/dimensions.yml file and write:

allowed:
  culture: [en, fr]

Now, we have to edit the main configuration script, so the plugin can add our brand new configuration levels.

require_once '/path/to/your/project/lib/vendor/symfony/lib/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();

require_once '/path/to/your/project/plugins/ysfDimensionsPlugin/lib/config/ysfProjectConfiguration.class.php';

class ProjectConfiguration extends ysfProjectConfiguration
{
	public function setup()
	{
	}
}

Notice that the ProjectConfiguration class now extends ysfProjectConfiguration (against sfProjectConfiguration, the y stands for yahoo!).

The dimension will be set up on an application level. In my example, the user culture is determined by the domain he is browsing. French will be something like fr.mydomain.com, and his culture will be set to english otherwise. To industrialize this behaviour, we have to edit our application configuration file.

Edit /apps/YOURAPP/config/yourAppConfiguration.class.php. First, manually require the plugin library.

require_once(dirname(__FILE__).'/../../../plugins/ysfDimensionsPlugin/lib/config/ysfApplicationConfiguration.class.php');

Then, make your class extend the Yahoo! Application configuration class, instead of the core symfony one.

class frontConfiguration extends ysfApplicationConfiguration // instead of sfApplicationConfiguration

Ok. Now, let’s define the dimension, in the configure method.

public function configure()
{
    //-- hacky. Demonstration purpose only.
	$host_part = explode('.', $_SERVER['HTTP_HOST']);
	$culture = (
		strLen($host_part[0])==2 &&
		(in_array($host_part[0], array('fr', 'en')))
	)?$host_part[0]:'en';

	$this->setDimension(array('culture' => $culture));
	parent::configure();
}

Note: this should go with an appropriate filter, like the one used here in symfonians.

Cool, we’re almost done. If you have an APC extension up and running on your environment, you can pretty safely trigger a symfony cc command. If everything goes as usual, try to browse your app, and if you nothing weird happens, you’re good to go.

If you don’t have APC, you have good chance it won’t work. Indeed, the plugin natively caches the configuration directories in the memory, using the PHP6 core library APC (you can grab it with “pecl install apc”).

If you can’t make it work, this is your last hope: override the main construction call, to make use of local cache or, if in debug mode, no cache at all (bad for production of course).

There you go:

class frontConfiguration extends ysfApplicationConfiguration
{
	public function configure()
	{
		$this->debug = true;

		//-- Hacky. Demonstration purpose only.
		$host_part = explode('.', $_SERVER['HTTP_HOST']);
		$culture = (
			strLen($host_part[0])==2 &&
			(in_array($host_part[0], array('fr', 'en')))
		)?$host_part[0]:'en';

		// setup dimensions before calling parent::configure();
		$this->dimension = new ysfConfigDimension(
			$this->getEventDispatcher(),
			(!isset($this->debug) || (isset($this->debug) && $this->debug === true))
			? new sfNoCache() :
			new sfCache(
				array(
					'prefix' => 'symfony.dimensions.config.default:'.$this->application.':'.$this->environment,
					'automatic_cleaning_factor' => 0, 'lifetime' => 86400)
			)
		);

		$this->setDimension(array('culture' => $culture));
		parent::configure();
	}
}

I had to force the $this->debug = true; because I had mysterious bugs on my development machine (Mac OSX). Try to remove it, if it works without that, it’s even better.

Now, let’s trigger a clear cache (symfony cc) and hit a fresh browser pointing to your application. Everything works as expected? Congrats, now we can go to the fun part.

Internalization with sfDimensionPlugin

In a big scale project, you generally have four types of I18N:

  • Stored data (work of ORMs to make this easy)
  • Localized short strings (handled natively by the symfony I18n support, enhanced in 1.1 with symfony i18n:extract –auto-save)
  • Configuration data (routing, meta tags, etc.)
  • And the last, often neglicted but rarely optional: long static (graphical) pages that are not made to be integrated in the DB or in the XLIFF file (about us, credit, contacts). They have to stay HTML fragments.

 

symfony natively supports nb 1 (thanks to Doctrine or Propel), nb 2, and that’s pretty much it. Let’s go back to our little project. You’re working hard on it, and the whole project is almost done. You have written pretty short SEO-friendly URL in /apps/YOUR_APP/config/routing.yml, and nice metas in your /apps/YOUR_APP/modules/YOUR_MOD/config/view.yml. Last, but not least, you decided to put all the static content in a “static” module, where you have empty actions and 5 to 10 HTML fragments.

Let’s internationalize everything:

routing.yml
homepage:
  url: /
  param: { module: home, action: index }

team:
  url: /team
  param: { module: team, action: index }

about_us:
  url: /about-us
  param: { module: static, action: about }

Obviously, we don’t need to translate the first routing rule (@homepage). So let’s create a routing.yml file in /apps/YOUR_APP/config/fr/routing.yml. (create the fr directory if it doesn’t exist yet).

team:
  url: /equipe

about_us:
  url: /a-propos

And that’s it! The plugin is smart enough to automatically inherit your main routing file, and as we gave them the same names, you can restrict your work to defining only the elements that change.

Now, try to go to http://fr.yoursite.dev, and hover a link to @team. It should show the french version now. Now point to the @about_us page. The URL is in french, but the content is in english, right? Remember, it’s a static page we created in a dedicated module. Let’s correct that:

Create a fr directory in

/apps/YOUR_APP/modules/static/templates

Now, copy the aboutSuccess.php template in that directory, and translate all its content. When it’s done, refresh your page. And boom, you should now have the french version.

 

This process can be done for almost anything in your website. It’s especially useful for metas. Just create a fr directory in /apps/YOUR_APP/modules/YOUR_MOD/config/fr/, and a view.yml file in it, and enjoy:

indexSuccess:
  metas:
    title: My French Title
[etc..]

When you’ve done that work once, you can reproduce a fully I18n environnement very quickly for your new project. Don’t forget that this ysfDimensionsPlugin is very powerful, and can be the perfect solution when you need to build many websites using the same engine (like a white label).

If you have any tip with I18N or ysfDimensionsPlugin, feel free to leave a comment.

A lire aussi:

Commentaires

Thanks for the tutorial. Clearly explained. Will surely help here.

James

Posted by james on 14/07/08

Quite nice ! But maybe a bit heavy

About i18n & Urls, there is another way to handle them that is quite nice too (with symfony 1.0).

It is a plugin I found on the web, named csI18nRoutingPlugin . I found it here :
http://prototyp.ical.ly/index.php/2007/08/29/routing-international-urls-in-symfony/

However, it had many bugs, and lacked some essential functionnalities.

So I extended it for a project of mine, and now it works fine : Plagiasi (http://sourceforge.net/projects/plagiasi)

Here is the url in the svn :

https://plagiasi.svn.sourceforge.net/svnroot/plagiasi/tags/v1.0/plugins/csI18nRoutingPlugin-0.1.0-extended/

Then, you just need to configure urls this way :

team:
url:
en: /team/:id
fr: /equipe/:id
param: { module: team, action: index }

It automatically converts links to the right culture. You can easily create a link that will load the same page with another language (dynamic flag links !). Here is an example :

https://plagiasi.svn.sourceforge.net/svnroot/plagiasi/tags/v1.0/apps/plagiasi/templates/layout.php

(line 24)

$uri = csI18nRouting::getInstance()->getCurrentOriginalInternalUri(true);

|

What do you think of this simple alternative ?

Posted by Piwaï on 14/07/08

Arrgg, still some problems with the comments. It would be nice if we could edit it, or pre render the comments.

Here is an exemple of the routing config file :

https://plagiasi.svn.sourceforge.net/svnroot/plagiasi/tags/v1.0/apps/plagiasi/config/routing.yml

Posted by Piwaï on 14/07/08

coucou

Félicitation pour votre article. Tres instructif.

Claude

Posted by claude on 14/07/08

tours en Arequipa ,sudamerica,climbing misti,chachani,copopuna,mismi,ampato,montain bike ,rafting,horse riding,down hill misti chachani,y en el colca ,puno,lima,nazca,pisco,peru bolivia y chile,tour en la selva,camino inca 4 dias y 2 dias,choquerirao,salkantaya.tour de aventura y convecional,rutas nuevas lima cusco 20 dias,el entanto del peru,peru trekking 24 dias,maravilla del peru,toro muerto, laguna de salinas,trekking a sogay,campiña de caballos,cotahuasi trekking,trekking al colca 4 dias fure,trekking a llahuar 3 dias ,down hill campiña,valle de los volcanes.Expedicion al mismi.

Posted by jesus on 14/07/08

Arequipa tours, South America, climbing misti, Chachani, copopuna, Mismi, Ampato, mountain biking, rafting, horse riding, down hill misti Chachani, and the Colca, Puno, Lima, Nazca, Pisco, Peru, Bolivia and Chile, tour jungle, inca trail 4 days and 2 days, choquerirao, salkantaya.tour adventure convecional, new routes lima cusco 20 days of the entanto peru, trekking peru 24 days, wonder of peru, bull died, saline lagoon, trekking to sogay, horse riding Cotahuasi trekking, trekking colca Fure 4 days, 3 days trekking llahuar, down hill countryside, valley of the volcanoes

Posted by jesus on 14/07/08

tours in Arequipa, sudamerica,climbing misti,chachani,copopuna,mismi,ampato,montain bike, rafting,horse riding,down hill misti chachani,y nel colca, puno,lima,nazca,pisco,peru bolivia e chile,tour nella selva,camino inca 4 giorni e 2 dias,choquerirao,salkantaya.tour di avventura e convecional,rutas nuovi lima cusco 20 giorni, l’entanto del peru,peru trekking 24 dias,maravilla del peru,toro morto, laguna di salinas,trekking a sogay,campiña di caballos,cotahuasi trekking,trekking al colca 4 giorni fure,trekking a llahuar 3 giorni, down hill campiña,valle dei vulcani.

Posted by jesus on 14/07/08

tours dans Arequipa, sudamerica, climbing misti, chachani, copopuna, mismi, ampato, montain bike, rafting, horse riding, down hill misti chachani, et dans le colca, un poing(poignée), lime, naît, pisco, peru bolivia et chile, tour dans la forêt, le chemin inca 4 jours et 2 jours, choquerirao, salkantaya.tour d’une aventure et convecional, de nouvelles routes il(elle) lime cusco 20 jours, l’entanto du peru, peru trekking 24 jours, surprend du peru, le taureau mort, lagune de mines de sel, trekking à sogay, un champ de chevaux, cotahuasi trekking, trekking au colca 4 jours fure, trekking à llahuar 3 jours, down hill un champ, une vallée des volcans.

Posted by jesus on 14/07/08

These kind of post are always inspiring and I prefer to read quality content so I happy to find many good point here in the post.

Posted by cheap air max shop on 14/07/08

I just read through the full article of yours and it was quite good. nice information!First place in google results&Thank you.

Posted by Louis Vuitton bags oulet on 14/07/08

This article gives the light in which we can observe the reality. this is very nice one and gives indepth information. thanks for this nice article.Prada handbags outlet

Posted by Prada handbags outlet on 14/07/08

Posted by joseph on 14/07/08

I want to make a withdrawal kid cartoons nude ham

Posted by Aypdhmdi on 14/07/08

How much notice do you have to give? russian preteen
grt

Posted by Zlvrmuxn on 14/07/08

Could I order a new chequebook, please? nymphet toplist
>:]

Posted by Jfdppque on 14/07/08

Its a great start of the day with a website like this. very informative , im now one of the regular visitor of your web. Thanks.

Posted by Air Max store on 14/07/08

I came here to study Preteen
3735

Posted by Vbbbdfph on 14/07/08

[...] aqui:http://www.sadai.net/full-i18n-with-ysfdimensionsplugin This entry was posted in Symfony, Uncategorized. Bookmark the permalink. ← Função de [...]

Could I make an appointment to see ? Pakistani Sex Model
=[

Posted by Nlkkbuoy on 14/07/08

Very Good Site Preeteen Kids Models
627340

Posted by Netiylfn on 14/07/08

Some First Class stamps preteen boy bath 8-D

Posted by Qdophpir on 14/07/08

I’d like to transfer some money to this account candid preteens videos %-[[

Posted by Pvbrubsv on 14/07/08

I support Manchester United pedo sex stories
qwu

Posted by Xrnjniqi on 14/07/08

Some First Class stamps cute mom boobs :( (

Posted by Ihloxjcd on 14/07/08

I’d like to cancel this standing order bikini busty lesbian >:PP

Posted by Lmzdpdmw on 14/07/08

Children with disabilities free lolitas kids bbs 8545

Posted by Puaqmnfz on 14/07/08

I’m not interested in football lolita russian nude free 8-DDD

Posted by Zzwbhmww on 14/07/08

Im having problems with your header image in Firefox

http://articles.adswork.com/index.php?page=article&article_id=74533

Posted by Thomas on 14/07/08

Ajouter un commentaire