You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rave.apache.org by sc...@apache.org on 2011/04/13 23:54:22 UTC
svn commit: r1091930 - in /incubator/rave/trunk/rave-portal: ./
src/main/java/org/apache/rave/portal/web/model/
src/main/java/org/apache/rave/portal/web/model/util/
src/main/java/org/apache/rave/portal/web/util/ src/test/java/org/
src/test/java/org/apa...
Author: scottbw
Date: Wed Apr 13 21:54:21 2011
New Revision: 1091930
URL: http://svn.apache.org/viewvc?rev=1091930&view=rev
Log:
Added basic localization support for international strings, and included in the Page and Widget models
Added:
incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/
incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/InternationalString.java
incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/LocalizedString.java
incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/util/
incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/util/LocalizationUtils.java
incubator/rave/trunk/rave-portal/src/test/java/org/
incubator/rave/trunk/rave-portal/src/test/java/org/apache/
incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/
incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/
incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/web/
incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/web/model/
incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/web/model/util/
incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/web/model/util/InternationalStringTest.java
Modified:
incubator/rave/trunk/rave-portal/pom.xml
incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Page.java
incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Widget.java
Modified: incubator/rave/trunk/rave-portal/pom.xml
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal/pom.xml?rev=1091930&r1=1091929&r2=1091930&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal/pom.xml (original)
+++ incubator/rave/trunk/rave-portal/pom.xml Wed Apr 13 21:54:21 2011
@@ -96,6 +96,20 @@
<artifactId>log4j</artifactId>
</dependency>
+ <dependency>
+ <groupId>com.ibm.icu</groupId>
+ <artifactId>icu4j</artifactId>
+ <version>4.6.1</version>
+ <type>jar</type>
+ <scope>compile</scope>
+ </dependency>
+ <dependency>
+ <groupId>commons-lang</groupId>
+ <artifactId>commons-lang</artifactId>
+ <version>2.6</version>
+ <type>jar</type>
+ <scope>compile</scope>
+ </dependency>
</dependencies>
<build>
Modified: incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Page.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Page.java?rev=1091930&r1=1091929&r2=1091930&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Page.java (original)
+++ incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Page.java Wed Apr 13 21:54:21 2011
@@ -20,6 +20,8 @@ package org.apache.rave.portal.web.model
import java.util.List;
+import org.apache.rave.portal.web.model.util.InternationalString;
+
/**
* A page, which consists of regions, and which may be owned by a user (or other principal)
*/
@@ -39,9 +41,9 @@ public interface Page {
*
* @return valid name
*/
- String getName();
+ InternationalString getName();
- void setName(String name);
+ void setName(InternationalString name);
/**
* Get the principal that owns the page and the widgets on it
Modified: incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Widget.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Widget.java?rev=1091930&r1=1091929&r2=1091930&view=diff
==============================================================================
--- incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Widget.java (original)
+++ incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/Widget.java Wed Apr 13 21:54:21 2011
@@ -18,13 +18,15 @@
*/
package org.apache.rave.portal.web.model;
+import org.apache.rave.portal.web.model.util.InternationalString;
+
/**
* A widget
*/
public interface Widget {
- String getTitle(String locale);
+ InternationalString getTitle();
- void setTitle(String title, String locale);
+ void setTitle(InternationalString title);
}
Added: incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/InternationalString.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/InternationalString.java?rev=1091930&view=auto
==============================================================================
--- incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/InternationalString.java (added)
+++ incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/InternationalString.java Wed Apr 13 21:54:21 2011
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rave.portal.web.model.util;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.rave.portal.web.util.LocalizationUtils;
+
+/**
+ * a String that has been internationalized into several Locales. This class is used as a replacement for the String type whenever a
+ * String needs to be i18nn-capable. An instance of the InternationalString interface composes within it an ArrayList of LocalizedString instances,
+ * where each String is specific to a particular Locale.
+ *
+ * Note: See also the javax.xml.registry.infomodel.InternationalString interface, which uses a similar approach
+ *
+ */
+public class InternationalString {
+
+ /**
+ * Default constructor
+ */
+ public InternationalString(){
+ this.localizedStrings = new ArrayList<LocalizedString>();
+ }
+
+ /**
+ * The collection of localized strings representing the different
+ * versions of the string for particular language-tags.
+ */
+ private ArrayList<LocalizedString> localizedStrings;
+
+
+ public LocalizedString getDefaultLocalizedString(){
+ return LocalizationUtils.getLocalizedElement(this.localizedStrings.toArray(new LocalizedString[this.localizedStrings.size()]), null);
+ }
+
+ /**
+ * Return the localized string that is the best match for the given locale
+ * @param locale
+ * @return a string best matching the locale, or null if no string matches
+ */
+ public LocalizedString getLocalizedString(String locale){
+ return getLocalizedString(new String[]{locale});
+ }
+
+ /**
+ * Return the localized string that is the best match for the given array of locales
+ * @param locales
+ * @return a string best matching the locales, or null if no string matches
+ */
+ public LocalizedString getLocalizedString(String[] locales){
+ return LocalizationUtils.getLocalizedElement(this.localizedStrings.toArray(new LocalizedString[this.localizedStrings.size()]), locales);
+ }
+
+ /**
+ * Returns all the localized strings for this object
+ * @return a List containing localized strings
+ */
+ public List<LocalizedString> getLocalizedStrings(){
+ return this.localizedStrings;
+ }
+
+ /**
+ * Set a single localized string
+ * @param localizedString
+ */
+ public void setLocalizedString(LocalizedString localizedString){
+ this.localizedStrings.add(localizedString);
+ }
+
+ /**
+ * Adds many localized strings
+ * @param localizedStrings
+ */
+ public void setLocalizedStrings(List<LocalizedString> localizedStrings){
+ this.localizedStrings.addAll(localizedStrings);
+ }
+
+ /**
+ * Remove a single localized string
+ * @param localizedString
+ */
+ public void removeLocalizedString(LocalizedString localizedString){
+ this.localizedStrings.remove(localizedString);
+ }
+
+ /**
+ * Remove many localized strings
+ * @param localizedStrings
+ */
+ public void removeLocalizedStrings(List<LocalizedString> localizedStrings){
+ this.localizedStrings.removeAll(localizedStrings);
+ }
+
+
+}
Added: incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/LocalizedString.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/LocalizedString.java?rev=1091930&view=auto
==============================================================================
--- incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/LocalizedString.java (added)
+++ incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/model/util/LocalizedString.java Wed Apr 13 21:54:21 2011
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rave.portal.web.model.util;
+
+/**
+ * A String localized for a specific language-tag
+ */
+public class LocalizedString {
+
+ /**
+ * Default constructor
+ */
+ public LocalizedString(){
+ }
+
+ public LocalizedString(String value, String lang){
+ this.value = value;
+ this.lang = lang;
+ }
+
+ /**
+ * The value of the String
+ */
+ private String value;
+
+ /**
+ * The BCP-47 language tag
+ */
+ private String lang;
+
+ public String getValue() {
+ return value;
+ }
+
+ public void setValue(String value) {
+ this.value = value;
+ }
+
+ public String getLang() {
+ return lang;
+ }
+
+ public void setLang(String lang) {
+ this.lang = lang;
+ }
+
+
+
+}
Added: incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/util/LocalizationUtils.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/util/LocalizationUtils.java?rev=1091930&view=auto
==============================================================================
--- incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/util/LocalizationUtils.java (added)
+++ incubator/rave/trunk/rave-portal/src/main/java/org/apache/rave/portal/web/util/LocalizationUtils.java Wed Apr 13 21:54:21 2011
@@ -0,0 +1,200 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rave.portal.web.util;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+
+import org.apache.commons.lang.ArrayUtils;
+import org.apache.log4j.Logger;
+import org.apache.rave.portal.web.model.util.LocalizedString;
+
+import com.ibm.icu.util.GlobalizationPreferences;
+import com.ibm.icu.util.ULocale;
+
+/**
+ * Utilities for localization (adapted from org.apache.wookie.w3c.util.LocalizationUtils.java)
+ */
+public class LocalizationUtils {
+ static Logger _logger = Logger.getLogger(LocalizationUtils.class.getName());
+
+ /**
+ * Returns the first (best) match for an element given the set of locales, or null
+ * if there are no suitable elements.
+ * @param elements
+ * @param locales
+ * @return a LocalizedString, or null if there are no valid entries
+ */
+ public static LocalizedString getLocalizedElement(LocalizedString[] elements,String[] locales){
+ if (elements == null) return null;
+ elements = processElementsByLocales(elements,locales);
+ if (elements.length == 0) return null;
+ return elements[0];
+ }
+
+ /**
+ * Filters and sorts a list of localized elements using the given locale list; only localized elements
+ * are returned unless no appropriate localized elements are found, in which case nonlocalized elements
+ * are returned
+ *
+ * @param elements
+ * @param locales
+ * @return the sorted and filtered set of elements
+ */
+ public static LocalizedString[] processElementsByLocales(LocalizedString[] elements,String[] locales){
+ if (elements == null) return null;
+ List<ULocale> localesList = getProcessedLocaleList(locales);
+ Arrays.sort(elements, new LocaleComparator(localesList));
+ return filter(elements,localesList);
+ }
+
+ /**
+ * Sorts an array of localized elements using default locales (*). This places
+ * any localized elements first, then any unlocalized elements
+ * @return a sorted array of LocalizedString objects
+ */
+ public static LocalizedString[] processElementsByDefaultLocales(LocalizedString[] elements){
+ if (elements == null) return null;
+ List<ULocale> localesList = getDefaultLocaleList();
+ Arrays.sort(elements, new LocaleComparator(localesList));
+ return filter(elements,localesList);
+ }
+
+ /**
+ * Comparator that sorts elements based on priority in the given locale list,
+ * with the assumption that earlier in the list means a higher priority.
+ */
+ static class LocaleComparator implements Comparator<LocalizedString>{
+ private List<ULocale> locales;
+ public LocaleComparator(List<ULocale> locales){
+ this.locales = locales;
+ }
+ public int compare(LocalizedString o1, LocalizedString o2) {
+ // check non-localized values for comparison
+ if (o1.getLang()!=null && o2.getLang() == null) return -1;
+ if (o1.getLang()==null && o2.getLang()!= null) return 1;
+ if (o1.getLang()==null && o2.getLang()==null) return 0;
+
+ // get index position of locales
+ int o1i = -1;
+ int o2i = -1;
+ for (int i=0;i<locales.size();i++){
+ if (o1.getLang().equalsIgnoreCase(locales.get(i).toLanguageTag())) o1i = i;
+ if (o2.getLang().equalsIgnoreCase(locales.get(i).toLanguageTag())) o2i = i;
+ }
+ // put non-matched after matched
+ if (o1i == -1 && o2i > -1) return 1;
+ if (o1i > -1 && o2i == -1) return -1;
+
+ // order by match
+ return o1i - o2i;
+ }
+ }
+
+ /**
+ * Filters a set of elements using the locales and returns a copy of the array
+ * containing only elements that match the locales, or that are not localized
+ * if there are no matches
+ * @param elements
+ * @param locales
+ * @return a copy of the array of elements only containing the filtered elements
+ */
+ protected static LocalizedString[] filter(LocalizedString[] elements, List<ULocale> locales){
+ for (LocalizedString element:elements){
+ String lang = element.getLang();
+ boolean found = false;
+ for(ULocale locale:locales){
+ if (locale.toLanguageTag().equalsIgnoreCase(lang)) found = true;
+ }
+ if (!found && lang != null) elements = (LocalizedString[])ArrayUtils.removeElement(elements, element);
+ }
+ // Strip out non-localized elements only if there are localized elements left
+ if (elements.length > 0){
+ if (elements[0].getLang() != null){
+ for (LocalizedString element:elements){
+ if (element.getLang()==null) elements = (LocalizedString[])ArrayUtils.removeElement(elements, element);
+ }
+ }
+ }
+ return elements;
+ }
+
+
+ /**
+ * Converts an array of language tags to a list of ULocale instances
+ * ordered according to priority, availability and fallback
+ * rules. For example "en-us-posix" will be returned as a List
+ * containing the ULocales for "en-us-posix", "en-us", and "en".
+ * @param locales
+ * @return
+ */
+ public static List<ULocale> getProcessedLocaleList(String[] locales){
+ if (locales == null) return getDefaultLocaleList();
+ GlobalizationPreferences prefs = new GlobalizationPreferences();
+
+ ArrayList<ULocale> ulocales = new ArrayList<ULocale>();
+ for (String locale:locales){
+ if (locale != null){
+ try {
+ ULocale ulocale = ULocale.forLanguageTag(locale);
+ if (!ulocale.getLanguage().equals(""))
+ ulocales.add(ulocale);
+ } catch (Exception e) {
+ // There can be intermittent problems with the internal
+ // functioning of the ULocale class with some
+ // language tags; best to just log these and continue
+ _logger.error("icu4j:ULocale.forLanguageTag("+locale+") threw Exception:",e);
+ }
+ }
+ }
+ if (ulocales.isEmpty()) return getDefaultLocaleList();
+ prefs.setLocales(ulocales.toArray(new ULocale[ulocales.size()]));
+ return prefs.getLocales();
+ }
+
+ /**
+ * Gets the default locales list
+ * @return
+ */
+ protected static List<ULocale> getDefaultLocaleList(){
+ GlobalizationPreferences prefs = new GlobalizationPreferences();
+ return prefs.getLocales();
+ }
+
+ /**
+ * Validates a given language tag. Empty and null values are considered false.
+ * @param tag
+ * @return true if a valid language tag, otherwise false
+ */
+ public static boolean isValidLanguageTag(String tag){
+ try {
+ ULocale locale = ULocale.forLanguageTag(tag);
+ if (locale.toLanguageTag() == null) return false;
+ // We don't accept "x" extensions (private use tags)
+ if(locale.getExtension("x".charAt(0))!=null) return false;
+ if (!locale.toLanguageTag().equalsIgnoreCase(tag)) return false;
+ return true;
+ } catch (Exception e) {
+ return false;
+ }
+ }
+
+}
Added: incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/web/model/util/InternationalStringTest.java
URL: http://svn.apache.org/viewvc/incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/web/model/util/InternationalStringTest.java?rev=1091930&view=auto
==============================================================================
--- incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/web/model/util/InternationalStringTest.java (added)
+++ incubator/rave/trunk/rave-portal/src/test/java/org/apache/rave/portal/web/model/util/InternationalStringTest.java Wed Apr 13 21:54:21 2011
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.rave.portal.web.model.util;
+
+import static org.junit.Assert.assertEquals;
+
+import org.junit.Test;
+import com.ibm.icu.util.GlobalizationPreferences;
+
+public class InternationalStringTest {
+
+ @Test
+ public void twoLanguages(){
+ InternationalString internationalString = new InternationalString();
+ internationalString.setLocalizedString(new LocalizedString("Hello World","en"));
+ internationalString.setLocalizedString(new LocalizedString("ä½ å¥½ä¸ç","cn"));
+
+ assertEquals("ä½ å¥½ä¸ç", internationalString.getLocalizedString("cn").getValue());
+ assertEquals("Hello World", internationalString.getLocalizedString("en").getValue());
+ }
+
+ @Test
+ public void defaultLocale(){
+ GlobalizationPreferences prefs = new GlobalizationPreferences();
+
+ InternationalString internationalString = new InternationalString();
+ internationalString.setLocalizedString(new LocalizedString("Hello World","en"));
+ internationalString.setLocalizedString(new LocalizedString("Hallo Wereld","nl"));
+ internationalString.setLocalizedString(new LocalizedString("ä½ å¥½ä¸ç","cn"));
+
+ // The actual test depends on the system default locale
+ String defaultLocale = prefs.getLocale(0).toLanguageTag();
+ if (defaultLocale.contains("cn"))
+ assertEquals("ä½ å¥½ä¸ç", internationalString.getDefaultLocalizedString().getValue());
+ if (defaultLocale.equals("nl"))
+ assertEquals("Hallo Wereld", internationalString.getDefaultLocalizedString().getValue());
+ if (defaultLocale.contains("en"))
+ assertEquals("Hello World", internationalString.getDefaultLocalizedString().getValue());
+ }
+
+ @Test
+ public void noLocalizedStrings(){
+ InternationalString internationalString = new InternationalString();
+ assertEquals(null, internationalString.getLocalizedString("cn"));
+ }
+
+ @Test
+ public void noMatch(){
+ InternationalString internationalString = new InternationalString();
+ internationalString.setLocalizedString(new LocalizedString("Hello World","en"));
+ assertEquals(null, internationalString.getLocalizedString("cn"));
+ }
+
+ /**
+ * This tests that we can use a "default" non-localized string as a last-resort fallback
+ */
+ @Test
+ public void nonLocalizedFallback(){
+ InternationalString internationalString = new InternationalString();
+ internationalString.setLocalizedString(new LocalizedString("Hello World",null));
+ assertEquals("Hello World", internationalString.getLocalizedString("cn").getValue());
+ }
+
+ @Test
+ public void fallback(){
+ InternationalString internationalString = new InternationalString();
+ internationalString.setLocalizedString(new LocalizedString("Hello World","en"));
+ internationalString.setLocalizedString(new LocalizedString("Hi World","en-us"));
+ internationalString.setLocalizedString(new LocalizedString("How Do You Do World","en-gb"));
+
+ assertEquals("Hello World", internationalString.getLocalizedString("en").getValue());
+ assertEquals("How Do You Do World", internationalString.getLocalizedString("en-gb").getValue());
+ assertEquals("Hi World", internationalString.getLocalizedString("en-us").getValue());
+ assertEquals("Hello World", internationalString.getLocalizedString("en-za").getValue());
+ assertEquals("Hi World", internationalString.getLocalizedString("en-us-posix").getValue());
+ }
+
+
+}