Marius Scurtescu wrote:
> First, let me clarify this
> [...]
> The second may take the bundle name from an attribute or an
> environment entry. The attribute name and scope and the
> environment entry name are hard coded values.
< [...]
> I was proposing to use something like:
> <i18n:localize bundle="com.wamnet.tools.jsptags.i18n-test"/>
> or
> <i18n:localize attr="org.apache.taglibs.i18n.LocalizeTag.bundle"/>
> or
> <i18n:localize env="org.apache.taglibs.i18n.LocalizeTag.bundle"/>
>
> This approach gives you two benefits:
> - it makes it clear where the bundle name comes from
> - you don't use hard coded values
ah, I see where you're going. though I'm not quite sure I agree, I'm open to
exploring the idea.
the reason I had hardcoded the environment entry (and later, the
application-scoped attribute) was that I considered it the equivalent of a
servlet init param. The reason the thing ended up so long was that I wanted
the fully qualified classname to make sure I didn't step on anyone else's
toes.
<sidebar>
The servlet init param is feature that IMHO should have an equivalent in the
taglib descriptor! OR, simply adding a <default> parameter to the taglib
would be good as well (Craig - are you listening? :-)
<attribute>
<name>bundle</name>
<default>com.wamnet.tools.jsptags.i18n-test</default>
</attribute>
</sidebar>
anyway, if you do servlet init params, the parameter names are hardcoded,
e.g.
<init-param>
<param-name>catalog</param-name>
<param-value>Spring</param-value>
</init-param>
while I agree that your approach makes it clearer where the bundle name
comes from, I wanted to provide a means for allowing an empty <localize/>
tag. if the attr or env need to be passed, then one might as well just type
in the actual name of the bundle to be used...
> Here is my understanding of the current architecture:
>
> The main tag in this library is the "message" tag. In order
> to provide you with a message it needs a bundle. This
> bundle is loaded by "localize" and stored in the "request"
> object using a hard coded name, this is where the "message"
> tag will look for it. The "localize" tag is also caching
> the bundle in the session using a hard coded prefix together
> with the bundle name as the attribute name.
>
> In order to load a bundle the "localize" tag has to figure
> two things: a bundle base name and a locale. The base name
> can be specified as an attribute or it is retrieved from
> either the "application" object or from the environment.
> The locale is take from the browser preferences.
agreed -- this is the current architecture, though I am planning to
implement your previous suggestion of allowing explicit setting of the
locale on a per-session basis.
> I can see two limitations to this architecture:
> - there is only one way to specify the locale (I addressed
> this already in #2 above)
agreed. though my initial take was to provide support for this with a
localeAttribute attribute on the localize tag and use pageContext's
findAttribute() method to resolve it. another option is just to provide a
locale attribute that allows an object. (1) provides a simpler interface,
though isn't quite as flexible as (2).
<i18n:localize bundle="com.wamnet.tools.jsptags.i18n-test"
localeAttribute="userLocale"/>
<i18n:localize bundle="com.wamnet.tools.jsptags.i18n-test" locale="<%=
session.getAttribute("userLocale") %>"/>
now that I see it in writing, I actually prefer (2).
> - you can have only one bundle in your page
True, but I guess I don't see this as a big problem -- hopefully JSP pages
are kept small enough that this doesn't become an issue. I suspect a lot of
smaller sites will use a single bundle for the entire webapp! Any
architecture has to find the balance between flexibility and simplicity, and
I guess I tend to lean towards the simplicity when I can for maintainability
reasons.
Plus, solving this can create additional problems, such as how do you
auto-select the locale if you have to look across two bundles? If one bundle
provides a locale that the other does not... what do you do?
> To overcome these limitations I propose the following
> changes:
>
> A. Replace the "localize" tag with a "bundle" tag that will
> load one bundle and which can have embedded tags
The structure you've proposed above is similar to the familiar XML problem
of whether to use subelements or attributes. Either is fine, but in taglibs
attributes make for a somewhat smaller codebase.
> B. Add a "bundle" attribute to the "message" and "require"
> tags to specify which bundle you want to use.
Hmm.. well, even if we allow multiple bundles for a single page, I'd hate to
require the tags to specify that if there's only one. It makes for a lot
more text to type, and more opportunity for bugs.
> The "bundle" tag would look like:
>
> <i18n:bundle id="bund1">
> <i18n:baseName value="com.wamnet.tools.jsptags.i18n-test"/>
> <i18n:locale language="ro" country="RO"/>
> </i18n:bundle>
>
> or
>
> <i18n:bundle id="bund2">
> <i18n:baseName
> attrib="org.apache.taglibs.i18n.LocalizeTag.bundle"
> scope="application"/>
> <i18n:locale
> attrib="org.apache.taglibs.i18n.LocalizeTag.locale.roRO"
> scope="session"/>
> </i18n:bundle>
>
> or
>
> <i18n:bundle id="bund3">
> <i18n:baseName env="org.apache.taglibs.i18n.LocalizeTag.bundle"/>
> <i18n:localeFromBrowser/>
> </i18n:bundle>
Ok, I kind of like how this looks with subelements, though I still question
the utility of not hardcoding the attribute or environment when if you're
going to specify something you could just specify the basename itself... I
mean, why the indirection if you're going to type something anyway?
As for the locale, I'm not sure why we'd ever specify the language and
country in the web page itself. If you're going to do that, why bother with
internationalization at all? Just put the language you want right in the
page... I think the point of using the tags is to allow the user, not the
programmer, to select the language. I'm probably missing your point again,
like I did in my last note. :-)
> And the corresponding "message" tag would look like:
>
> <i18n:message bundle="bund1" key="test1" />
>
> <i18n:message bundle="bund2" key="test2">
> this only displayed <em>if</em> 'test2' not found.
> </i18n:message>
>
> <i18n:message bundle="bund3" key="test1" args="<%= objectArray %>" />
>
>
> May be the "scope" attribute is not needed and we can use
> "findAttribute".
>
> This approach gives the following advantages:
> - no hard coded values
> - you can use several bundles at the same time
> - more flexibility on specifying the base name and the
> locale
>
> I don't even have to use the "bundle" tag if a controller servlet
> loads the bundle.
the only way this would work is if the bundle id was placed in a session,
page, or request scoped attribute, right? so under your proposed approach,
the bundle tag would put it in a page or request scope, but your controller
servlet would load into a session attribute, then the message tag just uses
"findAttribute". am I following correctly?
>
> I have some other ideas as well, but lets figure this
> first.
>
> What do you think?
>
I'm not convinced on all of it, but you do make some good points. I hope
you'll forgive my tendency to be a bit conservative... early on in my career
I had a history of over-engineering things and I had to good fortune of
living with my mistakes, so I've become less eager to add features until I
fully understood the need for them and the impact of having them.
I'm particularly curious to hear your response to my comments about (1) why
you'd specify the env or attr longhand when you could just specify the
bundle, and (2) the problems related to multiple bundles on a single page.
Tim