You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@cocoon.apache.org by Mike Engelhart <me...@earthtrip.com> on 2000/06/12 17:45:12 UTC

ResourceBundles - was [RT] i18n

I've been following the i18n thread and last night had a few minutes to whip
up some code. 

Here's my thoughts (I guess "random" thoughts :-))

1)  We all like XML for configuration.  Properties are OK but XML is better
and portable.
2)  I've been using ResourceBundle's a lot and like them for several reasons
some of which are that they've already been developed (my personal
favorite), they're debugged, they're standard Java and really easy to use
and caching is handled automatically so they only get loaded once by the
classloader

i've been using PropertyResourceBundle's in my code but have wanted an XML
based solution. My suggestion is this (please remove code and ideas that
suck and replace them with better code & ideas that don't suck).  Also be
advised that I have not even looked at C2 yet so my understanding of the
sitemap is basically non-existant so I didn't try and integrate this within
the C2 architecture.. :-(  This is solely to allow us to use XML documents
but still get all the ResourceBundle qualities that are cool.

anyway, we define an i18n directory in the sitemap where langauge based XML
documents reside using standard naming conventions for the documents, e.g.,
lang.xml, lang_en.xml, lang_es.xml, etc. (the default file being lang.xml
with no suffix that is used when an attempt to use a language that doesn't
have an associated ResourceBundle is made).

Then use the following class, I'm calling it CocoonResourceBundle which
reads in XML files of the following format (again replace XML that sucks
with XML that doesn't suck).
<!-- lang_en.xml -->
<?xml version="1.0"?>
<document xml:lang="en">
    <word>
        <key>_DATE</key>
        <value>Date</value>
    </word>
    <word>
        <key>_TIME</key>
        <value>Time</value>
    </word>
</document>

<!-- lang_es.xml -->
<?xml version="1.0"?>
<document xml:lang="es">
  <word>
    <key>_DATE</key>
    <value>Dia</value>
  </word>

  <word>
    <key>_TIME</key>
    <value>Tiempo</value>
  </word>
</document>

Here's the code for CocoonResourceBundle.  It extends
java.util.ListResourceBundle which itself subclasses
java.util.ResourceBundle.
This allows for us to customize the filling in of the "contents" array with
the XML based language file.



/** JDK classes **/
import java.io.IOException;
import java.util.ListResourceBundle;

/** W3C DOM classes **/
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
/** xerces classes **/
import org.apache.xerces.dom.TextImpl;
import org.apache.xerces.parsers.DOMParser;
import org.xml.sax.SAXException;

public class CocoonResourceBundle extends ListResourceBundle
{
    public CocoonResourceBundle()
    {
        super();
        try
        {
            setContents();
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
    }
    
    public Object[][] getContents()
    {
        return this.contents;
    }

    private void setContents() throws IOException, SAXException
    {
        DOMParser parser = new DOMParser();
        parser.parse("lang.xml");
        Document doc = parser.getDocument();
        Element e = doc.getDocumentElement();
        NodeList nodes = e.getElementsByTagName("word");
        int numberNodes = nodes.getLength();

        contents = new Object[numberNodes][2];
        
        for (int i = 0; i < numberNodes; i++)
        {
            Node node = nodes.item(i);
            contents[i][0] = getTextNodeData((Element) node, "key");
            contents[i][1] = getTextNodeData((Element) node, "value");
        }
    }
    
    
    public String getTextNodeData(Element element, String elementName)
    {
        NodeList nodes = element.getElementsByTagName(elementName);
        if (nodes.getLength() < 1)
            return "";
        Node node = nodes.item(0).getFirstChild();
        if (node.getNodeType() == Node.TEXT_NODE)
            return ((TextImpl) node).getData();
        else
            return "";
    }

    static Object[][] contents;
}

Then in XSP code or anywhere else in C2 you can do these kinds of accesses
(pseudo code follows)

<xsp:page>
    <document>
        <xsp:logic>
            Locale loc = request.getLocale();
            java.util.ResourceBundle bundle =
ResourceBundle.getBundle("org.apache.CocoonResourceBundle", loc);
        </xsp:logic>
        <!-- do something useful -->
        <p><xsp:expr>The word for 'Date' in your browsers default locale is
<xsp:expr>bundle.getString("_DATE")</xsp:expr></p >
    </document>
<xsp:page>

I'm not sure if this is possible but can we have Cocoon 2 (on startup) scan
the pre-defined language repository for files and then create classes on the
fly for each language?  Otherwise you need separate object code for each
language like CocoonResourceBundle_en.java, CocoonResouceBundle_es.java,
etc.   That's just how ResourceBundle's are designed.  If we could do this
without hardcoding the path names to the lang.xml files, that would be
ideal.  Again, this is just a concept so there is more work to do to get
this to work within C2 but it seems like a relatively simple solution that
gives us both of the best worlds.

Mike


Re: ResourceBundles - was [RT] i18n

Posted by Berin Loritsch <bl...@infoplanning.com>.
Stefano Mazzocchi wrote:

> Hey, I like this and I think this is general enough to be incorporated
> into Avalon as a very common block (like logging, thread management,
> object storing and such).

It may end up being just an extension of the ResourceBundle.  The i18n
file loading and such might constitute making it a block, I'll breach it with
Federico and get his input.  I'm still getting a handle on what architecturally
will constitute an architectural component/block, and what should simply
be a class.  ResourceBundle implicitly has a lot of that functionality in
it--so it may not constitute being a block or even a component.

Then again, to fit in the framework, and have an XMLResourceBundle
be part of a generic i18n component it would make sense.

> Just one thing on the schema: the use of "id" could create naming
> problems since ids cannot be repeated inside the same file. So I'd
> suggest:
>
> <?xml version="1.0"?>
> <resources xml:lang="en">
>   <group name="error">
>     <resource name="500">Internal Server Error</resource>
>     <resource name="404">Page not found</resource>
>   </group>
>   <group name="uri">
>     <resource name="addUser">user/add</resource>
>     <resource name="killUser">user/obliterate</resource>
>   </group>
>   <group name="form">
>     <resource name="userName" value="Enter the user's name here"/>
>   </group>
> </resource>
>
> Note how the syntax
>
>  <resource name="xxx" value="yyy">
>
> is equivalent to
>
>  <resource name="xxx>yyy</resource>
>
> which is perfectly legal and allows you to use the markup you like the
> most.

I like that.
+1.


Re: ResourceBundles - was [RT] i18n

Posted by Mike Engelhart <me...@earthtrip.com>.
on 6/13/00 7:19 AM, Stefano Mazzocchi at stefano@apache.org wrote:

> 
> Hey, I like this and I think this is general enough to be incorporated
> into Avalon as a very common block (like logging, thread management,
> object storing and such).
Yeah, I use ResourceBundle's for all sorts of uses in my app that are
unrelated to i18n.  They're very generic and useful when you call their
getResouceBundle() methods that don't have a Locale parameter.

> 
> Note how the syntax
> 
> <resource name="xxx" value="yyy">
> 
> is equivalent to
> 
> <resource name="xxx>yyy</resource>
> 
> which is perfectly legal and allows you to use the markup you like the
> most.
I like this too 
+1


Mike


Re: ResourceBundles - was [RT] i18n

Posted by Stefano Mazzocchi <st...@apache.org>.
Berin Loritsch wrote:
> 
> Mike Engelhart wrote:
> 
> > I've been following the i18n thread and last night had a few minutes to whip
> > up some code.
> >
> > Here's my thoughts (I guess "random" thoughts :-))
> >
> > 1)  We all like XML for configuration.  Properties are OK but XML is better
> > and portable.
> > 2)  I've been using ResourceBundle's a lot and like them for several reasons
> > some of which are that they've already been developed (my personal
> > favorite), they're debugged, they're standard Java and really easy to use
> > and caching is handled automatically so they only get loaded once by the
> > classloader
> >
> > i've been using PropertyResourceBundle's in my code but have wanted an XML
> > based solution. My suggestion is this (please remove code and ideas that
> > suck and replace them with better code & ideas that don't suck).  Also be
> > advised that I have not even looked at C2 yet so my understanding of the
> > sitemap is basically non-existant so I didn't try and integrate this within
> > the C2 architecture.. :-(  This is solely to allow us to use XML documents
> > but still get all the ResourceBundle qualities that are cool.
> >
> 
> I like using existing code to.  No sense in reinventing the wheel if it performs
> 
> your needs.
> 
> > Then use the following class, I'm calling it CocoonResourceBundle which
> > reads in XML files of the following format (again replace XML that sucks
> > with XML that doesn't suck).
> > <!-- lang_en.xml -->
> > <?xml version="1.0"?>
> > <document xml:lang="en">
> >     <word>
> >         <key>_DATE</key>
> >         <value>Date</value>
> >     </word>
> >     <word>
> >         <key>_TIME</key>
> >         <value>Time</value>
> >     </word>
> > </document>
> 
> I would propose a slightly different document style.  The style that you
> proposed offers no advantage over Property files--its more verbose,
> not as easy to follow.  I would propose the following style that incorporates
> the concept of resource groups.
> 
> <?xml version="1.0"?>
> <resource xml:lang="en">
>   <group id="error">
>     <value id="500">Internal Server Error</value>
>     <value id="404">Page not found</value>
>   </group>
>   <group id="uri">
>     <value id="addUser">user/add</value>
>     <value id="killUser">user/obliterate</value>
>   </group>
>   <group id="form">
>     <value id="userName">Enter the user's name here</value>
>   </group>
> </resource>
> 
> That way, we have the ability to group the informaiton into some form
> of context.  It is simple, straight-forward, and provides a benefit over
> simple property files.
> 
> Once we have our XMLResourceBundle object, we can get the resource
> by id.  Something like this would be possible:
> 
> ResourceBundle res;
> res = XMLResourceFactory.getResourceBundle(String role);
> res.getString(String key);

Hey, I like this and I think this is general enough to be incorporated
into Avalon as a very common block (like logging, thread management,
object storing and such).

Just one thing on the schema: the use of "id" could create naming
problems since ids cannot be repeated inside the same file. So I'd
suggest:

<?xml version="1.0"?>
<resources xml:lang="en">
  <group name="error">
    <resource name="500">Internal Server Error</resource>
    <resource name="404">Page not found</resource>
  </group>
  <group name="uri">
    <resource name="addUser">user/add</resource>
    <resource name="killUser">user/obliterate</resource>
  </group>
  <group name="form">
    <resource name="userName" value="Enter the user's name here"/>
  </group>
</resource>

Note how the syntax

 <resource name="xxx" value="yyy">

is equivalent to

 <resource name="xxx>yyy</resource>

which is perfectly legal and allows you to use the markup you like the
most.

-- 
Stefano Mazzocchi      One must still have chaos in oneself to be
                          able to give birth to a dancing star.
<st...@apache.org>                             Friedrich Nietzsche
--------------------------------------------------------------------
 Missed us in Orlando? Make it up with ApacheCON Europe in London!
------------------------- http://ApacheCon.Com ---------------------



Re: ResourceBundles - was [RT] i18n

Posted by Berin Loritsch <bl...@infoplanning.com>.
Mike Engelhart wrote:

> on 6/12/00 11:43 AM, Berin Loritsch at bloritsch@infoplanning.com wrote:
>
> > <?xml version="1.0"?>
> > <resource xml:lang="en">
> > <group id="error">
> > <value id="500">Internal Server Error</value>
> > <value id="404">Page not found</value>
> > </group>
> > <group id="uri">
> > <value id="addUser">user/add</value>
> > <value id="killUser">user/obliterate</value>
> > </group>
> > <group id="form">
> > <value id="userName">Enter the user's name here</value>
> > </group>
> > </resource>
> >
> > That way, we have the ability to group the informaiton into some form
> > of context.  It is simple, straight-forward, and provides a benefit over
> > simple property files.
> >
> > Once we have our XMLResourceBundle object, we can get the resource
> > by id.  Something like this would be possible:
> >
> > ResourceBundle res;
> > res = XMLResourceFactory.getResourceBundle(String role);
> > res.getString(String key);
>
> I think I like this better too. Are you saying that each <group>'s id
> attribute constitutes a separate ResourceBundle behind the scenes then?
> So in your example, it would be like
>
> String role = "uri";
> ResourceBundle res = XMLResourceFactory.getResourceBundle(role);
> res.getString("addUser");
>
> Mike

That's the idea.


Re: ResourceBundles - was [RT] i18n

Posted by Mike Engelhart <me...@earthtrip.com>.
on 6/12/00 11:43 AM, Berin Loritsch at bloritsch@infoplanning.com wrote:

> <?xml version="1.0"?>
> <resource xml:lang="en">
> <group id="error">
> <value id="500">Internal Server Error</value>
> <value id="404">Page not found</value>
> </group>
> <group id="uri">
> <value id="addUser">user/add</value>
> <value id="killUser">user/obliterate</value>
> </group>
> <group id="form">
> <value id="userName">Enter the user's name here</value>
> </group>
> </resource>
> 
> That way, we have the ability to group the informaiton into some form
> of context.  It is simple, straight-forward, and provides a benefit over
> simple property files.
> 
> Once we have our XMLResourceBundle object, we can get the resource
> by id.  Something like this would be possible:
> 
> ResourceBundle res;
> res = XMLResourceFactory.getResourceBundle(String role);
> res.getString(String key);

I think I like this better too. Are you saying that each <group>'s id
attribute constitutes a separate ResourceBundle behind the scenes then?
So in your example, it would be like

String role = "uri";
ResourceBundle res = XMLResourceFactory.getResourceBundle(role);
res.getString("addUser");

Mike


Re: ResourceBundles - was [RT] i18n

Posted by Berin Loritsch <bl...@infoplanning.com>.
Mike Engelhart wrote:

> I've been following the i18n thread and last night had a few minutes to whip
> up some code.
>
> Here's my thoughts (I guess "random" thoughts :-))
>
> 1)  We all like XML for configuration.  Properties are OK but XML is better
> and portable.
> 2)  I've been using ResourceBundle's a lot and like them for several reasons
> some of which are that they've already been developed (my personal
> favorite), they're debugged, they're standard Java and really easy to use
> and caching is handled automatically so they only get loaded once by the
> classloader
>
> i've been using PropertyResourceBundle's in my code but have wanted an XML
> based solution. My suggestion is this (please remove code and ideas that
> suck and replace them with better code & ideas that don't suck).  Also be
> advised that I have not even looked at C2 yet so my understanding of the
> sitemap is basically non-existant so I didn't try and integrate this within
> the C2 architecture.. :-(  This is solely to allow us to use XML documents
> but still get all the ResourceBundle qualities that are cool.
>

I like using existing code to.  No sense in reinventing the wheel if it performs

your needs.

> Then use the following class, I'm calling it CocoonResourceBundle which
> reads in XML files of the following format (again replace XML that sucks
> with XML that doesn't suck).
> <!-- lang_en.xml -->
> <?xml version="1.0"?>
> <document xml:lang="en">
>     <word>
>         <key>_DATE</key>
>         <value>Date</value>
>     </word>
>     <word>
>         <key>_TIME</key>
>         <value>Time</value>
>     </word>
> </document>

I would propose a slightly different document style.  The style that you
proposed offers no advantage over Property files--its more verbose,
not as easy to follow.  I would propose the following style that incorporates
the concept of resource groups.

<?xml version="1.0"?>
<resource xml:lang="en">
  <group id="error">
    <value id="500">Internal Server Error</value>
    <value id="404">Page not found</value>
  </group>
  <group id="uri">
    <value id="addUser">user/add</value>
    <value id="killUser">user/obliterate</value>
  </group>
  <group id="form">
    <value id="userName">Enter the user's name here</value>
  </group>
</resource>

That way, we have the ability to group the informaiton into some form
of context.  It is simple, straight-forward, and provides a benefit over
simple property files.

Once we have our XMLResourceBundle object, we can get the resource
by id.  Something like this would be possible:

ResourceBundle res;
res = XMLResourceFactory.getResourceBundle(String role);
res.getString(String key);