1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.struts2.components;
23
24 import java.io.Writer;
25 import java.util.Locale;
26 import java.util.ResourceBundle;
27
28 import org.apache.struts2.views.annotations.StrutsTag;
29 import org.apache.struts2.views.annotations.StrutsTagAttribute;
30 import org.apache.struts2.StrutsException;
31
32 import com.opensymphony.xwork2.ActionContext;
33 import com.opensymphony.xwork2.LocaleProvider;
34 import com.opensymphony.xwork2.TextProviderFactory;
35 import com.opensymphony.xwork2.TextProvider;
36 import com.opensymphony.xwork2.inject.Container;
37 import com.opensymphony.xwork2.inject.Inject;
38 import com.opensymphony.xwork2.util.LocalizedTextUtil;
39 import com.opensymphony.xwork2.util.ValueStack;
40 import com.opensymphony.xwork2.util.logging.Logger;
41 import com.opensymphony.xwork2.util.logging.LoggerFactory;
42
43 /***
44 * <!-- START SNIPPET: javadoc -->
45 *
46 * Gets a resource bundle and place it on the value stack. This allows
47 * the text tag to access messages from any bundle, and not just the bundle
48 * associated with the current action.
49 *
50 * <!-- END SNIPPET: javadoc -->
51 *
52 * <p/>
53 *
54 * <!-- START SNIPPET: params-->
55 *
56 * <ul>
57 * <li>name* - the resource bundle's name (eg foo/bar/customBundle)</li>
58 * </ul>
59 *
60 * <!-- END SNIPPET: params -->
61 *
62 * <p/>
63 *
64 * Example:
65 *
66 * <pre>
67 * <!-- START SNIPPET: example -->
68 *
69 * <s:i18n name="myCustomBundle">
70 * The i18n value for key aaa.bbb.ccc in myCustomBundle is <s:property value="text('aaa.bbb.ccc')" />
71 * </s:i18n>
72 *
73 * <!-- END SNIPPET: example -->
74 * </pre>
75 *
76 *
77 * <pre>
78 * <!-- START SNIPPET: i18nExample -->
79 *
80 * <s:i18n name="some.package.bundle" >
81 * <s:text name="some.key" />
82 * </s:i18n>
83 *
84 * <!-- END SNIPPET: i18nExample -->
85 * </pre>
86 *
87 */
88 @StrutsTag(name="i18n", tldTagClass="org.apache.struts2.views.jsp.I18nTag", description="Get a resource bundle" +
89 " and place it on the value stack")
90 public class I18n extends Component {
91
92 private static final Logger LOG = LoggerFactory.getLogger(I18n.class);
93
94 protected boolean pushed;
95 protected String name;
96 protected Container container;
97 private TextProvider textProvider;
98
99 public I18n(ValueStack stack) {
100 super(stack);
101 }
102
103 @Inject
104 public void setContainer(Container container) {
105 this.container = container;
106 }
107
108 public boolean start(Writer writer) {
109 boolean result = super.start(writer);
110
111 try {
112 String name = this.findString(this.name, "name", "Resource bundle name is required. Example: foo or foo_en");
113 ResourceBundle bundle = (ResourceBundle) findValue("getTexts('" + name + "')");
114
115 if (bundle == null) {
116 bundle = LocalizedTextUtil.findResourceBundle(name, (Locale) getStack().getContext().get(ActionContext.LOCALE));
117 }
118
119 if (bundle != null) {
120 final Locale locale = (Locale) getStack().getContext().get(ActionContext.LOCALE);
121 TextProviderFactory tpf = new TextProviderFactory();
122 container.inject(tpf);
123 textProvider = tpf.createInstance(bundle, new LocaleProvider() {
124 public Locale getLocale() {
125 return locale;
126 }
127 });
128 getStack().push(textProvider);
129 pushed = true;
130 }
131 } catch (Exception e) {
132 String msg = "Could not find the bundle " + name;
133 throw new StrutsException(msg, e);
134 }
135
136 return result;
137 }
138
139 public boolean end(Writer writer, String body) throws StrutsException {
140 if (pushed) {
141 Object o = getStack().pop();
142 if ((o == null) || (!o.equals(textProvider))) {
143 LOG.error("A closing i18n tag attempted to pop its own TextProvider from the top of the ValueStack but popped an unexpected object ("+(o != null ? o.getClass() : "null")+"). " +
144 "Refactor the page within the i18n tags to ensure no objects are pushed onto the ValueStack without popping them prior to the closing tag. " +
145 "If you see this message it's likely that the i18n's TextProvider is still on the stack and will continue to provide message resources after the closing tag.");
146 throw new StrutsException("A closing i18n tag attempted to pop its TextProvider from the top of the ValueStack but popped an unexpected object ("+(o != null ? o.getClass() : "null")+")");
147 }
148 }
149
150 return super.end(writer, body);
151 }
152
153 @StrutsTagAttribute(description="Name of resource bundle to use (eg foo/bar/customBundle)", required=true, defaultValue="String")
154 public void setName(String name) {
155 this.name = name;
156 }
157 }