[Catalyst] [Absolute Beginner] Navigation Q Part II i18n and URIs

Robert Sedlacek rs at 474.at
Fri Aug 20 22:46:14 GMT 2010

Hello Ekki,

On 08/20/2010 11:25 PM, Ekki Plicht (DF4OR) wrote:
> Two pre-requisites which I must fulfill in my webshop:
> 1.) I have to consider internationalisation (i18n) of my app. It has to serve 
> pages in 5 languages (today), probably more later. Language is depending on 
> browser header information or user choice.

Some things to consider:
· Should the user be able to override the language?
· Do you want to separate language by domain or URI part?

> 2.) I must have 'speaking' URIs for better SEO. I.e. URIs like 
> /cars/volkswagen/sedan instead of /products?manufacturer=23&prodid=42. In 
> German that URI would probably be /fahrzeuge/volkswagen/limousinen. Other 
> example:
> EN: /cars/rangerover/fourwheeldrive
> DE: /fahrzeuge/rangerover/allrad
> FR: /voitures/rangerover/tout-terrain
> (All examples are fictious.)

What would happen if someone who only accepts DE as language requests
the EN page? Browser language detection is pretty easy with the I18N
plugin, but the implementation of the language logic is dependent on
what you want to happen.

> Now, where does that leave me with the controller and dispatch actions? 
> One idea comes to mind which is to use n different controllers, one for each 
> language (Controller::Cars, Controller::Fahrzeuge, Controller::Voitures etc.). 
> In each controller the same list of actions is repeated (yuck!), each action 
> sub has it's counterpart in each other language.
> Currently we have 234 entries in our product selection tree (i.e. navigation 
> tree) grouped into 12 major categories and several subcategories, up to 5 
> levels deep.
> WTF? Maintain 5 (or more) navig trees plus write 5 (or more) more or less 
> idetical controllers (one for each language) with ~234 action subs each. No 
> way! That's a maintenance nightmare.
> That cannot be a viable solution... Where am I wrong in my thinking?

Both the language and the article to display are variables in the
process of displaying the page. The language can come from a cookie, the
browser language setting, a query parameter, the domain name, a part of
the URI, or multiple of those using the first it can find.

I'd always advise to build the actual business logic of the application
outside of the web front-end. You can test it easier, and you'll often
want to have access to it from outside anyway. Also, this keeps your
controller logic small and only concerned with the interaction of model
and view.

If you have a path segment like '/car/brand/model' or something you can
 basically imagine it as a (pseudo) model call like:

	$ctx->stash(page => $ctx->model('ModelName')->find(
	  lang => $ctx->stash->{language},
	  path => [@segments],

Which would be done in an action taking a variable number of arguments.
Then your error handling (malformed or unknown paths, etc.) can be
handled by your model as well. (Note: I omitted error handling in the
above for simplicity)

If you read your data from a database, a configuration file, or some
flat-file hierarchy mostly depends on your needs (or rather: the needs
of those who will maintain the content).

> What I am envisioning is a central file where I (somehow, XML?, database?) 
> maintain a navigation tree (ok, 5 or more), mapping menu entries to URIs. Some 
> process then maps these entries to actions. But how? 

As a model. Look at Config::Any (already used by Cat) for loading of
configuration files. For a database model I'd point you towards
DBIx::Class, but mostly because of community-size and personal
preference. There are other solutions, but I feel it is a good start.

Hooking the model into Catalyst is rather easy. You can take a look at
the Catalyst::Model::* namespace on CPAN to get a feel for what's
already there and what's possible.

Also, take a look at Moose. It's the OO system that Catalyst is built
on. You can reuse controller code just like any other code via
inheritance and role-composition. And as said above, you shouldn't need
that many actions in the first place. Code-repetition can usually be
avoided in Catalyst. If you want to separate different stages of the
request processing, Catalyst::DispatchType::Chained is a good way to do

> Other ideas coming to my mind:
> - Create actions on the fly, mapped from the Menu/URI table. Is this possible 
> with Catalyst? AFAIK Catalyst checks all controllers at startup and builds a 
> list of actions only once - at startup... right?

Right. If you want something to be dynamic, it's some kind of parameter
most of the time.

> - Have one controller per language and write a central dispatcher action, 
> which does nothing more than use the lookup table mapping menus to URIs? To me 
> this has not the right feel, giving up all the nice dispatcher possibilities 
> of Catalyst...

I usually let the Root controller have a base action that selects the
language (either from the URI or however it is required), and a separate
controller for content delivery that chains off the root's base and that
takes its arguments and looks up the content from wherever.

> - Put the navig tree in a separate view per language. Maintain n different 
> files when the tree changes. Still leaves me with the dispatcher issue.

The view should (in my opinion) not care about the content it renders,
only about its structure. There are exceptions, but they are rare.

> - Maintain the navig tree somehow (XML, SQL) and write a small script which 
> produces the Conntrollers and actions from the data (plus a navig view for 
> each language)?

No, I would definitely go the dynamic route.

> Maybe I am just blind to see a radically different solution to my problem... 
> any takers?

Basically I see no need to generate actions for each page at all, since
you can have one action that takes multiple arguments and uses them to
look up the content in the model. If you manage to design all of the
business logic outside of the application, the Catalyst code becomes
quite simple.

Robert 'phaylon' Sedlacek

Perl 5 Consultant for
Shadowcat Systems Limited - http://shadowcat.co.uk/

More information about the Catalyst mailing list