Indeed, when we get to Stripes, developers (and Stripes) should not guess where the strings are located. I filed this bug precisely because of that fact. TODAY, developers need to guess. And tomorrow, Stripes will have to.
In theory, we distinguish between top-level JSPs (which provide business logic and field validation) and template *Content JSPs (which present the UI). Whether something is in CoreResources versus default.props seems to depend on whether we've shipped it something as opposed to a third party customization.
But this has led to some slightly weird conventions. For example, the method that validates the input for new user profiles (in UserManager.validateProfile) uses the CoreResources bundle for generating errors – but the presentation markup on ProfileContent.jsp uses the "default" bundle. Why? Is there something intrinsic about validation that makes it a "core" feature rather than a "custom template" feature? Why look up field names in two places?
The key problem, in my view, is that in "core" we have mixed presentation-tier messages (for example, JSP form field validation) in with core class messages that have nothing to do with the presentation tier. I would suggest to you that this is the wrong distinction. The key point of separation (assuming we need one at all!) is not who (us v. someone els) WROTE the message strings, but what TIER the messages apply to.
For example, I've mixed together the various "login" properties from CoreResources and the default bundle. Can you tell which belongs to which? I sure can't.
login.heading.login=Sign in to
login.help=Please sign in with your login name and password.
login.error.capslock=Invalid login (please check your Caps Lock key) #obsolete
login.error.password=Not a valid login.
login.error.noaccess=It seems you don't have access to that. Sorry.
login.lostpw=Lost your password?
to log in once you retrieve your new password.
login.register.tab=Register New User
Having a single set of bundles for the JSP tier is critical for Stripes. Stripes relies on being able to locate a standard resource bundle for looking up validation error strings, field labels and the like. In the servlet configuration, you can tell Stripes where to find these strings by setting the "StripesResources" servlet init param. (You can actually configure two different bundles, one for errors and one for field names, but that's a minor point.) The point is, Stripes has no knowledge of what a JSPWiki "default template" is versus a "core resource"; it just wants a predictable place to find message strings.
For example, let's look at what happens in a typical Stripes ActionBean custom validation method.
@ValidationMethod( on = "save", when = ValidationState.ALWAYS )
public void validatePasswords( ValidationErrors errors )
// If a password was supplied, the same value must also have been passed
// to passwordAgain
if( m_profile.getPassword() != null )
if( !m_profile.getPassword().equals( m_passwordAgain ) )
errors.add( "profile.password", new LocalizableError( "security.error.passwordnomatch" ) );
This method fires before the save() event handler executes, and it makes sure the two password fields match. The ValidationErrors object contains the set of errors for this particular submitted form. If we add a LocalizableError (constructed with a message key), it will look in the bundle we've configured Stripes to use. You could argue, in this case, that Stripes should obviously use CoreResources, and in this case I would agree. In case we wanted to use the template's bundle, we could supply a "SimpleError" type instead, and look up and supply as hard-coded text the localized string we want, from the bundle we want. Ok, fine.
But, of course, we won't always have as much control over which message bundle we use. Consider a setFullname() setter method on the ActionBean with a @Validate annotation:
@Validate( field = "fullname", maxlength = 100, required = true, on = "save", label="security.user.fullname" )
The "label" portion of the annotation tells Stripes to use the "security.user.fullname" key for reporting errors. Stripes will look in the bundle we told it to use, presumably CoreResources. But if we wanted to use something in a template bundle, we'd be hosed.
Given the constraint that Stripes requires a consistent place for looking up message keys, we have exactly two choices here:
- Move ALL presentation-tier messages to default.properties and have Stripes use that as its default bundle. We could do this in 2.8
- Consolidate the properties in CoreResources and default.props and have Stripes use that bundle. It would be hard to do this in 2.8.
I favor the latter – collapsing ALL i18n properties (plugins too) into a single set of files. In addition, I think it would also make sense to externalize the properties into a directory in WEB-INF, rather than keep them in JSPWiki.jar. If, indeed, we expect developers to customize things, it seems burdensome to force them to rebuild the JSPWiki.jar every time they change a message string.