[Seaside-dev] Seaside vs I18N/L10N vs VW

Philippe Marschall philippe.marschall at gmail.com
Wed Oct 10 05:32:51 UTC 2007


2007/10/10, Martin Kobetic <mkobetic at cincom.com>:
> I'd like to provide an update on how we're doing with regards to I18N in VW and bring up few issues that we feel should be discussed in the wider Seaside developer community.
>
> Let me first briefly recap the situation in VW as it is shipping right now and then move towards Seaside from there. The standard mechanism for I18N in VW are UserMessages. Instead of hardcoding a string, e.g. 'Blah', you build an instance of UserMessage as follows:
>
>         #MessageID << #CatalogID >> 'Blah'.
>
> When the UserMessage gets converted to String at any point it will get resolved against current Locale and associated message catalogs. This happens transparently, there isn't any explicit call along the lines of:
>
>         self session translate: 'Blah'.
>
> The problem that we needed to solve for Seaside was that previously 'current Locale' meant only current global, image wide, Locale. For Seaside we needed something more granular, something that can mesh with Seaside session granularity.
>
> A fairly natural refinement of the Locale model described above is what we call per-process Locale. In this model any process can have its own Locale set on it which will override the global one. Anything relying on 'Locale current' should work the same as before and still get the per-process diversity for free. Since with Seaside there's a new process created for each incoming request, there's no danger of single process having to deal with multiple sessions. So per-process Locale should be plenty granular enough to support per-session Locale in Seaside. And that's what we did, you can manage locale on a Process using #locale(:) messages. And the rest should just work as expected in VW.
>
> Now, let's go back to the more Seaside relevant bits. For now we've created WALocalizedSession which maintains its #locale. Currently #locale is just a Symbol like #en_US, #ru_RU, etc. A WAComponent can access that via 'self session'. Before executing a WARequest we fetch the corresponding session, check if it has locale associated with it and if so we use it to set the corresponding Locale on the process executing the request. After that all UserMessages should reflect the process locale. Our simple localized test component looks like this

It wasn't clear to me from the post of mls that actually made
WALocalizedSession. I interpreted his post more in the way you worked
on extensions to WASession.

> renderContentOn: html
>
>         html form: [ | session |
>                 session := self session.
>                 html select
>                         list: session availableLocales;
>                         selected: session locale;
>                         callback: [ :value | session locale: value ].
>                 html submitButton text: 'Set Locale'.
>                 html text: #HelloWorld << #L10NTest >> 'Hello World!';
>                         text: Locale current languageID ]
>
> If you have #L10NTest catalogs for multiple Locales and they include #HelloWorld message, you should see the String change as you change the locale.
>
> To make this work we had to make 2 changes in Seaside realm.
>
> 1) We need access to a request's session before we hand control over to Seaside to execute it. For that we added #sessionForRequest: as follows:
>
> WARequestHandler>>sessionForRequest: aRequest
>
>         ^nil
>
> WADispatcher>>sessionForRequest: aRequest
>
>         ^(self handlerForRequest: aRequest) sessionForRequest: aRequest
>
> WARegistry>>sessionForRequest: aRequest
>
>         | key keyString |
>         "Under some circumstances, HTTP fields are collections of values"
>         key :=  [keyString := aRequest at: self handlerField.
>                         (keyString isKindOf: OrderedCollection) ifTrue: [keyString := keyString first].
>                         WAExternalID fromString: keyString] on: Error do: [:e | nil].
>         ^handlersByKey at: key ifAbsent: [nil].
>
> Some will probably notice that the WARegistry one is a clean extract from WARegistry>>handleKeyRequest:. So the first question is: Would this sort of refactoring and addition of something like #sessionForRequest: be an acceptable change to Seaside ?
>
> In general I'd be inclined to consider factoring the session lookup out of handleRequest: altogether, to avoid traversing the Dispatcher tree twice (potentially with different results if something goes really wrong). But that's outside the scope of this particular topic. But I'm game if there's any interest in that too.
>
> 2) Every request eventually goes through WAProcessMonitor>>critical:ifError:, which forks an additional process for request execution. Because of that we need to pass any process settings (like #locale) to the newly spawned process. Arguably it might make sense to modify #fork to pass these automatically, however that would be a backward incompatible change in VW (currently new process doesn't inherit the environment of the parent process). What I'd like to propose instead is replacing the call to #fork with a SeasidePlatformSupport call. That way we can put in any additional initializations as necessary. As it is we have to override WAProcessMonitor>>critical:ifError: directly. Is there any chance to agree on something like that ?

Do you really need to set the locale that early? Won't any later point
do as well?

> These are the more immediate issues we have on the VW integration front. There are of course the larger discussions where we have a lot of flexibility going forward:
>
> 1) What sort of i18n mechanism should Seaside support? Should there be one (Seaside specific?) mechanism used across dialects? Should we just make sure the existing dialect mechanisms work well with Seaside (The above seems to suffice for VW in that regard)? Or maybe both ?

In Squeak I'm only aware of NaturalLanguageTranslator which wouldn't
work for Seaside. For Gemstone I'm aware of nothing. So right now
everything we do here is VW specific unless someone wants to write or
donate code. This by the way would make an exceptional good candidate
for a module in Seaside 2.9.

> 2) How should locale be represented in Seaside session? The above scheme uses WALocalizedSession subclass with an inst var holding a Symbol. In previous discussions here we mentioned potentially adding a Locale object, which is fine too, however if we're after supporting dialect specific i18n methods then the Seaside Locale object will most likely get simply mapped to a platform specific Locale object pretty quickly. In which case it doesn't really provide much advantage over the Symbol. Any thoughts ?

We live by objects, we die by objects. Symbols are simply not objects.
See announcements for an analogy.

> 3) Subclassing Session. WALocalizedSession provides the possibility for a component to opt out of i18n support. However modeling this using session subclasses causes problems when you need to combine several different, optional features, e.g. WALocalizedSession vs WAGlorpSession (for persistence). We'd like to propose adding generic "resource" support to WASession allowing to attach arbitrary bits of information to sessions. It should be a bit more than plain "property dictionary" kind of thing. Some "resources" would probably find it useful if they were notified when the session expires, and there are probably other events that might be useful for other resource types. Any thoughts on this one ?

Again it would help if you have more users for this than VW. Like
Magma or Gemstone for example. And it's always simpler to talk about
actual code.

Cheers
Philippe

> That's how things look from VW side. I'd welcome any comments for other dialects.
>
> Thanks for reading this far,
>
> Martin
>
> _______________________________________________
> seaside-dev mailing list
> seaside-dev at lists.squeakfoundation.org
> http://lists.squeakfoundation.org/mailman/listinfo/seaside-dev
>


More information about the seaside-dev mailing list