Re: [Catalyst] Multi-language and REST
Haven't been looking in here for a while, just saw this thread. I have a multilingual app at http://www.engoi.com which uses Chained to do this. It works really well, and makes Do Not Repeat Yourself quite easy to achieve. In fact, for many actions, *two* languages are selected - the native and target language of the user. You can see the way this maps to URI's easily enough by looking around. Browser detection happens if you go to the domain root, and redirects you straight to the home page in your language. It's pretty simple. BTW don't let the fact that many pages are actually served static fool you. All content is developed in Catalyst, I use a script to generate html pages for stuff which is not actually dynamic in behaviour, and some shennaigans with URL's and server config to make it all work together. Cat is very powerful and flexible and lets you do things many, many ways. Daniel ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
I think other cases show it is not only an i18n issue. In a business listings site I made I have x.com/dir/CityName/Business_Services/Advertising for example. The top level category Business_Services is optional as the secondary level category name is unique. The CityName could be any city in the state, or All_Cities. No city means All_Cities. If there is a city but no topic, it shows table of contents for that city only. A top level topic but no secondary level topic, it shows a blog on that topic. As Bill Moseley does, after the dir (which is Dir.pm) I check if there is a valid city. I also made some experimental tags to modify behavior. So you could add /show_all_cities at the end and it would do that regardless of the city. (decided not to use that). Also was going to add a /tags:(x,y,z,w) style supplement to be able to submit a set of unordered tags but this also proved overkill. However when doing faceted metadata search the order really isn't important and so order in the url sholdn't be either I think. This suggests to me that it would be useful to create a general url windowing module that lets you specify (and validate urls to) an url format in which certain segments of it may be structured differently. By window I mean it lets you look at and define segments of urls. It could pick up collisions between adjacent keywords too. Could also pad missing virtual folder names (like setting All_Cities if not present). I guess you'd define subs for each window spec. The definition would see x.com/dir/[CITYSPEC]/[MAJORSPEC]]/[MINORSPEC] It need not be complicated as the purpose is human readability. I know Accept-Language is good REST but it is less intuitive and personally I detest being forced to read a Japanese page for a website that has perfectly good English on it. It might be useful if you could define a certain format, like -MMDD for a publication date, for a certain spec. Then it would be easy to pick up on whether it is present or not and you could easily handle x.com/Jones/2008-0428 as well as x.com/Fiction/Jones and even x.com/Jones/EarlyWorks (if you allow the date spec to include EarlyWorks, defined as within 10 years of the first PubDate on record). Anyway the fr/en switch is a small subset of this functionality which is otherwise very useful for helping users (and hopefully Google) intuitively navigate orthogonal metadata (think Author, PubDate, Topic) or data organized into hierarchies with crosslinks, like a Yahoo style topic hierarchy. I suppose this is too long a post but it would benefit all catalyst sites if created. I suppose UrlFu or the like. ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
From: Matt Rosin [EMAIL PROTECTED] FWIW after all that such a module should allow keys stored in cookies to supplement/overwrite the url. So instead of prepending lang code, I could keep the same url but have a javascript language button set the language. I think that the pages with different content (in different languages) should have a unique URL (for allowing the search engines to index all the pages). I first made an application in a single language then I needed to make it multilanguage, and the most easy way I found was to add the language ID in the query string, like: ?lang=FR. The app uses Catalyst::Plugin::I18N. If the request doesn't contain any lang variable and any lang cookie, it gets the languages prefered by the browser and displays the page in the most apropriate language. If the request contains the lang cookie, the app displays the pages using that language. If the request contains the lang variable, it also displays the page using that language. The links which should be used for changing the language send a lang variable, and a cook variable. When the app receives both of these variables, it displays the site in the specified language, and it also sets a cookie with that language, and the next time the visitor will visit the site, he will see the page displayed in the previously chosen language. This won't happen if this wasn't his choice, but only a browser preference. For doing this I use the code I put below. I put it in the Root.pm, in the auto subroutine, so it is executed for all the other controllers and it sets the lang var in the stash for using it later in those controllers if needed (for sending emails in the chosen language, for example). Of course, after doing this, I also needed to modify some templates and controllers in which I hard-coded URLs because I needed to insert lang=[% lang %]. HTH Octavian Here is the code I use: my $lang = $c-req-param('lang'); my $cook = $c-req-param('cook'); if ($lang and $cook) { #set cookie $c-res-cookies-{lang} = {value = $lang, domain = $c-config-{cookie_domain}, path = '/', expires = '+1y'}; $c-languages([$lang]); } elsif ($lang) { $c-languages([$lang]); } elsif ($c-req-cookies-{lang}) { $lang = $c-req-cookies-{lang}-value; $c-languages([$lang]); } else { #read the browser prefered languages my @accept_language = split /,/, $c-req-header('Accept-Language'); my @langs; foreach(@accept_language) { s/;.*$//; s/-.*$//; push (@langs, $_); } $c-languages([EMAIL PROTECTED]); $lang = $c-language; #the chosen language } $c-stash-{lang} = $lang; ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
[Catalyst] Multi-language and REST
I have been pondering how to take an existing Catalyst application and make it multi-lingual. I would prefer to use a RESTful method, so this would translate /foo/bar to /en/foo/bar or /fr/foo/bar (for English and French respectively). The problem as I see it is how to do this. I don't want to move all my controllers, e.g. MyApp::Controller::Foo::Bar to MyApp::Controller::Lang::Foo::Bar What other alternatives are there? Regards Ian ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
On Friday 25 April 2008 14:44:38 Ian Docherty wrote: I have been pondering how to take an existing Catalyst application and make it multi-lingual. I would prefer to use a RESTful method, so this would translate /foo/bar to /en/foo/bar or /fr/foo/bar (for English and French respectively). The elegang solution is to make use of the request header Accept-Language, but not many users know how to change this setting in their browsers. http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z12 The problem as I see it is how to do this. I don't want to move all my controllers, e.g. MyApp::Controller::Foo::Bar to MyApp::Controller::Lang::Foo::Bar What other alternatives are there? Regards Ian ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/ -- Knut-Olav Hoven Systemutvikler mob: +47 986 71 700 Linpro AShttp://www.linpro.no/ signature.asc Description: This is a digitally signed message part. ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
Ian Docherty wrote: I have been pondering how to take an existing Catalyst application and make it multi-lingual. I would prefer to use a RESTful method, so this would translate /foo/bar to /en/foo/bar or /fr/foo/bar (for English and French respectively). The problem as I see it is how to do this. I don't want to move all my controllers, e.g. MyApp::Controller::Foo::Bar to MyApp::Controller::Lang::Foo::Bar What other alternatives are there? Regards Ian Well, I'm sure there's a somewhat elegant way to do this with Chained, but it the other controllers don't use Chained now, that could get fun. The brute force way is to inspect the request and rip out the language portion before sending it on to get dispatched...just like the Flavour plugin does with file extensions: sub prepare_path {} signature.asc Description: OpenPGP digital signature ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
On Fri, Apr 25, 2008 at 01:44:38PM +0100, Ian Docherty wrote: I have been pondering how to take an existing Catalyst application and make it multi-lingual. I would prefer to use a RESTful method, so this would translate /foo/bar to /en/foo/bar or /fr/foo/bar (for English and French respectively). The problem as I see it is how to do this. I don't want to move all my controllers, e.g. MyApp::Controller::Foo::Bar to MyApp::Controller::Lang::Foo::Bar I check if the prefix is a valid language (if it's one of the language files I loaded at startup), if so I then remove it from the request path and append it to the request base. -- Bill Moseley [EMAIL PROTECTED] ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
Christopher H. Laco wrote: Ian Docherty wrote: I have been pondering how to take an existing Catalyst application and make it multi-lingual. I would prefer to use a RESTful method, so this would translate /foo/bar to /en/foo/bar or /fr/foo/bar (for English and French respectively). The problem as I see it is how to do this. I don't want to move all my controllers, e.g. MyApp::Controller::Foo::Bar to MyApp::Controller::Lang::Foo::Bar What other alternatives are there? Regards Ian Well, I'm sure there's a somewhat elegant way to do this with Chained, but it the other controllers don't use Chained now, that could get fun. I have considered chained, and would be prepared to re-write the existing controllers. A bigger decision would be renaming the controllers or moving them. e.g. existing MyApp::Controller::Foo::Bar maps to URI /foo/bar To match against /lang/foo/bar either I can leave the controller where it is (lib/MyApp/Controller/Foo/Bar.pm) or move it (lib/MyApp/Controller/Lang/Foo/Bar) The first approach is less work (only using chained) the second is more work, but maps the URI namespace more logically to the Class names. What would people do if they were writing a Catalyst App from scratch with this feature? That would tell me what the 'best practice' is even if it means a big re-write exercise. The brute force way is to inspect the request and rip out the language portion before sending it on to get dispatched...just like the Flavour plugin does with file extensions: sub prepare_path {} One of my pet peeves is exemplified in the 'Flavour' plugin. It is such minimal documentation that it neither tells you what it does or why it does it. OK, I can look at the code, but it is too much effort unless I think I have a good reason to do so. I assume in this case that it is something to do with date strings in the URI (for blogging?). I can't be ar**d! ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
On Fri, 25 Apr 2008, Ian Docherty wrote: http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z12 Yes, I have done this previously, it is elegant, but not RESTful and does not make it easy for users to change their settings on a site-by-site basis dynamically, as you could if you provided a language selection box on each page. Why do you say it's not RESTful? I think it's very RESTful, but it depends on how you think about it. If the language of the content is basically an issue of formatting, then switching language based on a header is perfect. The client provides sufficient information to produce a correct response _on each request_ as part of HTTP. This is basically the essence of REST. OTOH, if you consider each language's content fundamentally separate things, then each language should have its own set of URIs. -dave /*== VegGuide.Org Your guide to all that's veg ==*/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
Dave Rolsky wrote: On Fri, 25 Apr 2008, Ian Docherty wrote: http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z12 Yes, I have done this previously, it is elegant, but not RESTful and does not make it easy for users to change their settings on a site-by-site basis dynamically, as you could if you provided a language selection box on each page. Why do you say it's not RESTful? I think it's very RESTful, but it depends on how you think about it. If the language of the content is basically an issue of formatting, then switching language based on a header is perfect. The client provides sufficient information to produce a correct response _on each request_ as part of HTTP. This is basically the essence of REST. OTOH, if you consider each language's content fundamentally separate things, then each language should have its own set of URIs. Yes, this is exactly what I had in mind. I did not (and still don't) consider the language of the content as 'formatting', the content for each language is different (in my mind). I don't really want this to start another flame-war about RESTful etc. this point is outside of my original request so I won't respond (on list) to this off-topic subject any more. Regards Ian ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
Dave Rolsky wrote: On Fri, 25 Apr 2008, Ashley wrote: I agree that it's content, not formatting. If CSS/client-side-JS can (in a practical fashion) change it, it's formatting, otherwise, it's content. I should have used the word representation. With REST, you'd have the same URI for one resource, but you might offer it as HTML, JSON, and plain text based on what the client requests. Given the Accept-Language header, you could do the same thing with language. -dave Could and should. I've taken the approach using the REST controller that if anyone wants to get at a resource easier (easier to alter the uri than the headers), then use the content-type query param. I think the same should be true for language. If changing Accept-Language is too much, (or people want to view a language other than their native), then look at language= in the query params first..if it's empty...honor Accept-Language... rather than forcing /lang/ at the front of all urls. signature.asc Description: OpenPGP digital signature ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
On Apr 25, 2008, at 10:28 AM, Christopher H. Laco wrote: If changing Accept-Language is too much, (or people want to view a language other than their native), then look at language= in the query params first..if it's empty...honor Accept-Language... rather than forcing /lang/ at the front of all urls. I like the idea (and you could even cookie language prefs instead of a query string solution which would be more expensive/complex with the URI rewrites) but giving up a large chunk of one's search engine results for a more purist interface is a pretty high price. As of last year (haven't checked recently) the googlebot couldn't even correctly index pages served as application/xhtml. Some bots might do the right thing with headers for their target language base(s) but I doubt it's many, if even a minority, of them yet. It's not a transport issue (like HTML/PDF/JSON/XML/etc) which makes perfect sense for header control because the clients and client-side stuff is being written now in tandem, it's different content and the target clients are laden with legacy behavior. I like PUT and DELETE too but I'm not going to abandon POST as their stand-in (or fall- back) any time soon. ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Multi-language and REST
Christopher H. Laco wrote: Ian Docherty wrote: Christopher H. Laco wrote: Ian Docherty wrote: I have been pondering how to take an existing Catalyst application and make it multi-lingual. I would prefer to use a RESTful method, so this would translate /foo/bar to /en/foo/bar or /fr/foo/bar (for English and French respectively). The problem as I see it is how to do this. I don't want to move all my controllers, e.g. MyApp::Controller::Foo::Bar to MyApp::Controller::Lang::Foo::Bar What other alternatives are there? Regards Ian Well, I'm sure there's a somewhat elegant way to do this with Chained, but it the other controllers don't use Chained now, that could get fun. I have considered chained, and would be prepared to re-write the existing controllers. A bigger decision would be renaming the controllers or moving them. e.g. existing MyApp::Controller::Foo::Bar maps to URI /foo/bar To match against /lang/foo/bar either I can leave the controller where it is (lib/MyApp/Controller/Foo/Bar.pm) or move it (lib/MyApp/Controller/Lang/Foo/Bar) The first approach is less work (only using chained) the second is more work, but maps the URI namespace more logically to the Class names. What would people do if they were writing a Catalyst App from scratch with this feature? That would tell me what the 'best practice' is even if it means a big re-write exercise. The brute force way is to inspect the request and rip out the language portion before sending it on to get dispatched...just like the Flavour plugin does with file extensions: sub prepare_path {} One of my pet peeves is exemplified in the 'Flavour' plugin. It is such minimal documentation that it neither tells you what it does or why it does it. OK, I can look at the code, but it is too much effort unless I think I have a good reason to do so. I assume in this case that it is something to do with date strings in the URI (for blogging?). I can't be ar**d! It does just what just what Bill suggested. I check if the prefix is a valid language (if it's one of the language files I loaded at startup), if so I then remove it from the request path and append it to the request base. In prepare_path.. you inspect the requested path.. yank out the language.. then pass along the remaining path...which should map to your existing controllers just fine. I have actually taken a look at the Flavour plugin (can't see for the life of me why it is called that!) and it gives an example of yanking off the //mm/dd at the start of a path, putting the values into accessors of flavour (e.g. $c-flavour-year) leaving the rest of the path to be processed as normal. This is pretty much what I want to do for the language so thanks for pointing out the plugin to me. I am pretty confident that I can now write a plugin to strip out a language from the start of a path in the same way. Looking at the Catalyst best practices, am I going to be polluting the catalyst namespace by writing this as a plugin? I can't see any alternative (making it a base Controller is actually what I am trying to avoid). Any suggestions as to a namespace for this? Catalyst::Plugin::LangURI perhaps? As far as chained goes... I thought there was an example floating around that has Root::lang as Chained, then all other modules Chaine against /lang as their root instead of /... I should not need this if I do the above then I can leave my existing controllers unchanged (and unchained). -=Chris ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/