Okay, small update.
New interface
public interface IFilter {
public abstract String filter(String source);
}
So I've something like this in my application:
ResourceStreamLocator locator;
IFilter filter;
public ResourceStreamLocator getResourceStreamLocator() {
if(locator == null) {
filter = new IFilter() {
public String filter(String source) {
return source.replaceAll("@foo.bar", "new value");
}
};
locator = new
FilterResourceStreamLocator(getSettings().getResourceFinder(), filter);
}
return locator;
}
So the result is replacing every @foo.bar instance in every loaded
markup with 'new value'.
Do you think such/similiar functionality could get into wicket 1.1?
Replacing is done on fly, on every markup reload.
I know that the actual filtering is not optimizied, using Strings
instead of string buffers/builders. But I don't see point in
optimizing this because it won't happen periodicaly, only on markup
reload.
Well, I'm going to get some sleep, it's 3:12 AM here :)
-Matej
Matej Knopp wrote:
I have done some basic stuff.
I have UrlFilterResourceStream class with function
String filter(String source) {
...
}
that can be used to process the markup files before the actual markup
parsing.
All you have to do is add
ResourceStreamLocator locator;
public ResourceStreamLocator getResourceStreamLocator() {
if(locator == null)
locator = new
FilterResourceStreamLocator(getSettings().getResourceFinder());
return locator;
}
It works well with cache, reloading works correctly too and locales
shouldn't be not a problem.
The next step is to introducte an IFilter interface, so that is
possible to take filtering out of the UrlFilterResourceStream class.
And of course, implementing actual text substitution. I'm still not
sure here. What I need is pretty simple, something like replacing
$(foo.bar) with a string. I'm not sure if I need velocity/freemaker
for this. It seems that regexp expressions will do this.
-Matej
Eelco Hillenius wrote:
That would be pretty useable. You probably can't use the default
markup caching mechanism though, so we might want to make that more
configurable
https://sourceforge.net/tracker/index.php?func=detail&aid=1235319&group_id=119783&atid=684978
Juergen, is there anything more we can do here? We had a discussion
about 18n text replacing on this list last week too, so it seems
like a good idea to consider whether we can support this better...
Eelco
Matej Knopp wrote:
What I wanted to do was having a one markup (like Page_src.html)
that would look like
<html>
$(item1)
</html>
and properties for different languages that could be used as model
to generate Page_en, Page_sk, Page_de, etc. These pages would be
generated statically from ide. But I don't want it anymore.
I'm going to try if it is possible to implement my own resource
locator that would return a stream that would generate the correct
page content (replacing things like $(item1)) on fly.
I know I can use <wicket:component> to i18n, but it doesn't seem to
be able to do things like translation buttons label (the value
attribute).
-Matej
Juergen Donnerstag wrote:
Matej,
did you look at the forminput example already? It shows you how to
use
properties file to localize your apps.
I've tried some plugins from exlipse plugins site but I couldn't
get any
of them running properly in eclipse 3.1.
not sure what you mean. An ecplise plugin which "automatically"
maintains the different markup files for you with input from
properties files?
So I just want to know if anyone have some experience with this
to share.
wicket-stuff contains an example on using velocity, but as far as I
remember not in the context of I18N. Don't know if that is of any
help.
What I did some months ago and I don't know if it is still working
with HEAD, I created a kind of wicket based pre-processor which
created files page.html, page_en.html, page_de.html etc from a
template markup file and replaced wicket-preprocessor tags.
Wicket-preprocessor tags didn't use wicket:id, they simply used
w18n:id instead, thus separating the pre-processor from actual wicket
tags. But it was wicket-core which replaced the text to be localized.
Juergen
------------------------------------------------------------------------
package esz.app.i18n;
import java.net.URL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import wicket.util.resource.IResourceStream;
import wicket.util.resource.locator.AbstractResourceStreamLocator;
import wicket.util.resource.locator.ResourceStreamLocator;
public class ClassLoaderFilterResourceStreamLocator extends
AbstractResourceStreamLocator {
/** Logging */
private static Log log = LogFactory.getLog(ResourceStreamLocator.class);
/** The path to search along */
private ClassLoader classloader;
private IFilter filter;
/**
* Constructor
*/
public ClassLoaderFilterResourceStreamLocator(IFilter filter) {
this.filter = filter;
}
/**
* Constructor
*
* @param classloader
* The class loader to search
*/
public ClassLoaderFilterResourceStreamLocator(final ClassLoader
classloader) {
this.classloader = classloader;
}
/**
* @see
wicket.util.resource.locator.AbstractResourceStreamLocator#locate(java.lang.String)
*/
protected IResourceStream locate(final String path) {
// Ensure classloader
if (classloader == null) {
classloader = getClass().getClassLoader();
}
// Log attempt
log.debug("Attempting to locate resource '" + path
+ "' using classloader " + classloader);
// Try loading path using classloader
final URL url = classloader.getResource(path);
if (url != null) {
return new UrlFilterResourceStream(url, filter);
}
return null;
}
}
------------------------------------------------------------------------
package esz.app.i18n;
import java.util.Locale;
import wicket.util.file.IResourceFinder;
import wicket.util.resource.IResourceStream;
import wicket.util.resource.locator.IResourceStreamLocator;
import wicket.util.resource.locator.ResourceStreamLocator;
public class FilterResourceStreamLocator extends ResourceStreamLocator {
/**
* Constructor
*
* @param finder
* The finder to search
*/
public FilterResourceStreamLocator(final IResourceFinder finder, final
IFilter filter) {
super(new IResourceStreamLocator() {
private final ResourceFinderFilterResourceStreamLocator
finderLocator = new ResourceFinderFilterResourceStreamLocator(finder, filter);
private final ClassLoaderFilterResourceStreamLocator
classLoaderLocator = new ClassLoaderFilterResourceStreamLocator(filter);
public IResourceStream locate(String path, String style, Locale
locale, String extension) {
IResourceStream resource = finderLocator.locate(path, style,
locale, extension);
if (resource != null) {
return resource;
}
return classLoaderLocator.locate(path, style, locale,
extension);
}
});
}
}
------------------------------------------------------------------------
package esz.app.i18n;
public interface IFilter {
public abstract String filter(String source);
}
------------------------------------------------------------------------
package esz.app.i18n;
import java.net.URL;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import wicket.util.file.IResourceFinder;
import wicket.util.resource.IResourceStream;
import wicket.util.resource.locator.AbstractResourceStreamLocator;
import wicket.util.resource.locator.ResourceStreamLocator;
public class ResourceFinderFilterResourceStreamLocator extends
AbstractResourceStreamLocator {
/** Logging */
private static Log log = LogFactory.getLog(ResourceStreamLocator.class);
/** The finder to use to locate the resource stream */
private IResourceFinder finder;
private IFilter filter;
/**
* Constructor
*
* @param finder
* The path to search
*/
public ResourceFinderFilterResourceStreamLocator(final IResourceFinder
finder, IFilter filter) {
this.finder = finder;
this.filter = filter;
}
/**
* @see
wicket.util.resource.locator.AbstractResourceStreamLocator#locate(java.lang.String)
*/
protected IResourceStream locate(final String path) {
// Log attempt
log.debug("Attempting to locate resource '" + path + "' on path "
+ finder);
// Try to find file resource on the path supplied
final URL file = finder.find(path);
// Found resource?
if (file != null) {
// Return file resource
return new UrlFilterResourceStream(file, filter);
}
return null;
}
}
------------------------------------------------------------------------
package esz.app.i18n;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import wicket.util.resource.AbstractResourceStream;
import wicket.util.resource.ResourceStreamNotFoundException;
import wicket.util.resource.UrlResourceStream;
import wicket.util.time.Time;
public class UrlFilterResourceStream extends AbstractResourceStream {
UrlResourceStream wrapped;
ByteArrayInputStream buffer;
URL url;
boolean fresh;
long length;
IFilter filter;
UrlFilterResourceStream(final URL url, IFilter filter) {
this.url = url;
wrapped = new UrlResourceStream(url);
// we set fresh here, because we've create UrlResourceStream
// without actualy reading the stream, so it can be used in
// getInputStream.
fresh = true;
this.filter = filter;
}
public InputStream getInputStream() throws ResourceStreamNotFoundException {
if (buffer == null) {
if (fresh == false) // do we have to create new resource stream?
wrapped = new UrlResourceStream(url);
else
fresh = false;
// FIXME! - charset
// The charset should be read from the first line of file
// (<xml...), otherwise set to VM default
String filtered = filter.filter(wrapped.asString());
length = filtered.length();
buffer = new ByteArrayInputStream(filtered.getBytes());
}
return buffer;
}
public String getContentType() {
return getContentType();
}
public long length() {
return length;
}
public URL getURL() {
return wrapped.getURL();
}
public Time lastModifiedTime() {
return wrapped.lastModifiedTime();
}
public void close() throws IOException {
wrapped.close();
if (buffer != null)
buffer.close();
buffer = null;
}
}