flash.localization.XLRLocalizer Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of swfutils Show documentation
Show all versions of swfutils Show documentation
The Apache Royale Compiler SWF Utility classes
/*
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package flash.localization;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.ext.LexicalHandler;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.SAXParser;
import java.util.Map;
import java.util.Locale;
import java.util.Stack;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Iterator;
import java.io.File;
import java.io.InputStream;
import java.io.BufferedInputStream;
import java.net.URL;
/**
* ILocalizer implementation, which supports looking up text in XLR
* files..
*/
public class XLRLocalizer implements ILocalizer
{
public XLRLocalizer()
{
// only resources
}
public XLRLocalizer( String path )
{
findFiles( new File( path ), null );
}
public XLRTargetNode loadNode( Locale fileLocale, String fileId, Locale locale, String id )
{
String key = getKey( fileLocale, fileId );
XLRFile f = filedict.get( key );
if (f == null)
{
String resource = key.replaceAll( "\\.", "/" ) + ".xlr";
URL url = getClass().getClassLoader().getResource( resource );
if (url != null)
{
f = new XLRFile( fileId, url );
filedict.put( key, f );
}
}
if (f != null)
{
f.load();
XLRMessageNode messageNode = (XLRMessageNode) nodedict.get( id );
if (messageNode != null)
{
XLRTargetNode targetNode = messageNode.getTarget( locale.toString() );
return targetNode;
}
}
return null;
}
public XLRTargetNode checkPrefix( Locale fileLocale, String fileId, Locale locale, String id )
{
XLRTargetNode t = loadNode( fileLocale, fileId, locale, id );
if (t == null)
{
int sep = fileId.lastIndexOf( '$' );
if (sep == -1)
sep = fileId.lastIndexOf( '.' );
if (sep != -1)
t = checkPrefix( fileLocale, fileId.substring( 0, sep ), locale, id );
}
return t;
}
public XLRTargetNode checkLocales( Locale locale, String id )
{
XLRTargetNode t = checkPrefix( locale, id, locale, id );
if ((t == null) && (locale.getCountry().length() > 0) && (locale.getVariant().length() > 0))
t = checkPrefix( new Locale( locale.getLanguage(), locale.getCountry() ), id, locale, id );
if ((t == null) && (locale.getCountry().length() > 0))
t = checkPrefix( new Locale( locale.getLanguage() ), id, locale, id );
if ((t == null))
t = checkPrefix( null, id, locale, id );
return t;
}
public ILocalizedText getLocalizedText( Locale locale, String id )
{
XLRMessageNode messageNode = (XLRMessageNode) nodedict.get( id );
XLRTargetNode targetNode = null;
if (messageNode != null)
{
targetNode = messageNode.getTarget( locale.toString() );
}
if (targetNode == null)
{
targetNode = checkLocales( locale, id );
}
if (targetNode == null)
{
return null;
}
return new XLRLocalizedText( targetNode );
}
private String getKey( Locale locale, String id )
{
String key = id;
if (locale != null)
{
if (locale.getLanguage().length() > 0)
{
key += "_" + locale.getLanguage();
if (locale.getCountry().length() > 0)
{
key += "_" + locale.getCountry();
if (locale.getVariant().length() > 0)
{
key += "_" + locale.getVariant();
}
}
}
}
return key;
}
private Map filedict = new HashMap();
private Map nodedict = new HashMap();
private class XLRFile
{
public XLRFile( String prefix, URL url )
{
this.prefix = prefix;
this.url = url;
}
public void load()
{
if (loaded)
{
return;
}
try
{
InputStream in = new BufferedInputStream( this.url.openStream() );
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware( false ); // FIXME
XLRHandler xmlHandler = new XLRHandler( nodedict, prefix );
CDATAHandler cdataHandler = new CDATAHandler( xmlHandler );
SAXParser parser = factory.newSAXParser();
parser.setProperty("http://xml.org/sax/properties/lexical-handler", cdataHandler);
parser.parse( in, xmlHandler );
}
catch (Exception e)
{
e.printStackTrace( );
}
loaded = true;
}
private boolean loaded = false;
private final URL url;
private final String prefix;
}
private void findFiles( File f, String relative )
{
try
{
if (!f.exists())
return;
if (f.isDirectory())
{
File[] files = f.listFiles();
for (int i = 0; i < files.length; ++i)
{
findFiles( files[i].getAbsoluteFile(), ((relative == null)? "":(relative + ".")) + files[i].getName() );
}
}
else
{
if (!f.getName().endsWith( ".xlr" ))
return;
else
{
String id = relative.substring( 0, relative.length() - ".xlr".length() );
String prefix = id;
int dot = id.lastIndexOf( '.' );
int underscore = -1;
if (dot != -1)
{
underscore = id.indexOf( '_', dot );
}
else
{
underscore = id.indexOf( '_' );
}
if (underscore != -1)
{
prefix = id.substring( 0, underscore );
}
filedict.put( id, new XLRFile( prefix, f.toURL() ) );
}
}
}
catch (Exception e)
{
e.printStackTrace( );
}
}
private class XLRLocalizedText implements ILocalizedText
{
public XLRLocalizedText( XLRTargetNode node )
{
this.node = node;
}
public String format( Map parameters )
{
StringBuilder buffer = new StringBuilder();
String s = node.execute( buffer, node.locale, parameters )? buffer.toString() : null;
if (s != null)
{
s = LocalizationManager.replaceInlineReferences( s, parameters );
}
return s;
}
private XLRTargetNode node;
}
private abstract class XLRNode
{
public LinkedList children = new LinkedList();
public boolean execute( StringBuilder buffer, String locale, Map parameters )
{
boolean success = false;
for (Iterator it = children.iterator(); it.hasNext(); )
{
XLRNode child = it.next();
if (child.execute( buffer, locale, parameters ))
{
success = true;
}
}
return success;
}
}
private class XLRChoiceNode extends XLRNode
{
public boolean execute( StringBuilder buffer, String locale, Map parameters )
{
for (Iterator it = children.iterator(); it.hasNext(); )
{
XLRNode child = it.next();
if (child.execute( buffer, locale, parameters ))
{
return true;
}
}
return false;
}
}
private class XLRMessageNode extends XLRChoiceNode
{
public XLRMessageNode( String id )
{
this.id = id;
}
public XLRTargetNode getTarget( String locale )
{
for (Iterator it = children.iterator(); it.hasNext();)
{
XLRNode node = it.next();
if ((node instanceof XLRTargetNode) && ((XLRTargetNode) node).matchesLocale( locale ))
{
return (XLRTargetNode) node;
}
}
return null;
}
public final String id;
}
private class XLRTargetNode extends XLRNode
{
public XLRTargetNode( String locale )
{
this.locale = locale;
}
public boolean matchesLocale( String locale )
{
return (((this.locale == null) && (locale == null)) || locale.equalsIgnoreCase( this.locale ));
}
public boolean execute( StringBuilder buffer, String locale, Map parameters )
{
if (matchesLocale( locale ))
{
return super.execute( buffer, locale, parameters );
}
return false;
}
public final String locale;
}
private class XLRTextNode extends XLRNode
{
public XLRTextNode( String text )
{
this.text = text;
}
public boolean execute( StringBuilder buffer, String locale, Map parameters )
{
boolean success = false;
if (text != null)
{
success = true;
buffer.append( text );
}
boolean result = super.execute( buffer, locale, parameters );
return success || result;
}
public final String text;
}
private class XLRVariableNode extends XLRNode
{
public XLRVariableNode( String name )
{
this.varname = name;
}
public boolean execute( StringBuilder buffer, String locale, Map parameters )
{
boolean success = false;
if (varname != null)
{
success = parameters.containsKey( varname ) && (parameters.get( varname ) != null);
if (success)
{
buffer.append( parameters.get( varname ).toString());
}
}
success |= super.execute( buffer, locale, parameters );
return success;
}
public String varname;
}
private class XLRMatchNode extends XLRNode
{
public String varname;
public String text = null;
public String pattern = null;
public XLRMatchNode( String varname, String pattern )
{
this.varname = varname;
this.pattern = pattern;
}
public boolean execute( StringBuilder buffer, String locale, Map parameters )
{
String value = null;
if ((varname != null) && parameters.containsKey( varname ) && parameters.get( varname ) != null)
{
value = parameters.get( varname ).toString();
}
if (value == null)
{
value = "";
}
// match based on the value being non-zero length, non-zero, or not "false" if pattern isn't set
boolean matched = false;
if (pattern == null)
{
if ((value != null) && (value.length() > 0))
{
matched = !(value.equalsIgnoreCase( "false" ) || value.equals( "0" ));
}
else
{
matched = false; // null string
}
}
else
{
// to match an empty string, try pattern of "^$"
matched = value.matches( pattern );
}
if (matched)
{
super.execute( buffer, locale, parameters );
return true;
}
else
{
return false;
}
}
}
private class XLRHandler extends DefaultHandler
{
public XLRHandler( Map nodedict, String base )
{
this.nodedict = nodedict; // id -> messagenode
this.base = base;
}
public Stack context = new Stack();
private String fileLocale = null;
private String base = null;
private Map nodedict;
StringBuilder textBuffer = new StringBuilder(128);
protected boolean inCDATA = false;
public void startElement (String uri, String localName,
String qName, Attributes attributes)
throws SAXException
{
XLRNode current = null;
if (context.size() > 0)
current = context.peek();
// common shortcuts...
String locale = attributes.getValue( "locale" );
if (locale == null)
locale = fileLocale;
String text = attributes.getValue( "text" );
XLRNode node = null;
if ("messages".equals( qName ))
{
fileLocale = attributes.getValue( "locale" );
if (attributes.getValue( "idbase" ) != null)
base = attributes.getValue( "idbase" );
}
else if ("message".equals( qName ))
{
String id = attributes.getValue( "id" );
if (base != null)
id = base + "." + id;
node = nodedict.get( id );
if (node == null)
{
node = new XLRMessageNode( id );
nodedict.put( id, node );
}
if ((text != null) && (locale != null)) // check errors
{
XLRTargetNode targetNode = new XLRTargetNode( locale );
node.children.add( targetNode );
XLRTextNode textNode = new XLRTextNode( text );
targetNode.children.add( textNode );
}
context.push( node );
}
else if ("target".equals( qName ))
{
node = new XLRTargetNode( locale );
if (text != null)
node.children.add( new XLRTextNode( text ));
current.children.add( node );
context.push( node );
}
else if ("text".equals( qName ))
{
String value = attributes.getValue( "value" );
node = new XLRTextNode( value );
current.children.add( node );
context.push( node );
}
else if ("variable".equals( qName ))
{
String name = attributes.getValue( "name" );
node = new XLRVariableNode( name );
current.children.add( node );
context.push( node );
}
else if ("match".equals( qName ))
{
node = new XLRMatchNode( attributes.getValue( "variable" ), attributes.getValue( "pattern" ) );
if (text != null)
node.children.add( new XLRTextNode( text ));
current.children.add( node );
context.push( node );
}
else if ("select".equals( qName ))
{
node = new XLRChoiceNode();
current.children.add( node );
context.push( node );
}
else
{
throw new SAXParseException( "blorp", null ); // fixme
}
}
public void endElement (String uri, String localName, String qName)
throws SAXException
{
XLRNode current = null;
if (context.size() > 0)
current = context.pop();
if ("messages".equals( qName ))
{
// done
}
else if ("text".equals( qName ))
{
if (textBuffer.length() > 0)
{
current.children.add( new XLRTextNode( textBuffer.toString() ) );
}
}
else if ("variable".equals( qName ))
{
if (textBuffer.length() > 0)
{
((XLRVariableNode) current).varname = textBuffer.toString();
}
}
textBuffer.setLength( 0 );
}
public void characters (char ch[], int start, int length)
throws SAXException
{
if (inCDATA)
{
textBuffer.append(ch, start, length);
}
else
{
String s = new String( ch, start, length ).trim();
if (s.length() > 0)
textBuffer.append( s );
}
}
public void ignorableWhitespace (char ch[], int start, int length)
throws SAXException
{
// no op
}
public void warning ( SAXParseException e)
throws SAXException
{
// no op
}
public void error (SAXParseException e)
throws SAXException
{
// no op
}
public void fatalError (SAXParseException e)
throws SAXException
{
throw e;
}
}
private class CDATAHandler implements LexicalHandler
{
private XLRHandler parentHandler;
public CDATAHandler( XLRHandler h )
{
parentHandler = h;
}
public void startCDATA() throws SAXException
{
parentHandler.inCDATA = true;
}
public void endCDATA() throws SAXException
{
parentHandler.inCDATA = false;
}
public void startDTD(String s, String s1, String s2) throws SAXException
{
}
public void endDTD() throws SAXException
{
}
public void startEntity(String s) throws SAXException
{
}
public void endEntity(String s) throws SAXException
{
}
public void comment(char[] chars, int i, int i1) throws SAXException
{
}
}
}