On Aug 19, 2009, at 1:58 PM, Ceki Gulcu wrote:
Ralph Goers wrote:
As I've said, I'm not at all in favor of SLF4J "doing" I18N. It is
better to do it under a framework such as Spring's MessageSource
interface where you can either use the default implementation,
which uses ResourceBundles, or easily provide your own. As I said,
I'm also planning on creating a framework to manage
internationalized messages using Commons Configuration and XML files.
In a way, MessageFormatter [1] performs a similar function to a
ResourceBundle. It is also noteworthy that currently
MessageFormatter.format() is invoked within slf4j bindings.
Previously, users had asked that the MessageFormatter implementation
be pluggable. Unfortunately, this is not possible because if library
A depends on MessageFormatter_A and library B depends on
MessageFormatter_B, and if MessageFormatter_A and MessageFormatter_B
use incompatible message formatting conventions, for example "hello
{}" and "hello {0}", then choosing MessageFormatter_A as the
implementation will screw up messages generated by library B. The
same problem would occur with resource bundles or its spring
equivalents.
While an I18N framework might do some sort of message formatting
itself it wouldn't replace MessageFormatter.format(). In otherwords,
lets say I have a couple of message definitions like
<property key="name">Bank of America</property>
<property key="welcome">Welcome to ${name}, {}</property>
In this case one would hope that the framework would return "Welcome
to Bank of America, {}". Presumably SLF4J's usual mechanism would
replace the runtime variable. OTOH, if the formatting is deferred to
the Appender then obviously the runtime variables would have to be
replaced there. Many of the current I18N frameworks use the normal
Java formatter for that.
In that scenario the application either calls getMessage() and then
passes the resulting String to the log call or the application
passes the message key as the message on the log call, which is the
approach I would suggest. In the second scenario it is up to the
Appender to resolve the key by calling getMessage(). Ideally, the
Appender should be able to tell whether it is getting a key or the
actual message text. This can be done simply by convention - i.e. a
log message like "key=Message1" or by passing a parameter. There is
no real need to enhance SLF4J to be able to do this.
Assuming we had I18NLogger_1 wrapping/decorating o.slf4j.Logger, a
printing method, say i18nInfo() could be implemented as:
public class I18NLogger_1 extends LoggerWrapper implements Logger
I18NLogger(Logger logger) {
super(logger, I18NLogger_1.class.getName());
}
void i18nInfo(String message, Object... params) {
if(logger.isInfoEnabled()) {
// aMessageSourceImpl is some implementation of
// org.springframework.context.MessageSource or similar
// interface
String m = aMessageSourceImpl.getMessage(message, params,
locale);
logger.info(m);
}
}
}
In the above code, only aMessageSourceImpl and locale are not
clearly defined.
Another possible implementation for I18NLogger is as follows:
public class I18NLogger_2 extends LoggerWrapper implements Logger
I18NLogger_2(Logger logger) {
super(logger, I18NLogger_2.class.getName());
}
void i18nInfo(String message, Object... params) {
if(logger.isInfoEnabled()) {
// I18N is a marker for all internationalized messages
logger.info(I18N, message, params);
}
}
}
In this second implementation, internationalization is done within
the appropriate appender or possibly a new logback component (e.g.
ILoggingEventTransformer) which would know how to
internationalize messages. It would do so only for messages marked
with I18N.
Wow. How stupid of me. I completely forgot about Markers. That is an
obvious and very good way of indicating whether the message is a key
or text.
The advantage of this second approach is that Joran (logback's
internal configuration framework) can be leveraged to configure
things pretty much the end-user wants. See for example
SiftingAppender [2] which is heavily based on Joran.
The piece that SLF4J is missing is the ability to detect the target
Locale of the message. But even this can be handled without change
to SLF4J. Just adding the Locale to the MDC would allow the
Appender to do the right thing. Of course, you'd have to use a
logging implementation that supports the MDC.
FYI, all slf4j bindings, including slf4j-jdk14 and even slf4j-nop
ship with functional MDC support. It's just that the underlying
logging framework does not make use of the provided MDC data.
Sure. But how would you write a Handler for JUL that could do it?
In short, instead of asking for a change to SLF4J it would make
more sense to me for you to ask for an enhancement to Logback so
that any Appender can have the opportunity to internationalize the
message. Currently you'd have to do that in a Layout, but I don't
believe all Appenders support them.
I don't know. Logback is tempting because of all the customization
it allows. I could even imagine adding a new component, say
ILoggingEventTransformer, which could transform logging events with
internationalization being one particular type of transformation. If
ILoggingEventTransformer came before appenders, it could transform
the event for all appenders. Nevertheless, the main advantage of
logback is all the additional customization made possible.
Yes. Doing it that way would be beneficial to some Logback users.
Hopefully, it would still allow the message to be left unresolved in
the case where the customer wants to write the message key and
parameters to a database, not the localized message.
For Web Beans, I am under the impression that all logging back ends
need to be supported, hence I18NLogger_1.
What were the requirements again? :-)
Lol.
Ralph
_______________________________________________
dev mailing list
dev@slf4j.org
http://www.slf4j.org/mailman/listinfo/dev