Tim Dawson wrote:
[...]
> > 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 mean the one with the "localeAttribute" attribute? That is
the one I would prefer because it makes more sense to somebody
that doesn't know Java.
>
> > - 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.
It is really hard to guess in what ways people will use
this taglib. In some cases it may make sense to have several
bundles in one page.
>
> 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.
I made the very same reasoning when I started using the JDBC
taglib but Morgan convinced of the contrary. One big drawback
in JSP is that you cannot use tags to set the value of some other
tag's attribute. To give you an example, here is what you
have to do to set the base name from a parameter:
<i18n:localize bundle='<%=request.getParameter("BundleName")%>'/>
using subelements you could have:
<i18n:localize>
<i18n:baseName><req:parameter name="BundleName"/></i18n:baseName>
</i18n:localize>
or:
<i18n:localize>
<i18n:baseName param="BundleName"/>
</i18n:localize>
The first example using subelements may be a bit verbose,
but is very generic. You can use whatever tags you like
in order to generate the name: JNDI, JDBC... It is very
flexible.
The second example is just a convenience for a common
usage.
>
> > 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?
At this point I think that the best way would be to have an
optional attribute on the "bundle" tag, called "basename", which
can be used for hardcoded names and a subelement that can be used
for anything else:
<i18n:bundle id="bund1" basename="MyBundle"/>
or
<i18n:bundle id="bund2">
<i18n:baseName><app:attribute
name="org.apache.taglibs.i18n.LocalizeTag.bundle"/></i18n:baseName>
</i18n:bundle>
The advantage is that we don't have to deal with specific
cases like scope attributes or environment variables, those
values can be retrieved by other tags.
>
> 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. :-)
That was just a dumb example. Instead of attributes we should
probably use subelements to leave it open where the language
and the country comes from.
>
> > 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?
Well, the "bundle" would place it in the page scope,
but if a controlling servlet is doing this then it would
be placed at least in the request scope. The "message"
tag should use "findAttribute".
>
> >
> > 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.
(1) I got to the conclusion that we should not deal with the "env"
and "attr", but by using a "bundleName" subelement we leave the
possibility open.
(2) You have a very good point that by enforcing the "bundle" attribute
on the "message" tag we complicate things unnecessarily. One
solution would be to make it optional and use a tag to set
an implicit bundle:
<i18n:bundle id="b1" baseName="xyz"/>
<i18n:bundle id="b2" baseName="abc"/>
<i18n:use bundle="b1">
<i18n:message key="x"/>
<i18n:use bundle="b1">
<i18n:message key="a"/>
<i18n:message key="b"/>
<i18n:message bundle="b2" key="z"/>
</i18n:use>
<i18n:message bundle="b1" key="c"/>
<i18n:message key="y"/>
</i18n:use>
Marius