1 package org.apache.velocity.tools.struts;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.util.List;
23 import java.util.Locale;
24 import org.apache.struts.util.MessageResources;
25 import org.apache.velocity.tools.Scope;
26 import org.apache.velocity.tools.config.DefaultKey;
27 import org.apache.velocity.tools.config.ValidScope;
28
29 /**
30 * <p>
31 * The MessageTool is used to render internationalized message strings. Source
32 * of the strings are the message resource bundles of the Struts framework. The
33 * following methods operate on these message resources.
34 * </p>
35 *
36 * <p><pre>
37 * Template example(s):
38 * #if( $text.greeting.exists )
39 * $text.greeting
40 * #end
41 *
42 * Toolbox configuration:
43 * <tools>
44 * <toolbox scope="request">
45 * <tool class="org.apache.velocity.tools.struts.MessageTool"/>
46 * </toolbox>
47 * </tools>
48 * </pre></p>
49 *
50 * <p>This tool should only be used in the request scope.</p>
51 *
52 * @author <a href="mailto:sidler@teamup.com">Gabe Sidler</a>
53 * @since VelocityTools 1.0
54 * @version $Id: MessageTool.java 601976 2007-12-07 03:50:51Z nbubna $
55 */
56 @DefaultKey("text")
57 @ValidScope(Scope.REQUEST)
58 public class MessageTool extends MessageResourcesTool
59 {
60 /**
61 * Looks up and returns the localized message for the specified key.
62 * The user's locale is consulted to determine the language of the
63 * message.
64 *
65 * <p><pre>Example use: $text.forms.profile.title</pre></p>
66 *
67 * @param key message key
68 */
69 public TextKey get(String key)
70 {
71 return new TextKey(key, null, null, getLocale());
72 }
73
74
75 /**
76 * Looks up and returns the localized message for the specified key.
77 * The user's locale is consulted to determine the language of the
78 * message.
79 *
80 * @param key message key
81 * @param bundle The bundle name to look for.
82 *
83 * @return the localized message for the specified key or
84 * <code>null</code> if no such message exists
85 * @since VelocityTools 1.1
86 */
87 public String get(String key, String bundle)
88 {
89 return get(key, bundle, (Object[])null);
90 }
91
92
93 /**
94 * Looks up and returns the localized message for the specified key.
95 * Replacement parameters passed with <code>args</code> are
96 * inserted into the message. The user's locale is consulted to
97 * determine the language of the message.
98 *
99 * @param key message key
100 * @param args replacement parameters for this message
101 *
102 * @return the localized message for the specified key or
103 * <code>null</code> if no such message exists
104 */
105 public String get(String key, Object args[])
106 {
107 return get(key, null, args);
108 }
109
110 /**
111 * Looks up and returns the localized message for the specified key.
112 * Replacement parameters passed with <code>args</code> are
113 * inserted into the message. The user's locale is consulted to
114 * determine the language of the message.
115 *
116 * @param key message key
117 * @param bundle The bundle name to look for.
118 * @param args replacement parameters for this message
119 * @since VelocityTools 1.1
120 * @return the localized message for the specified key or
121 * <code>null</code> if no such message exists
122 */
123 public String get(String key, String bundle, Object args[])
124 {
125 return this.get(key, bundle, args, getLocale());
126 }
127
128 /**
129 * Looks up and returns the localized message for the specified key.
130 * Replacement parameters passed with <code>args</code> are
131 * inserted into the message.
132 *
133 * @param key message key
134 * @param bundle The bundle name to look for.
135 * @param args replacement parameters for this message
136 * @param locale The locale to use for this message.
137 *
138 * @return the localized message for the specified key or
139 * <code>null</code> if no such message exists
140 * @since VelocityTools 1.4
141 */
142 public String get(String key, String bundle, Object[] args, Locale locale)
143 {
144 MessageResources res = getResources(bundle);
145 if (res == null)
146 {
147 return null;
148 }
149
150 // return the requested message
151 if (args == null)
152 {
153 return res.getMessage(locale, key);
154 }
155 else
156 {
157 return res.getMessage(locale, key, args);
158 }
159 }
160
161 /**
162 * Same as {@link #get(String key, Object[] args)}, but takes a
163 * <code>java.util.List</code> instead of an array. This is more
164 * Velocity friendly.
165 *
166 * @param key message key
167 * @param args replacement parameters for this message
168 *
169 * @return the localized message for the specified key or
170 * <code>null</code> if no such message exists
171 */
172 public String get(String key, List args)
173 {
174 return get(key, null, args);
175 }
176
177 /**
178 * Same as {@link #get(String key, Object[] args)}, but takes a
179 * <code>java.util.List</code> instead of an array. This is more
180 * Velocity friendly.
181 *
182 * @param key message key
183 * @param bundle The bundle name to look for.
184 * @param args replacement parameters for this message
185 * @since VelocityTools 1.1
186 * @return the localized message for the specified key or
187 * <code>null</code> if no such message exists
188 */
189 public String get(String key, String bundle, List args)
190 {
191 return get(key, bundle, args.toArray());
192 }
193
194 /**
195 * Looks up and returns the localized message for the specified key.
196 * Replacement parameters passed with <code>args</code> are
197 * inserted into the message.
198 *
199 * @param key message key
200 * @param bundle The bundle name to look for.
201 * @param args replacement parameters for this message
202 * @param locale The locale to use for this message.
203 *
204 * @since VelocityTools 1.4
205 * @return the localized message for the specified key or
206 * <code>null</code> if no such message exists
207 */
208 public String get(String key, String bundle, List args, Locale locale)
209 {
210 return get(key, bundle, args.toArray(), locale);
211 }
212
213 /**
214 * Checks if a message string for a specified message key exists
215 * for the user's locale.
216 *
217 * @param key message key
218 *
219 * @return <code>true</code> if a message strings exists,
220 * <code>false</code> otherwise
221 */
222 public boolean exists(String key)
223 {
224 return exists(key, null);
225 }
226
227 /**
228 * Checks if a message string for a specified message key exists
229 * for the user's locale.
230 *
231 * @param key message key
232 * @param bundle The bundle name to look for.
233 * @since VelocityTools 1.1
234 * @return <code>true</code> if a message strings exists,
235 * <code>false</code> otherwise
236 */
237 public boolean exists(String key, String bundle)
238 {
239 MessageResources res = getResources(bundle);
240 if (res == null)
241 {
242 return false;
243 }
244
245 // Return the requested message presence indicator
246 return res.isPresent(getLocale(), key);
247 }
248
249
250 /**
251 * Helper class to simplify tool usage when retrieving
252 * no-arg messages from the default bundle that have periods
253 * in their key.
254 *
255 * <p>So instead of <code>$text.get("forms.profile.title")</code>,1
256 * you can just type <code>$text.forms.profile.title</code>. Also,
257 * this lets you do things like:
258 * <pre>
259 * #if( $text.forms.profile.exists )
260 * #set( $profiletext = $text.forms.profile )
261 * <h1>$profiletext.title</h1>
262 * <h3>$profiletext.subtitle</h3>
263 * #end
264 * </pre>
265 * </p>
266 *
267 * @since VelocityTools 1.2
268 */
269 public class TextKey
270 {
271 private final String key;
272 private final String bundle;
273 private final Object[] args;
274 private final Locale locale;
275
276 /**
277 * @since VelocityTools 1.4
278 */
279 public TextKey(String key, String bundle,
280 Object[] args, Locale locale)
281 {
282 this.key = key;
283 this.bundle = bundle;
284 this.args = args;
285 this.locale = locale;
286 }
287
288 /**
289 * Appends a period and the new key to the current
290 * key and returns a new TextKey instance with the
291 * combined result as its key.
292 */
293 public TextKey get(String appendme)
294 {
295 StringBuilder sb = new StringBuilder(this.key);
296 sb.append('.');
297 sb.append(appendme);
298 return new TextKey(sb.toString(), this.bundle, this.args, this.locale);
299 }
300
301 /**
302 * Returns a new TextKey with the specified resource bundle set.
303 * @since VelocityTools 1.3
304 */
305 public TextKey bundle(String setme)
306 {
307 return new TextKey(this.key, setme, this.args, this.locale);
308 }
309
310 /**
311 * Returns a new TextKey with the specified resource bundle set.
312 * @since VelocityTools 1.4
313 */
314 public TextKey locale(Locale setme)
315 {
316 return new TextKey(this.key, this.bundle, this.args, setme);
317 }
318
319 /**
320 * Returns a new TextKey with the specified argument
321 * to be inserted into the text output. If arguments already
322 * exist for this TextKey, the new arguments will be appended
323 * to the old ones in the new TextKey that is returned.
324 *
325 * @since VelocityTools 1.3
326 */
327 public TextKey insert(Object addme)
328 {
329 return insert(new Object[] { addme });
330 }
331
332 /**
333 * Returns a new TextKey with the specified arguments
334 * to be inserted into the text output. If arguments already
335 * exist for this TextKey, the new arguments will be appended
336 * to the old ones in the new TextKey that is returned.
337 *
338 * @since VelocityTools 1.3
339 */
340 public TextKey insert(Object addme, Object metoo)
341 {
342 return insert(new Object[] { addme, metoo });
343 }
344
345 /**
346 * Returns a new TextKey with the specified arguments
347 * to be inserted into the text output. If arguments already
348 * exist for this TextKey, the new arguments will be appended
349 * to the old ones in the new TextKey that is returned.
350 *
351 * @since VelocityTools 1.3
352 */
353 public TextKey insert(Object addme, Object metoo, Object methree)
354 {
355 return insert(new Object[] { addme, metoo, methree });
356 }
357
358 /**
359 * Returns a new TextKey with the specified List of arguments
360 * to be inserted into the text output. If arguments already
361 * exist for this TextKey, the new arguments will be appended
362 * to the old ones in the new TextKey that is returned.
363 *
364 * @since VelocityTools 1.3
365 */
366 public TextKey insert(List addme)
367 {
368 // convert the list to an array
369 Object[] newargs = ((List)addme).toArray();
370 return insert(newargs);
371 }
372
373 /**
374 * Returns a new TextKey with the specified array of arguments
375 * to be inserted into the text output. If arguments already
376 * exist for this TextKey, the new arguments will be appended
377 * to the old ones in the new TextKey that is returned.
378 *
379 * @since VelocityTools 1.3
380 */
381 public TextKey insert(Object[] addme)
382 {
383 Object[] newargs;
384 if (this.args == null)
385 {
386 // we can just use the ones we're adding
387 newargs = addme;
388 }
389 else
390 {
391 // create the new array to hold both the new and old ones
392 newargs = new Object[this.args.length + addme.length];
393 // copy the old args into the newargs array
394 System.arraycopy(this.args, 0, newargs, 0, this.args.length);
395 // copy the args to be inserted into the newargs array
396 System.arraycopy(addme, 0, newargs, this.args.length, addme.length);
397 }
398 // return an new TextKey
399 return new TextKey(this.key, this.bundle, newargs, this.locale);
400 }
401
402 /**
403 * This will return a new TextKey that has <b>no</b> arguments to
404 * be inserted into the text output.
405 *
406 * @since VelocityTools 1.3
407 */
408 public TextKey clearArgs()
409 {
410 return new TextKey(this.key, this.bundle, null, this.locale);
411 }
412
413 /**
414 * Convenience method to allow <code>$text.key.exists</code> syntax.
415 * @since VelocityTools 1.3
416 */
417 public boolean getExists()
418 {
419 return exists();
420 }
421
422 /**
423 * Checks for the existence of the key that we've built up.
424 * @since VelocityTools 1.3
425 */
426 public boolean exists()
427 {
428 return MessageTool.this.exists(key, bundle);
429 }
430
431 /**
432 * Renders the text output according to the collected key value,
433 * bundle, and arguments.
434 */
435 public String toString()
436 {
437 return MessageTool.this.get(key, bundle, args, locale);
438 }
439 }
440
441 }