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 import info.magnolia.jcr.util.PropertyUtil;
41
42 import java.util.Collection;
43 import java.util.HashSet;
44 import java.util.Iterator;
45 import java.util.LinkedHashMap;
46 import java.util.Locale;
47 import java.util.Map;
48 import java.util.Set;
49
50 import javax.jcr.Node;
51 import javax.jcr.Property;
52 import javax.jcr.RepositoryException;
53
54 import org.apache.commons.lang.StringUtils;
55 import org.slf4j.Logger;
56 import org.slf4j.LoggerFactory;
57
58
59
60
61
62
63
64
65
66
67 public abstract class AbstractI18nContentSupport implements I18nContentSupport {
68
69 private static final Logger log = LoggerFactory.getLogger(AbstractI18nContentSupport.class);
70
71
72
73
74 private Locale fallbackLocale = new Locale("en");
75
76
77
78
79 protected Locale defaultLocale;
80
81 private boolean enabled = false;
82
83
84
85
86 private final Map<String, Locale> locales = new LinkedHashMap<String, Locale>();
87
88 @Override
89 public Locale getLocale() {
90 Locale locale = null;
91 if(MgnlContext.getWebContextOrNull() != null){
92 locale = MgnlContext.getAggregationState().getLocale();
93 }
94 if (locale == null) {
95 return fallbackLocale;
96 }
97 return locale;
98 }
99
100 @Override
101 public void setLocale(Locale locale) {
102 MgnlContext.getAggregationState().setLocale(locale);
103 }
104
105 @Override
106 public Locale getFallbackLocale() {
107 return this.fallbackLocale;
108 }
109
110 @Override
111 public void setFallbackLocale(Locale fallbackLocale) {
112 this.fallbackLocale = fallbackLocale;
113 }
114
115
116
117
118
119
120
121
122
123
124 protected Locale getNextLocale(Locale locale) {
125
126 if(StringUtils.isNotEmpty(locale.getCountry())){
127
128 Locale langOnlyLocale = new Locale(locale.getLanguage());
129 if(isLocaleSupported(langOnlyLocale)){
130 return langOnlyLocale;
131 }
132 }
133
134 for (Iterator<Locale> iter = getLocales().iterator(); iter.hasNext();) {
135 Locale otherCountryLocale = iter.next();
136
137 if(locale.getLanguage().equals(otherCountryLocale.getLanguage()) && !locale.equals(otherCountryLocale)){
138 return otherCountryLocale;
139 }
140 }
141 return getFallbackLocale();
142 }
143
144
145
146
147 @Override
148 public Locale determineLocale() {
149 Locale locale;
150
151 locale = onDetermineLocale();
152
153
154 if(locale == null){
155 locale = getDefaultLocale();
156 }
157
158 if(!isLocaleSupported(locale)){
159 locale = getNextLocale(locale);
160 }
161
162
163 if(locale.equals(getFallbackLocale())){
164 locale = getDefaultLocale();
165 }
166 return locale;
167 }
168
169 protected abstract Locale onDetermineLocale();
170
171 protected static Locale determineLocalFromString(String localeStr) {
172 if(StringUtils.isNotEmpty(localeStr)){
173 String[] localeArr = StringUtils.split(localeStr, "_");
174 if(localeArr.length ==1){
175 return new Locale(localeArr[0]);
176 }
177 else if(localeArr.length == 2){
178 return new Locale(localeArr[0],localeArr[1]);
179 }
180 }
181 return null;
182 }
183
184 @Override
185 public String toI18NURI(String uri) {
186 if (!isEnabled()) {
187 return uri;
188 }
189 Locale locale = getLocale();
190 if (isLocaleSupported(locale)) {
191 return toI18NURI(uri, locale);
192 }
193 return uri;
194 }
195
196 protected abstract String toI18NURI(String uri, Locale locale);
197
198
199
200
201 @Override
202 public String toRawURI(String i18nURI) {
203 if (!isEnabled()) {
204 return i18nURI;
205 }
206
207 Locale locale = getLocale();
208 if (isLocaleSupported(locale)) {
209 return toRawURI(i18nURI, locale);
210 }
211 return i18nURI;
212 }
213
214 protected abstract String toRawURI(String i18nURI, Locale locale);
215
216 @Override
217 public NodeData getNodeData(Content node, String name, Locale locale) throws RepositoryException {
218 String nodeDataName = name + "_" + locale;
219 if (node.hasNodeData(nodeDataName)) {
220 return node.getNodeData(nodeDataName);
221 }
222 return null;
223 }
224
225
226
227
228
229 @Override
230 public NodeData getNodeData(Content node, String name) {
231 NodeData nd = null;
232
233 if (isEnabled()) {
234 try {
235
236 Locale locale = getLocale();
237 Set<Locale> checkedLocales = new HashSet<Locale>();
238
239
240 while(locale != null){
241 nd = getNodeData(node, name, locale);
242 if (!isEmpty(nd)) {
243 return nd;
244 }
245 checkedLocales.add(locale);
246 locale = getNextContentLocale(locale, checkedLocales);
247 }
248 }
249 catch (RepositoryException e) {
250 log.error("can't read i18n nodeData " + name + " from node " + node, e);
251 }
252 }
253
254
255 return node.getNodeData(name);
256 }
257
258 @Override
259 public Node getNode(Node node, String name) throws RepositoryException {
260 if (isEnabled()) {
261
262 try {
263
264 Locale locale = getLocale();
265 Set<Locale> checkedLocales = new HashSet<Locale>();
266
267
268 while(locale != null){
269 String localeSpecificChildName = name + "_" + locale;
270 if (node.hasNode(localeSpecificChildName)) {
271 return node.getNode(localeSpecificChildName);
272 }
273 checkedLocales.add(locale);
274 locale = getNextContentLocale(locale, checkedLocales);
275 }
276 }
277 catch (RepositoryException e) {
278 log.error("can't read i18n node " + name + " from node " + node, e);
279 }
280 }
281
282 return node.getNode(name);
283 }
284
285 @Override
286 public boolean hasProperty(Node node, String name) throws RepositoryException {
287 if (!isEnabled()) {
288 return node.hasProperty(name);
289 }
290 try {
291
292 getProperty(node, name);
293 } catch (RepositoryException e) {
294 return false;
295 }
296 return true;
297 }
298
299 @Override
300 public Property getProperty(Node node, String name) throws RepositoryException {
301 if (!isEnabled()) {
302 return node.getProperty(name);
303 }
304 try {
305
306 Locale locale = getLocale();
307 Set<Locale> checkedLocales = new HashSet<Locale>();
308
309
310 while (locale != null) {
311 Property property = getProperty(node, name, locale);
312 if (!isEmpty(property)) {
313 return property;
314 }
315 checkedLocales.add(locale);
316 locale = getNextContentLocale(locale, checkedLocales);
317 }
318 } catch (RepositoryException e) {
319 log.error("can't read i18n nodeData " + name + " from node " + node, e);
320 }
321
322
323 return node.getProperty(name);
324 }
325
326 @Override
327 public Property getProperty(Node node, String name, Locale locale) throws RepositoryException {
328 String propName = name + "_" + locale;
329 if (node.hasProperty(propName)) {
330 return node.getProperty(propName);
331 }
332 return null;
333 }
334
335
336
337
338
339
340 protected Locale getNextContentLocale(Locale locale, Set<Locale> checkedLocales) {
341 if(locale.equals(getFallbackLocale())){
342 return null;
343 }
344 Locale candidate = getNextLocale(locale);
345 if(!checkedLocales.contains(candidate)){
346 return candidate;
347 }
348 return getFallbackLocale();
349 }
350
351 @Override
352 public boolean isEnabled() {
353 return this.enabled;
354 }
355
356 public void setEnabled(boolean enabled) {
357 this.enabled = enabled;
358 }
359
360 @Override
361 public Collection<Locale> getLocales() {
362 return this.locales.values();
363 }
364
365 public void setLocales(Map<String, Locale> locales) {
366 this.locales.putAll(locales);
367 }
368
369 public void addLocale(LocaleDefinition ld) {
370 if (ld.isEnabled()) {
371 this.locales.put(ld.getId(), ld.getLocale());
372 }
373 }
374
375 protected boolean isLocaleSupported(Locale locale) {
376 return locale != null && locales.containsKey(locale.toString());
377 }
378
379
380
381
382
383
384 @Deprecated
385 protected boolean isEmpty(NodeData nd) {
386 if (nd != null && nd.isExist()) {
387
388 return StringUtils.isEmpty(NodeDataUtil.getValueString(nd));
389 }
390 return true;
391 }
392
393
394
395
396 protected boolean isEmpty(Property nd) {
397 if (nd != null) {
398 return StringUtils.isEmpty(PropertyUtil.getValueString(nd));
399 }
400 return true;
401 }
402
403 public Locale getDefaultLocale() {
404 if(this.defaultLocale == null){
405 return getFallbackLocale();
406 }
407 return this.defaultLocale;
408 }
409
410 public void setDefaultLocale(Locale defaultLocale) {
411 this.defaultLocale = defaultLocale;
412 }
413 }