1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.cms.i18n;
35
36 import info.magnolia.cms.core.Content;
37 import info.magnolia.cms.core.NodeData;
38 import info.magnolia.cms.util.NodeDataUtil;
39 import info.magnolia.context.MgnlContext;
40
41 import java.util.Collection;
42 import java.util.HashSet;
43 import java.util.Iterator;
44 import java.util.LinkedHashMap;
45 import java.util.Locale;
46 import java.util.Map;
47 import java.util.Set;
48
49 import javax.jcr.Node;
50 import javax.jcr.RepositoryException;
51
52 import org.apache.commons.lang.StringUtils;
53 import org.slf4j.Logger;
54 import org.slf4j.LoggerFactory;
55
56
57
58
59
60
61
62
63
64
65 public abstract class AbstractI18nContentSupport implements I18nContentSupport {
66
67 private static final Logger log = LoggerFactory.getLogger(AbstractI18nContentSupport.class);
68
69
70
71
72 private Locale fallbackLocale = new Locale("en");
73
74
75
76
77 protected Locale defaultLocale;
78
79 private boolean enabled = false;
80
81
82
83
84 private Map<String, Locale> locales = new LinkedHashMap<String, Locale>();
85
86 @Override
87 public Locale getLocale() {
88 final Locale locale = MgnlContext.getAggregationState().getLocale();
89 if (locale == null) {
90 return fallbackLocale;
91 }
92 return locale;
93 }
94
95 @Override
96 public void setLocale(Locale locale) {
97 MgnlContext.getAggregationState().setLocale(locale);
98 }
99
100 @Override
101 public Locale getFallbackLocale() {
102 return this.fallbackLocale;
103 }
104
105 @Override
106 public void setFallbackLocale(Locale fallbackLocale) {
107 this.fallbackLocale = fallbackLocale;
108 }
109
110
111
112
113
114
115
116
117
118
119 protected Locale getNextLocale(Locale locale) {
120
121 if(StringUtils.isNotEmpty(locale.getCountry())){
122
123 Locale langOnlyLocale = new Locale(locale.getLanguage());
124 if(isLocaleSupported(langOnlyLocale)){
125 return langOnlyLocale;
126 }
127 }
128
129 for (Iterator<Locale> iter = getLocales().iterator(); iter.hasNext();) {
130 Locale otherCountryLocale = iter.next();
131
132 if(locale.getLanguage().equals(otherCountryLocale.getLanguage()) && !locale.equals(otherCountryLocale)){
133 return otherCountryLocale;
134 }
135 }
136 return getFallbackLocale();
137 }
138
139
140
141
142 @Override
143 public Locale determineLocale() {
144 Locale locale;
145
146 locale = onDetermineLocale();
147
148
149 if(locale == null){
150 locale = getDefaultLocale();
151 }
152
153 if(!isLocaleSupported(locale)){
154 locale = getNextLocale(locale);
155 }
156
157
158 if(locale.equals(getFallbackLocale())){
159 locale = getDefaultLocale();
160 }
161 return locale;
162 }
163
164 protected abstract Locale onDetermineLocale();
165
166 protected static Locale determineLocalFromString(String localeStr) {
167 if(StringUtils.isNotEmpty(localeStr)){
168 String[] localeArr = StringUtils.split(localeStr, "_");
169 if(localeArr.length ==1){
170 return new Locale(localeArr[0]);
171 }
172 else if(localeArr.length == 2){
173 return new Locale(localeArr[0],localeArr[1]);
174 }
175 }
176 return null;
177 }
178
179 @Override
180 public String toI18NURI(String uri) {
181 if (!isEnabled()) {
182 return uri;
183 }
184 Locale locale = getLocale();
185 if (isLocaleSupported(locale)) {
186 return toI18NURI(uri, locale);
187 }
188 return uri;
189 }
190
191 protected abstract String toI18NURI(String uri, Locale locale);
192
193
194
195
196 @Override
197 public String toRawURI(String i18nURI) {
198 if (!isEnabled()) {
199 return i18nURI;
200 }
201
202 Locale locale = getLocale();
203 if (isLocaleSupported(locale)) {
204 return toRawURI(i18nURI, locale);
205 }
206 return i18nURI;
207 }
208
209 protected abstract String toRawURI(String i18nURI, Locale locale);
210
211 @Override
212 public NodeData getNodeData(Content node, String name, Locale locale) throws RepositoryException {
213 String nodeDataName = name + "_" + locale;
214 if (node.hasNodeData(nodeDataName)) {
215 return node.getNodeData(nodeDataName);
216 }
217 return null;
218 }
219
220
221
222
223
224 @Override
225 public NodeData getNodeData(Content node, String name) {
226 NodeData nd = null;
227
228 if (isEnabled()) {
229 try {
230
231 Locale locale = getLocale();
232 Set<Locale> checkedLocales = new HashSet<Locale>();
233
234
235 while(locale != null){
236 nd = getNodeData(node, name, locale);
237 if (!isEmpty(nd)) {
238 return nd;
239 }
240 checkedLocales.add(locale);
241 locale = getNextContentLocale(locale, checkedLocales);
242 }
243 }
244 catch (RepositoryException e) {
245 log.error("can't read i18n nodeData " + name + " from node " + node, e);
246 }
247 }
248
249
250 return node.getNodeData(name);
251 }
252
253 @Override
254 public Node getNode(Node node, String name) throws RepositoryException {
255 if (isEnabled()) {
256
257 try {
258
259 Locale locale = getLocale();
260 Set<Locale> checkedLocales = new HashSet<Locale>();
261
262
263 while(locale != null){
264 String localeSpecificChildName = name + "_" + locale;
265 if (node.hasNode(localeSpecificChildName))
266 return node.getNode(localeSpecificChildName);
267 checkedLocales.add(locale);
268 locale = getNextContentLocale(locale, checkedLocales);
269 }
270 }
271 catch (RepositoryException e) {
272 log.error("can't read i18n node " + name + " from node " + node, e);
273 }
274 }
275
276 return node.getNode(name);
277 }
278
279
280
281
282
283
284 protected Locale getNextContentLocale(Locale locale, Set<Locale> checkedLocales) {
285 if(locale.equals(getFallbackLocale())){
286 return null;
287 }
288 Locale candidate = getNextLocale(locale);
289 if(!checkedLocales.contains(candidate)){
290 return candidate;
291 }
292 return getFallbackLocale();
293 }
294
295 @Override
296 public boolean isEnabled() {
297 return this.enabled;
298 }
299
300 public void setEnabled(boolean enabled) {
301 this.enabled = enabled;
302 }
303
304 @Override
305 public Collection<Locale> getLocales() {
306 return this.locales.values();
307 }
308
309 public void addLocale(LocaleDefinition ld) {
310 if (ld.isEnabled()) {
311 this.locales.put(ld.getId(), ld.getLocale());
312 }
313 }
314
315 protected boolean isLocaleSupported(Locale locale) {
316 return locale != null && locales.containsKey(locale.toString());
317 }
318
319
320
321
322 protected boolean isEmpty(NodeData nd) {
323 if (nd != null && nd.isExist()) {
324
325 return StringUtils.isEmpty(NodeDataUtil.getValueString(nd));
326 }
327 return true;
328 }
329
330 public Locale getDefaultLocale() {
331 if(this.defaultLocale == null){
332 return getFallbackLocale();
333 }
334 return this.defaultLocale;
335 }
336
337 public void setDefaultLocale(Locale defaultLocale) {
338 this.defaultLocale = defaultLocale;
339 }
340 }