2009-06-19 07:39:16 +00:00
using System ;
using System.Collections.Generic ;
using System.Data ;
using System.Globalization ;
using System.Xml ;
using umbraco.cms.businesslogic.cache ;
using umbraco.DataLayer ;
using umbraco.BusinessLogic ;
2010-05-25 14:58:43 +00:00
using System.Linq ;
using System.Runtime.CompilerServices ;
[assembly: InternalsVisibleTo("Umbraco.Test")]
2009-06-19 07:39:16 +00:00
namespace umbraco.cms.businesslogic.language
{
/// <summary>
/// The language class contains methods for creating and modifing installed languages.
///
/// A language is used internal in the umbraco console for displaying languagespecific text and
/// in the public website for language/country specific representation of ex. date/time, currencies.
///
/// Besides by using the built in Dictionary you are able to store language specific bits and pieces of translated text
/// for use in templates.
/// </summary>
public class Language
{
2010-05-25 14:58:43 +00:00
#region Private members
2009-06-19 07:39:16 +00:00
private int _id ;
private string _name = "" ;
private string _friendlyName ;
2010-05-25 14:58:43 +00:00
private string _cultureAlias ;
#endregion
2009-06-19 07:39:16 +00:00
2010-05-25 14:58:43 +00:00
#region Constants and static members
2009-06-19 07:39:16 +00:00
private static object getLanguageSyncLock = new object ();
private static readonly string UmbracoLanguageCacheKey = "UmbracoPropertyTypeCache" ;
2010-06-01 09:58:20 +00:00
private const int DefaultLanguageId = 1 ;
2009-06-19 07:39:16 +00:00
/// <summary>
/// Gets the SQL helper.
/// </summary>
/// <value>The SQL helper.</value>
protected static ISqlHelper SqlHelper
{
get { return Application . SqlHelper ; }
}
2010-05-25 14:58:43 +00:00
protected internal const string m_SQLOptimizedGetAll = @"select * from umbracoLanguage" ;
private static readonly object m_Locker = new object ();
#endregion
#region Constructors
2009-06-19 07:39:16 +00:00
/// <summary>
/// Initializes a new instance of the <see cref="Language"/> class.
/// </summary>
/// <param name="id">The id.</param>
public Language ( int id )
{
2010-05-25 14:58:43 +00:00
var lang = GetAllAsList ()
. Where ( x => x . id == id )
. SingleOrDefault ();
if ( lang == null )
{
throw new ArgumentException ( "No language found with the specified id" );
}
_id = lang . id ;
_cultureAlias = lang . CultureAlias ;
_friendlyName = lang . FriendlyName ;
2009-06-19 07:39:16 +00:00
}
/// <summary>
2010-05-25 14:58:43 +00:00
/// Empty constructor used to create a language object manually
2009-06-19 07:39:16 +00:00
/// </summary>
2010-05-25 14:58:43 +00:00
internal Language () { }
2009-06-19 07:39:16 +00:00
2010-05-25 14:58:43 +00:00
#endregion
2009-06-19 07:39:16 +00:00
2010-05-25 14:58:43 +00:00
#region Static methods
2009-06-19 07:39:16 +00:00
/// <summary>
/// Creates a new language given the culture code - ie. da-dk (denmark)
/// </summary>
/// <param name="CultureCode">Culturecode of the language</param>
public static void MakeNew ( string CultureCode )
{
if ( new CultureInfo ( CultureCode ) != null )
{
SqlHelper . ExecuteNonQuery (
"insert into umbracoLanguage (languageISOCode) values (@CultureCode)" ,
SqlHelper . CreateParameter ( "@CultureCode" , CultureCode ));
2010-05-25 14:58:43 +00:00
InvalidateCache ();
2009-06-19 07:39:16 +00:00
NewEventArgs e = new NewEventArgs ();
GetByCultureCode ( CultureCode ). OnNew ( e );
}
}
2010-05-25 14:58:43 +00:00
private static void InvalidateCache ()
2009-06-19 07:39:16 +00:00
{
2010-05-25 14:58:43 +00:00
Cache . ClearCacheItem ( UmbracoLanguageCacheKey );
2009-06-19 07:39:16 +00:00
}
/// <summary>
/// Method for accessing all installed languagess
/// </summary>
2010-05-25 14:58:43 +00:00
[Obsolete("Use the GetAllAsList() method instead")]
2009-06-19 07:39:16 +00:00
public static Language [] getAll
{
get
{
2010-05-25 14:58:43 +00:00
return GetAllAsList (). ToArray ();
2009-06-19 07:39:16 +00:00
}
}
2010-05-25 14:58:43 +00:00
/// <summary>
/// Returns all installed languages
/// </summary>
/// <returns></returns>
/// <remarks>
/// This will return a cached set of all languages. if the cache is not found it will create it.
/// </remarks>
public static IEnumerable < Language > GetAllAsList ()
{
return Cache . GetCacheItem < IEnumerable < Language >>( UmbracoLanguageCacheKey , getLanguageSyncLock , TimeSpan . FromMinutes ( 60 ),
delegate
{
var languages = new List < Language >();
using ( IRecordsReader dr = SqlHelper . ExecuteReader ( m_SQLOptimizedGetAll ))
{
while ( dr . Read ())
{
//create the ContentType object without setting up
Language ct = new Language ();
ct . PopulateFromReader ( dr );
languages . Add ( ct );
}
}
return languages ;
});
}
2009-06-19 07:39:16 +00:00
/// <summary>
/// Gets the language by its culture code, if no language is found, null is returned
/// </summary>
/// <param name="CultureCode">The culture code.</param>
/// <returns></returns>
2010-05-25 14:58:43 +00:00
public static Language GetByCultureCode ( String cultureCode )
2009-06-19 07:39:16 +00:00
{
2010-05-25 14:58:43 +00:00
if ( new CultureInfo ( cultureCode ) != null )
2009-06-19 07:39:16 +00:00
{
2010-05-25 14:58:43 +00:00
return GetAllAsList ()
. Where ( x => x . CultureAlias == cultureCode )
. SingleOrDefault ();
2009-06-19 07:39:16 +00:00
}
return null ;
}
2010-05-25 14:58:43 +00:00
/// <summary>
/// Imports a language from XML
/// </summary>
/// <param name="xmlData">The XML data.</param>
/// <returns></returns>
public static Language Import ( XmlNode xmlData )
{
string cA = xmlData . Attributes [ "CultureAlias" ]. Value ;
if ( Language . GetByCultureCode ( cA ) == null )
{
Language . MakeNew ( cA );
return Language . GetByCultureCode ( cA );
}
else
{
return null ;
}
}
#endregion
#region Public Properties
2009-06-19 07:39:16 +00:00
/// <summary>
/// The id used by umbraco to identify the language
/// </summary>
public int id
{
get { return _id ; }
}
/// <summary>
/// The culture code of the language: ie. Danish/Denmark da-dk
/// </summary>
public string CultureAlias
{
get { return _cultureAlias ; }
set
{
_cultureAlias = value ;
SqlHelper . ExecuteNonQuery (
"update umbracoLanguage set languageISOCode = @cultureAlias where id = @id" , SqlHelper . CreateParameter ( "@id" , id ),
SqlHelper . CreateParameter ( "@cultureAlias" , _cultureAlias ));
updateNames ();
}
}
/// <summary>
/// The user friendly name of the language/country
/// </summary>
public string FriendlyName
{
get { return _friendlyName ; }
2010-05-25 14:58:43 +00:00
}
#endregion
#region Public methods
/// <summary>
/// Ensures uniqueness by id
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals ( object obj )
{
var l = obj as Language ;
if ( l != null )
{
return id . Equals ( l . id );
}
return false ;
}
/// <summary>
/// Ensures uniqueness by id
/// </summary>
/// <returns></returns>
public override int GetHashCode ()
{
return id . GetHashCode ();
}
/// <summary>
/// Used to persist object changes to the database. In Version3.0 it's just a stub for future compatibility
/// </summary>
public virtual void Save ()
{
SaveEventArgs e = new SaveEventArgs ();
FireBeforeSave ( e );
if (! e . Cancel )
{
InvalidateCache ();
FireAfterSave ( e );
}
}
/// <summary>
/// Deletes the current Language.
///
/// Notice: this can have various sideeffects - use with care.
/// </summary>
2010-06-01 09:58:20 +00:00
/// <remarks>
/// You cannot delete the default language: en-US, this is installed by default and is required.
/// </remarks>
2010-05-25 14:58:43 +00:00
public void Delete ()
{
2010-06-01 09:58:20 +00:00
if ( this . id == DefaultLanguageId )
{
throw new InvalidOperationException ( "You cannot delete the default language: en-US" );
}
2010-05-25 14:58:43 +00:00
if ( SqlHelper . ExecuteScalar < int >( "SELECT count(id) FROM umbracoDomains where domainDefaultLanguage = @id" ,
SqlHelper . CreateParameter ( "@id" , id )) == 0 )
{
DeleteEventArgs e = new DeleteEventArgs ();
FireBeforeDelete ( e );
if (! e . Cancel )
{
2010-06-01 09:58:20 +00:00
//remove the dictionary entries first
Item . RemoveByLanguage ( id );
2010-05-25 14:58:43 +00:00
InvalidateCache ();
SqlHelper . ExecuteNonQuery ( "delete from umbracoLanguage where id = @id" ,
SqlHelper . CreateParameter ( "@id" , id ));
FireAfterDelete ( e );
}
}
else
{
Log . Add ( LogTypes . Error , umbraco . BasePages . UmbracoEnsuredPage . CurrentUser , - 1 , "Could not remove Language " + _friendlyName + " because it's attached to a node" );
throw new DataException ( "Cannot remove language " + _friendlyName + " because it's attached to a domain on a node" );
}
2009-06-19 07:39:16 +00:00
}
/// <summary>
/// Converts the instance to XML
/// </summary>
/// <param name="xd">The xml document.</param>
/// <returns></returns>
public System . Xml . XmlNode ToXml ( XmlDocument xd )
{
XmlNode language = xd . CreateElement ( "Language" );
language . Attributes . Append ( xmlHelper . addAttribute ( xd , "Id" , this . id . ToString ()));
language . Attributes . Append ( xmlHelper . addAttribute ( xd , "CultureAlias" , this . CultureAlias ));
language . Attributes . Append ( xmlHelper . addAttribute ( xd , "FriendlyName" , this . FriendlyName ));
return language ;
2010-05-25 14:58:43 +00:00
}
#endregion
2009-06-19 07:39:16 +00:00
2010-05-25 14:58:43 +00:00
#region Protected methods
2009-06-19 07:39:16 +00:00
2010-05-25 14:58:43 +00:00
protected void PopulateFromReader ( IRecordsReader dr )
2009-06-19 07:39:16 +00:00
{
2010-05-25 14:58:43 +00:00
_id = Convert . ToInt32 ( dr . GetShort ( "id" ));
_cultureAlias = dr . GetString ( "languageISOCode" );
updateNames ();
}
#endregion
#region Private methods
private void updateNames ()
{
try
2009-06-19 07:39:16 +00:00
{
2010-05-25 14:58:43 +00:00
CultureInfo ci = new CultureInfo ( _cultureAlias );
_friendlyName = ci . DisplayName ;
2009-06-19 07:39:16 +00:00
}
2010-05-25 14:58:43 +00:00
catch
2009-06-19 07:39:16 +00:00
{
2010-05-25 14:58:43 +00:00
_friendlyName = _name + "(unknown Culture)" ;
2009-06-19 07:39:16 +00:00
}
2010-05-25 14:58:43 +00:00
}
2009-06-19 07:39:16 +00:00
2010-05-25 14:58:43 +00:00
#endregion
2009-06-19 07:39:16 +00:00
2010-05-25 14:58:43 +00:00
#region Events
2009-06-19 07:39:16 +00:00
/// <summary>
/// The save event handler
/// </summary>
public delegate void SaveEventHandler ( Language sender , SaveEventArgs e );
/// <summary>
/// The new event handler
/// </summary>
public delegate void NewEventHandler ( Language sender , NewEventArgs e );
/// <summary>
/// The delete event handler
/// </summary>
public delegate void DeleteEventHandler ( Language sender , DeleteEventArgs e );
/// <summary>
/// Occurs when a language is saved.
/// </summary>
public static event SaveEventHandler BeforeSave ;
protected virtual void FireBeforeSave ( SaveEventArgs e )
{
if ( BeforeSave != null )
BeforeSave ( this , e );
}
public static event SaveEventHandler AfterSave ;
protected virtual void FireAfterSave ( SaveEventArgs e )
{
if ( AfterSave != null )
AfterSave ( this , e );
}
public static event NewEventHandler New ;
protected virtual void OnNew ( NewEventArgs e )
{
if ( New != null )
New ( this , e );
}
public static event DeleteEventHandler BeforeDelete ;
protected virtual void FireBeforeDelete ( DeleteEventArgs e )
{
if ( BeforeDelete != null )
BeforeDelete ( this , e );
}
public static event DeleteEventHandler AfterDelete ;
protected virtual void FireAfterDelete ( DeleteEventArgs e )
{
if ( AfterDelete != null )
AfterDelete ( this , e );
2010-05-25 14:58:43 +00:00
}
#endregion
2009-06-19 07:39:16 +00:00
}
}