/******************************************************************************
* Product: Adempiere ERP & CRM Smart Business Solution *
* Copyright (C) 1999-2006 ComPiere, Inc. All Rights Reserved. *
* This program is free software; you can redistribute it and/or modify it *
* under the terms version 2 of the GNU General Public License as published *
* by the Free Software Foundation. This program is distributed in the hope *
* that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
* See the GNU General Public License for more details. *
* You should have received a copy of the GNU General Public License along *
* with this program; if not, write to the Free Software Foundation, Inc., *
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. *
* For the text or an alternative of this public license, you may reach us *
* ComPiere, Inc., 2620 Augustine Dr. #245, Santa Clara, CA 95054, USA *
* or via info@compiere.org or http://www.compiere.org/license.html *
*****************************************************************************/
package org.compiere.util;
import java.awt.ComponentOrientation;
import java.io.Serializable;
import java.text.DateFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.logging.Level;
import javax.print.attribute.standard.MediaSize;
import org.compiere.model.MLanguage;
import org.compiere.print.MPrintPaper;
/**
* Language Management.
*
* @author Jorg Janke
* @version $Id: Language.java,v 1.2 2006/07/30 00:52:23 jjanke Exp $
*/
public class Language implements Serializable
{
/**
* generated serial id
*/
private static final long serialVersionUID = 7039775951366180267L;
/**************************************************************************
* Languages
* http://www.ics.uci.edu/pub/ietf/http/related/iso639.txt
* Countries
* http://www.iso.org/iso/country_codes/iso_3166_code_lists/english_country_names_and_code_elements.htm
*************************************************************************/
/** Base Language */
private static final String AD_Language_en_US = "en_US";
/***
* System Languages.
* If you want to add a language, use the method getLanguage which extends the array
**/
private static List s_languages = new ArrayList();
/** Base Language */
private static Language s_baseLanguage = null;
private static boolean isBaseLanguageSet = false;
static {
s_languages.add(new Language ("English", AD_Language_en_US, Locale.US, null, null, MediaSize.NA.LETTER));
s_baseLanguage = s_languages.get(0);
}
/** Logger */
private static CLogger log = CLogger.getCLogger(Language.class.getName());
/**
* Get Number of Languages
* @return Language count
*/
public static int getLanguageCount()
{
return s_languages.size();
} // getLanguageCount
/**
* Get Language
* @param index index
* @return Language
*/
public static Language getLanguage (int index)
{
if (index < 0 || index >= s_languages.size())
return s_baseLanguage;
return s_languages.get(index);
} // getLanguage
/**
* Get Language.
* If language does not exist, create it on the fly assuming that it is valid
* @param langInfo either language (en) or locale (en-US) or display name
* @return Name (e.g. Deutsch)
*/
public synchronized static Language getLanguage (String langInfo)
{
int idxReplace = -1;
String lang = langInfo;
if (lang == null || lang.length() == 0)
lang = System.getProperty("user.language", "");
// Search existing Languages
for (int i = 0; i < s_languages.size(); i++)
{
if ( lang.equals(s_languages.get(i).getAD_Language())
|| lang.equals(s_languages.get(i).getLanguageCode())
|| lang.equals(s_languages.get(i).getName())) {
if (!s_languages.get(i).m_fromDB && DB.isConnected()) {
// if language was not get from DB and now we're connected
idxReplace = i;
break;
} else {
return s_languages.get(i);
}
}
}
// Create Language on the fly
if (lang.length() == 5) // standard format _
{
Language ll = null;
String language = lang.substring(0,2);
String country = lang.substring(3);
Locale locale = new Locale(language, country);
if (DB.isConnected()) {
// first time connected?
if (!isBaseLanguageSet) {
setBaseLanguage();
}
MLanguage dblang = MLanguage.get(Env.getCtx(), langInfo);
if (dblang != null) {
if (!( language.equals(dblang.getLanguageISO())
&& country.equals(dblang.getCountryCode())
) && dblang.getLanguageISO() != null
&& dblang.getCountryCode() != null
) {
locale = new Locale(dblang.getLanguageISO(), dblang.getCountryCode());
}
MediaSize mediaSize = MediaSize.ISO.A4;
if (dblang.getAD_PrintPaper_ID() > 0) {
MPrintPaper pp = MPrintPaper.get(dblang.getAD_PrintPaper_ID());
mediaSize = pp.getMediaSize();
}
ll = new Language(dblang.getPrintName(), langInfo, locale, null, dblang.getDatePattern(), mediaSize);
ll.m_fromDB = true;
if (dblang.isBaseLanguage()) {
idxReplace = 0;
if (dblang.isSystemLanguage()) {
// base language is uploaded also as System language, don't use base language but the corresponding translation
s_baseLanguage = new Language ("no-base", "xx_XX", locale);
} else {
s_baseLanguage = ll;
}
}
}
}
if (ll == null) {
ll = new Language (lang, lang, locale);
}
if (log.isLoggable(Level.INFO)) {
StringBuilder msglog = new StringBuilder("Adding Language=").append(language).append(", Country=").append(country).append(", Locale=").append(locale);
log.info (msglog.toString());
}
if (idxReplace >= 0) {
s_languages.set(idxReplace, ll);
} else {
s_languages.add(ll);
}
return ll;
}
// Get the default one
return s_baseLanguage;
} // getLanguage
/**
* Set base language from AD_Language table
*/
private static void setBaseLanguage() {
isBaseLanguageSet = true;
String baselang = DB.getSQLValueStringEx(null, "SELECT AD_Language FROM AD_Language WHERE IsActive='Y' AND IsBaseLanguage = 'Y'");
if (baselang != null) {
getLanguage(baselang);
}
}
/**
* Set baselang as base language
* @param baselang
*/
public static void setBaseLanguage(String baselang) {
Language lang = getLanguage(baselang);
s_baseLanguage = lang;
}
/**
* Is it the base language
* @param langInfo either language (en) or locale (en-US) or display name
* @return true if base language
*/
public static boolean isBaseLanguage (String langInfo)
{
if (langInfo == null || langInfo.length() == 0
|| langInfo.equals(s_baseLanguage.getName())
|| langInfo.equals(s_baseLanguage.getLanguageCode())
|| langInfo.equals(s_baseLanguage.getAD_Language()))
return true;
return false;
} // isBaseLanguage
/**
* Get Base Language
* @return Base Language
*/
public static Language getBaseLanguage()
{
return s_baseLanguage;
} // getBase
/**
* Get Base Language code. (e.g. en-US)
* @return Base Language
*/
public static String getBaseAD_Language()
{
return s_baseLanguage.getAD_Language();
} // getBase
/**
* Get Locale from langInfo
* @param langInfo either language (en) or locale (en-US) or display name
* @return Locale
*/
public static Locale getLocale (String langInfo)
{
return getLanguage(langInfo).getLocale();
} // getLocale
/**
* Get Language from langInfo
* @param langInfo either language (en) or locale (en-US) or display name
* @return AD_Language (e.g. en-US)
*/
public static String getAD_Language (String langInfo)
{
return getLanguage(langInfo).getAD_Language();
} // getAD_Language
/**
* Get Language code from locale
* @param locale Locale
* @return AD_Language (e.g. en-US)
*/
public static String getAD_Language (Locale locale)
{
if (locale != null)
{
for (int i = 0; i < s_languages.size(); i++)
{
if (locale.getLanguage().equals(s_languages.get(i).getLocale().getLanguage()))
return s_languages.get(i).getAD_Language();
}
}
return s_baseLanguage.getAD_Language();
} // getLocale
/**
* Get Language Name from langInfo
* @param langInfo either language (en) or locale (en-US) or display name
* @return Language Name (e.g. English)
*/
public static String getName (String langInfo)
{
return getLanguage(langInfo).getName();
} // getAD_Language
/**
* Returns true if Decimal Point (not comma)
* @param langInfo either language (en) or locale (en-US) or display name
* @return use of decimal point
*/
public static boolean isDecimalPoint(String langInfo)
{
return getLanguage(langInfo).isDecimalPoint();
} // getAD_Language
/**
* Get Display names of supported languages
* @return Array of Language names
*/
public static String[] getNames()
{
String[] retValue = new String[s_languages.size()];
for (int i = 0; i < s_languages.size(); i++)
retValue[i] = s_languages.get(i).getName();
return retValue;
} // getNames
/**
* Get Current Login Language
* @return login language
*/
public static Language getLoginLanguage ()
{
return Env.getLanguage(Env.getCtx());
} // getLanguage
/**
* Set Current Login Language
* @param language language
*/
public static void setLoginLanguage (Language language)
{
if (language != null)
{
Env.setContext(Env.getCtx(), Env.LANGUAGE, language.getAD_Language());
if (log.isLoggable(Level.CONFIG)) log.config(language.toString());
}
} // setLanguage
/**
* Define Language
* @param name - displayed value, e.g. English
* @param AD_Language - the code of system supported language, e.g. en_US
* (might be different than Locale - i.e. if the system does not support the language)
* @param locale - the Locale, e.g. Locale.US
* @param decimalPoint true if Decimal Point - if null, derived from Locale
* @param javaDatePattern Java date pattern as not all locales are defined - if null, derived from Locale
* @param mediaSize default media size
*/
public Language (String name, String AD_Language, Locale locale,
Boolean decimalPoint, String javaDatePattern, MediaSize mediaSize)
{
if (name == null || AD_Language == null || locale == null)
throw new IllegalArgumentException ("Language - parameter is null");
m_name = name;
m_AD_Language = AD_Language;
m_locale = locale;
//
m_decimalPoint = decimalPoint;
setDateFormat (javaDatePattern);
setMediaSize (mediaSize);
} // Language
/**
* Define Language with AD_Language and default decimal point and date format
* @param name - displayed value, e.g. English
* @param AD_Language - the code of system supported language, e.g. en_US
* (might be different than Locale - i.e. if the system does not support the language)
* @param locale - the Locale, e.g. Locale.US
*/
public Language (String name, String AD_Language, Locale locale)
{
this (name, AD_Language, locale, null, null, null);
} // Language
/**
* Copy constructor
* @param copy
*/
public Language(Language copy)
{
this.m_AD_Language = copy.m_AD_Language;
this.m_dateFormat = copy.m_dateFormat;
this.m_dbDateFormat = copy.m_dbDateFormat;
this.m_decimalPoint = copy.m_decimalPoint;
this.m_fromDB = copy.m_fromDB;
this.m_leftToRight = copy.m_leftToRight;
this.m_locale = copy.m_locale;
this.m_mediaSize = copy.m_mediaSize;
this.m_name = copy.m_name;
}
/** Name */
private String m_name;
/** Language (key) */
private String m_AD_Language;
/** Locale */
private Locale m_locale;
//
private Boolean m_decimalPoint;
private Boolean m_leftToRight;
private SimpleDateFormat m_dateFormat;
private String m_dbDateFormat;
private MediaSize m_mediaSize = MediaSize.ISO.A4;
private boolean m_fromDB = false;
/**
* Get Language Name.
* e.g. English
* @return name
*/
public String getName()
{
return m_name;
} // getName
/**
* Get Application Dictionary Language (system supported).
* e.g. en-US
* @return AD_Language
*/
public String getAD_Language()
{
return m_AD_Language;
} // getAD_Language
/**
* Set Application Dictionary Language (system supported).
* @param AD_Language e.g. en-US
*/
public void setAD_Language (String AD_Language)
{
if (AD_Language != null)
{
m_AD_Language = AD_Language;
if (log.isLoggable(Level.CONFIG)) log.config(toString());
}
} // getAD_Language
/**
* Get Locale
* @return locale
*/
public Locale getLocale()
{
return m_locale;
} // getLocale
/**
* Overwrite Locale
* @param locale locale
*/
public void setLocale (Locale locale)
{
if (locale == null)
return;
m_locale = locale;
m_decimalPoint = null; // reset
} // getLocale
/**
* Get Language Code.
* e.g. en - derived from Locale
* @return language code
*/
public String getLanguageCode()
{
return m_locale.getLanguage();
} // getLanguageCode
/**
* Component orientation is Left To Right
* @return true if left-to-right
*/
public boolean isLeftToRight()
{
if (m_leftToRight == null)
// returns true if language not iw, ar, fa, ur
m_leftToRight = Boolean.valueOf(ComponentOrientation.getOrientation(m_locale).isLeftToRight());
return m_leftToRight.booleanValue();
} // isLeftToRight
/**
* Returns true if Decimal Point (not comma)
* @return use of decimal point
*/
public boolean isDecimalPoint()
{
if (m_decimalPoint == null)
{
DecimalFormatSymbols dfs = new DecimalFormatSymbols(m_locale);
m_decimalPoint = Boolean.valueOf(dfs.getDecimalSeparator() == '.');
}
return m_decimalPoint.booleanValue();
} // isDecimalPoint
/**
* Is This the Base Language
* @return true if base Language
*/
public boolean isBaseLanguage()
{
return this.equals(getBaseLanguage());
} // isBaseLanguage
/**
* Set Date Format Pattern.
* The date format is not checked for correctness
* @param javaDatePattern for details see java.text.SimpleDateFormat,
* format must be able to be converted to database date format by
* using the upper case function.
* It also must have leading zero for day and month.
*/
public synchronized void setDateFormat (String javaDatePattern)
{
if (javaDatePattern == null)
return;
m_dateFormat = (SimpleDateFormat)DateFormat.getDateInstance
(DateFormat.SHORT, m_locale);
try
{
m_dateFormat.applyPattern(javaDatePattern);
}
catch (Exception e)
{
log.severe(javaDatePattern + " - " + e);
m_dateFormat = null;
}
} // setDateFormat
/**
* Get (Short) Date Format.
* @return date format MM/dd/yyyy - dd.MM.yyyy
*/
public synchronized SimpleDateFormat getDateFormat()
{
if (m_dateFormat == null)
{
m_dateFormat = (SimpleDateFormat)DateFormat.getDateInstance
(DateFormat.SHORT, m_locale);
String sFormat = m_dateFormat.toPattern();
// some short formats have only one M and/or d (e.g. ths US)
if (sFormat.indexOf("MM") == -1 || sFormat.indexOf("dd") == -1)
{
sFormat = sFormat.replaceFirst("d+", "dd");
sFormat = sFormat.replaceFirst("M+", "MM");
// log.finer(sFormat + " => " + nFormat);
m_dateFormat.applyPattern(sFormat);
}
// Unknown short format => use JDBC
if (m_dateFormat.toPattern().length() != 8)
m_dateFormat.applyPattern("yyyy-MM-dd");
// 4 digit year
if (m_dateFormat.toPattern().indexOf("yyyy") == -1)
{
sFormat = m_dateFormat.toPattern();
StringBuilder nFormat = new StringBuilder();
for (int i = 0; i < sFormat.length(); i++)
{
if (sFormat.charAt(i) == 'y')
nFormat.append("yy");
else
nFormat.append(sFormat.charAt(i));
}
m_dateFormat.applyPattern(nFormat.toString());
}
m_dateFormat.setLenient(true);
}
return (SimpleDateFormat) m_dateFormat.clone();
} // getDateFormat
/**
* Get Date Time Format.
* @return Date Time format MMM d, yyyy h:mm:ss a z -or- dd.MM.yyyy HH:mm:ss z
* -or- j nnn aaaa, H' ?????? 'm' ????'
*/
public SimpleDateFormat getDateTimeFormat()
{
SimpleDateFormat retValue = (SimpleDateFormat)DateFormat.getDateTimeInstance
(DateFormat.MEDIUM, DateFormat.LONG, m_locale);
return retValue;
} // getDateTimeFormat
/**
* Get Time Format.
* @return Time format h:mm:ss z or HH:mm:ss z
*/
public SimpleDateFormat getTimeFormat()
{
return (SimpleDateFormat)DateFormat.getTimeInstance
(DateFormat.LONG, m_locale);
} // getTimeFormat
/**
* Get Database Date Pattern.
* Derive from date pattern (make upper case and replace month as word with MM)
* @return date pattern
*/
public String getDBdatePattern()
{
if (m_dbDateFormat == null)
{
m_dbDateFormat = getDateFormat().toPattern().toUpperCase(m_locale);
// IDEMPIERE-3888 - temporary hack - a better solution would be to implement AD_Language.DBDatePattern
m_dbDateFormat = m_dbDateFormat.replaceFirst("MMM*", "MM");
}
return m_dbDateFormat;
} // getDBdatePattern
/**
* Get default MediaSize
* @return media size
*/
public MediaSize getMediaSize()
{
return m_mediaSize;
} // getMediaSize
/**
* Set default MediaSize
* @param size media size
*/
public void setMediaSize (MediaSize size)
{
if (size != null)
m_mediaSize = size;
} // setMediaSize
/**
* String Representation
* @return string representation
*/
@Override
public String toString()
{
StringBuilder sb = new StringBuilder("Language=[");
sb.append(m_name).append(",Locale=").append(m_locale.toString())
.append(",AD_Language=").append(m_AD_Language)
.append(",DatePattern=").append(getDBdatePattern())
.append(",DecimalPoint=").append(isDecimalPoint())
.append("]");
return sb.toString();
} // toString
/**
* Hash Code
* @return hashcode
*/
@Override
public int hashCode()
{
return m_AD_Language.hashCode();
} // hashcode
/**
* Equals.
* Two languages are equal, if they have the same AD_Language
* @param obj compare
* @return true if AD_Language is the same
*/
@Override
public boolean equals(Object obj)
{
if (obj instanceof Language)
{
Language cmp = (Language)obj;
if (cmp.getAD_Language().equals(m_AD_Language))
return true;
}
return false;
} // equals
} // Language