=== modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/i18n/locale/I18nLocale.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/i18n/locale/I18nLocale.java 2013-10-01 16:44:42 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/i18n/locale/I18nLocale.java 2013-10-06 07:45:05 +0000 @@ -32,9 +32,7 @@ public class I18nLocale extends BaseIdentifiableObject -{ - private String name; - +{ private String locale; // ------------------------------------------------------------------------- @@ -43,7 +41,7 @@ public I18nLocale() { - this.name = "English, United Kingdom"; + this.name = "English (United Kingdom)"; this.locale = "en_GB"; } @@ -57,16 +55,6 @@ // Getters and setters // ------------------------------------------------------------------------- - public String getName() - { - return name; - } - - public void setName( String name ) - { - this.name = name; - } - public String getLocale() { return locale; === modified file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/translation/Translation.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/translation/Translation.java 2013-10-01 16:44:42 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/translation/Translation.java 2013-10-06 07:45:05 +0000 @@ -69,6 +69,15 @@ } // ------------------------------------------------------------------------- + // Logic + // ------------------------------------------------------------------------- + + public String getClassIdPropKey() + { + return className + "-" + id + "-" + property; + } + + // ------------------------------------------------------------------------- // Getters and setters // ------------------------------------------------------------------------- === added directory 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/translation/comparator' === added file 'dhis-2/dhis-api/src/main/java/org/hisp/dhis/translation/comparator/TranslationLocaleSpecificityComparator.java' --- dhis-2/dhis-api/src/main/java/org/hisp/dhis/translation/comparator/TranslationLocaleSpecificityComparator.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-api/src/main/java/org/hisp/dhis/translation/comparator/TranslationLocaleSpecificityComparator.java 2013-10-06 07:45:05 +0000 @@ -0,0 +1,54 @@ +package org.hisp.dhis.translation.comparator; + +/* + * Copyright (c) 2004-2013, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.util.Comparator; + +import org.hisp.dhis.translation.Translation; + +/** + * Compares two Translation objects based on how specific the Locales are. The + * Translation with least specific Locale appears first. + * + * @author Lars Helge Overland + */ +public class TranslationLocaleSpecificityComparator + implements Comparator +{ + public static final TranslationLocaleSpecificityComparator INSTANCE = new TranslationLocaleSpecificityComparator(); + + @Override + public int compare( Translation t1, Translation t2 ) + { + Integer l1 = Integer.valueOf( t1.getLocale().length() ); + Integer l2 = Integer.valueOf( t2.getLocale().length() ); + + return l1.compareTo( l2 ); + } +} === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nLocaleService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nLocaleService.java 2013-10-04 16:25:27 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nLocaleService.java 2013-10-06 07:45:05 +0000 @@ -42,17 +42,15 @@ import org.hisp.dhis.common.GenericIdentifiableObjectStore; import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.common.comparator.IdentifiableObjectNameComparator; +import org.hisp.dhis.common.comparator.LocaleNameComparator; import org.hisp.dhis.i18n.locale.I18nLocale; import org.hisp.dhis.system.util.LocaleUtils; -import org.hisp.dhis.system.util.TextUtils; import org.springframework.transaction.annotation.Transactional; @Transactional public class DefaultI18nLocaleService implements I18nLocaleService -{ - private static final String NAME_SEP = ", "; - +{ // ------------------------------------------------------------------------- // Dependencies // ------------------------------------------------------------------------- @@ -132,7 +130,7 @@ String loc = LocaleUtils.getLocaleString( language, country, null ); - String name = languageName + ( countryName != null ? ( NAME_SEP + countryName ) : TextUtils.EMPTY ); + String name = new Locale( language, country ).toString(); I18nLocale locale = new I18nLocale( name, loc ); @@ -180,4 +178,18 @@ { return localeStore.getAllLikeNameOrderedName( name, first, max ); } + + public List getAllLocales() + { + List locales = new ArrayList(); + + for ( I18nLocale locale : localeStore.getAll() ) + { + locales.add( LocaleUtils.getLocale( locale.getLocale() ) ); + } + + Collections.sort( locales, LocaleNameComparator.INSTANCE ); + + return locales; + } } === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java 2013-10-01 16:44:42 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/DefaultI18nService.java 2013-10-06 07:45:05 +0000 @@ -37,7 +37,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Collections; import java.util.HashMap; import java.util.Hashtable; import java.util.List; @@ -46,9 +45,7 @@ import org.hisp.dhis.common.IdentifiableObject; import org.hisp.dhis.common.NameableObject; -import org.hisp.dhis.common.comparator.LocaleNameComparator; import org.hisp.dhis.dataelement.DataElement; -import org.hisp.dhis.system.util.LocaleUtils; import org.hisp.dhis.translation.Translation; import org.hisp.dhis.translation.TranslationService; import org.hisp.dhis.user.UserSettingService; @@ -69,6 +66,13 @@ { this.translationService = translationService; } + + private I18nLocaleService localeService; + + public void setLocaleService( I18nLocaleService localeService ) + { + this.localeService = localeService; + } private UserSettingService userSettingService; @@ -78,27 +82,6 @@ } // ------------------------------------------------------------------------- - // Properties - // ------------------------------------------------------------------------- - - private List locales = new ArrayList(); - - public void setLocales( List localeStrings ) - { - for ( String string : localeStrings ) - { - Locale locale = LocaleUtils.getLocale( string ); - - if ( locale != null ) - { - locales.add( locale ); - } - } - - Collections.sort( locales, LocaleNameComparator.INSTANCE ); - } - - // ------------------------------------------------------------------------- // Internationalise // ------------------------------------------------------------------------- @@ -289,7 +272,7 @@ public List getAvailableLocales() { - return locales; + return localeService.getAllLocales(); } // ------------------------------------------------------------------------- === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/I18nLocaleService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/I18nLocaleService.java 2013-10-04 15:05:00 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/i18n/I18nLocaleService.java 2013-10-06 07:45:05 +0000 @@ -28,6 +28,8 @@ */ import java.util.Collection; +import java.util.List; +import java.util.Locale; import java.util.Map; import org.hisp.dhis.i18n.locale.I18nLocale; @@ -61,4 +63,6 @@ Collection getI18nLocalesBetween( int first, int max ); Collection getI18nLocalesBetweenLikeName( String name, int first, int max ); + + List getAllLocales(); } === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/translation/DefaultTranslationService.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/translation/DefaultTranslationService.java 2013-10-01 16:44:42 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/translation/DefaultTranslationService.java 2013-10-06 07:45:05 +0000 @@ -31,9 +31,6 @@ import java.util.Collection; import java.util.Locale; -import org.hisp.dhis.translation.Translation; -import org.hisp.dhis.translation.TranslationService; -import org.hisp.dhis.translation.TranslationStore; import org.springframework.transaction.annotation.Transactional; /** === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/translation/hibernate/HibernateTranslationStore.java' --- dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/translation/hibernate/HibernateTranslationStore.java 2013-10-01 16:44:42 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/java/org/hisp/dhis/translation/hibernate/HibernateTranslationStore.java 2013-10-06 07:45:05 +0000 @@ -37,6 +37,7 @@ import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.criterion.Restrictions; +import org.hisp.dhis.system.util.LocaleUtils; import org.hisp.dhis.translation.Translation; import org.hisp.dhis.translation.TranslationStore; @@ -75,6 +76,7 @@ session.update( translation ); } + @SuppressWarnings( "unchecked" ) public Translation getTranslation( String className, int id, Locale locale, String property ) { Session session = sessionFactory.getCurrentSession(); @@ -83,12 +85,14 @@ criteria.add( Restrictions.eq( "className", className ) ); criteria.add( Restrictions.eq( "id", id ) ); - criteria.add( Restrictions.eq( "locale", locale.toString() ) ); + criteria.add( Restrictions.in( "locale", LocaleUtils.getLocaleFallbacks( locale ) ) ); criteria.add( Restrictions.eq( "property", property ) ); criteria.setCacheable( true ); - return (Translation) criteria.uniqueResult(); + List translations = LocaleUtils.getTranslationsHighestSpecifity( criteria.list() ); + + return !translations.isEmpty() ? translations.get( 0 ) : null; } @SuppressWarnings( "unchecked" ) @@ -100,11 +104,13 @@ criteria.add( Restrictions.eq( "className", className ) ); criteria.add( Restrictions.eq( "id", id ) ); - criteria.add( Restrictions.eq( "locale", locale.toString() ) ); + criteria.add( Restrictions.in( "locale", LocaleUtils.getLocaleFallbacks( locale ) ) ); criteria.setCacheable( true ); - return criteria.list(); + List translations = criteria.list(); + + return LocaleUtils.getTranslationsHighestSpecifity( translations ); } @SuppressWarnings( "unchecked" ) @@ -115,11 +121,13 @@ Criteria criteria = session.createCriteria( Translation.class ); criteria.add( Restrictions.eq( "className", className ) ); - criteria.add( Restrictions.eq( "locale", locale.toString() ) ); + criteria.add( Restrictions.in( "locale", LocaleUtils.getLocaleFallbacks( locale ) ) ); criteria.setCacheable( true ); - return criteria.list(); + List translations = criteria.list(); + + return LocaleUtils.getTranslationsHighestSpecifity( translations ); } @SuppressWarnings( "unchecked" ) === modified file 'dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml' --- dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2013-10-04 16:25:27 +0000 +++ dhis-2/dhis-services/dhis-service-core/src/main/resources/META-INF/dhis/beans.xml 2013-10-06 07:45:05 +0000 @@ -794,39 +794,8 @@ + - - - af - ar - bi - am - de - dz - en - es - fa - fr - gu - hi - id - it - km - lo - my - ne - nl - no - ps - pt - ru - rw - sw - tg - vi - zh - - === modified file 'dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/LocaleUtils.java' --- dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/LocaleUtils.java 2013-10-05 14:04:38 +0000 +++ dhis-2/dhis-support/dhis-support-system/src/main/java/org/hisp/dhis/system/util/LocaleUtils.java 2013-10-06 07:45:05 +0000 @@ -28,7 +28,16 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; import java.util.Locale; +import java.util.Map; + +import org.hisp.dhis.translation.Translation; +import org.hisp.dhis.translation.comparator.TranslationLocaleSpecificityComparator; /** * @author Oyvind Brucker @@ -49,7 +58,7 @@ } /** - * Createa a locale string based on the given language, country and varient. + * Createa a locale string based on the given language, country and variant. * * @param language the language, cannot be null. * @param country the country, can be null. @@ -77,4 +86,54 @@ return locale; } + + /** + * Creates a list of locales of all possible specifities based on the given + * Locale. As an example, for the given locale "en_UK", the locales "en" and + * "en_UK" are returned. + * + * @param locale the Locale. + * @return a list of locale strings. + */ + public static List getLocaleFallbacks( Locale locale ) + { + List locales = new ArrayList(); + + locales.add( locale.getLanguage() ); + + if ( !locale.getCountry().isEmpty() ) + { + locales.add( locale.getLanguage() + SEP + locale.getCountry() ); + } + + if ( !locale.getVariant().isEmpty() ) + { + locales.add( locale.toString() ); + } + + return locales; + } + + /** + * Filters the given list of translations in a way where only the most specific + * locales are kept for every base locale. + * + * @param translations the list of translations. + * @return a list of translations. + */ + public static List getTranslationsHighestSpecifity( Collection translations ) + { + Map translationMap = new HashMap(); + + List trans = new ArrayList( translations ); + + Collections.sort( trans, TranslationLocaleSpecificityComparator.INSTANCE ); + + for ( Translation tr : trans ) + { + translationMap.put( tr.getClassIdPropKey(), tr ); + } + + return new ArrayList( translationMap.values() ); + } } === added file 'dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/LocaleUtilsTest.java' --- dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/LocaleUtilsTest.java 1970-01-01 00:00:00 +0000 +++ dhis-2/dhis-support/dhis-support-system/src/test/java/org/hisp/dhis/system/util/LocaleUtilsTest.java 2013-10-06 07:45:05 +0000 @@ -0,0 +1,89 @@ +package org.hisp.dhis.system.util; + +/* + * Copyright (c) 2004-2013, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +import java.util.Arrays; +import java.util.List; +import java.util.Locale; + +import org.hisp.dhis.dataelement.DataElement; +import org.hisp.dhis.translation.Translation; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Lars Helge Overland + */ +public class LocaleUtilsTest +{ + @Test + public void testGetTranslationsHighestSpecifity() + { + Locale l1 = new Locale( "en", "UK", "en" ); + Locale l2 = new Locale( "en", "UK" ); + Locale l3 = new Locale( "en" ); + + Translation t1 = new Translation( DataElement.class.getSimpleName(), 1, l1.toString(), "name", "Name" ); + Translation t2 = new Translation( DataElement.class.getSimpleName(), 1, l2.toString(), "name", "Name" ); + Translation t3 = new Translation( DataElement.class.getSimpleName(), 1, l3.toString(), "name", "Name" ); + + Translation t4 = new Translation( DataElement.class.getSimpleName(), 1, l1.toString(), "shortName", "Short name" ); + Translation t5 = new Translation( DataElement.class.getSimpleName(), 1, l2.toString(), "shortName", "Short name" ); + + Translation t6 = new Translation( DataElement.class.getSimpleName(), 1, l2.toString(), "code", "Code" ); + + List list = Arrays.asList( t1, t2, t3, t4, t5, t6 ); + + List translations = LocaleUtils.getTranslationsHighestSpecifity( list ); + + assertEquals( 3, translations.size() ); + assertTrue( translations.contains( t1 ) ); + assertTrue( translations.contains( t4 ) ); + assertTrue( translations.contains( t6 ) ); + } + + @Test + public void testGetLocaleFallbacks() + { + Locale l1 = new Locale( "en", "UK", "en" ); + Locale l2 = new Locale( "en", "UK" ); + Locale l3 = new Locale( "en" ); + + List locales = LocaleUtils.getLocaleFallbacks( l1 ); + + assertEquals( 3, locales.size() ); + assertTrue( locales.contains( "en_UK_en" ) ); + assertTrue( locales.contains( "en_UK" ) ); + assertTrue( locales.contains( "en_UK" ) ); + + assertEquals( 2, LocaleUtils.getLocaleFallbacks( l2 ).size() ); + assertEquals( 1, LocaleUtils.getLocaleFallbacks( l3 ).size() ); + } +} === modified file 'dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.js' --- dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.js 2013-10-05 17:11:35 +0000 +++ dhis-2/dhis-web/dhis-web-commons-resources/src/main/webapp/dhis-web-commons/security/login.js 2013-10-06 07:45:05 +0000 @@ -16,7 +16,7 @@ var locale = $.cookie( login.localeCookie ); - if ( undefined !== locale ) + if ( undefined !== locale && locale != null ) { login.changeLocale( locale ); $( '#localeSelect option[value="' + locale + '"]' ).attr( 'selected', 'selected' ); === modified file 'dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/i18n/action/GetStringsFromLocaleAction.java' --- dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/i18n/action/GetStringsFromLocaleAction.java 2013-10-04 17:06:16 +0000 +++ dhis-2/dhis-web/dhis-web-commons/src/main/java/org/hisp/dhis/i18n/action/GetStringsFromLocaleAction.java 2013-10-06 07:45:05 +0000 @@ -66,10 +66,10 @@ public String execute() throws Exception { - Locale locale = LocaleUtils.getLocale( loc ); - if ( loc != null ) - { + { + Locale locale = LocaleUtils.getLocale( loc ); + i18nObject = manager.getI18n( this.getClass(), locale ); } === modified file 'dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml' --- dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml 2013-10-04 14:34:08 +0000 +++ dhis-2/dhis-web/dhis-web-maintenance/dhis-web-maintenance-dataadmin/src/main/resources/struts.xml 2013-10-06 07:45:05 +0000 @@ -58,7 +58,6 @@ /main.vm /dhis-web-maintenance-dataadmin/localeList.vm /dhis-web-maintenance-dataadmin/menu.vm - F_LOCALE_MANAGEMENT /main.vm /dhis-web-maintenance-dataadmin/updateLocaleForm.vm /dhis-web-maintenance-dataadmin/menu.vm - F_LOCALE_UPDATE + F_LOCALE_ADD locale.action - F_LOCALE_UPDATE + F_LOCALE_ADD