diff --git a/source/Griffin.MvcContrib.RavenDb/Localization/TypeLocalizationRepository.cs b/source/Griffin.MvcContrib.RavenDb/Localization/TypeLocalizationRepository.cs index ac5be43..7f66f12 100644 --- a/source/Griffin.MvcContrib.RavenDb/Localization/TypeLocalizationRepository.cs +++ b/source/Griffin.MvcContrib.RavenDb/Localization/TypeLocalizationRepository.cs @@ -1,341 +1,338 @@ -using System; -using System.Collections.Generic; -using System.ComponentModel.DataAnnotations; -using System.Globalization; -using System.Linq; -using System.Threading; -using Griffin.MvcContrib.Localization; -using Griffin.MvcContrib.Localization.Types; -using Griffin.MvcContrib.Logging; -using Raven.Client; - -namespace Griffin.MvcContrib.RavenDb.Localization -{ - /// - /// Used to translate different types (and their properties) - /// - /// - /// You might want to specify , en-us is used per default. - /// - /// Class is not thread safe and are expected to have a short lifetime (per scope) - /// - /// Remember to set - /// - public class TypeLocalizationRepository : ILocalizedTypesRepository, IDisposable - { - private static readonly Dictionary Cache = - new Dictionary(); - - private readonly IDocumentSession _documentSession; - - private readonly ILogger _logger = LogProvider.Current.GetLogger(); - - private readonly LinkedList _modifiedDocuments = - new LinkedList(); - - /// - /// Initializes a new instance of the class. - /// - /// The document session used to work with the database. - public TypeLocalizationRepository(IDocumentSession documentSession) - { - _documentSession = documentSession; - CheckValidationPrompts(); - } - - #region IDisposable Members - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - /// 2 - public void Dispose() - { - lock (_modifiedDocuments) - { - if (_modifiedDocuments.Count > 0) - _logger.Debug("Writing cache"); - foreach (var document in _modifiedDocuments) - { - _documentSession.Store(document); - } - _modifiedDocuments.Clear(); - _documentSession.SaveChanges(); - } - } - - #endregion - - private void CheckValidationPrompts() - { - var language = GetOrCreateLanguage(DefaultUICulture.Value); - var prompt = language.Get(typeof (RequiredAttribute), "class"); - if (prompt != null) - return; - - var prompts = - ValidationAttributesStringProvider.Current.GetPrompts(DefaultUICulture.Value).Select( - p => new TypePromptDocument(DefaultUICulture.Value, p) - { - Text = p.TranslatedText - }); - - foreach (var p in prompts) - { - language.AddPrompt(p); - } - - _documentSession.Store(language); - } - - private TypeLocalizationDocument GetOrCreateLanguage(CultureInfo culture) - { - TypeLocalizationDocument document; - lock (Cache) - { - if (Cache.TryGetValue(culture.LCID, out document)) - return document; - } - - document = (from p in _documentSession.Query() - where p.Id == culture.Name - select p).FirstOrDefault(); - if (document == null) - { - _logger.Debug("Failed to find document for " + culture.Name + ", creating it."); - var defaultLang = DefaultUICulture.Is(culture) - ? new TypeLocalizationDocument - {Id = culture.Name, Prompts = new List()} - : GetOrCreateLanguage(DefaultUICulture.Value); - - document = defaultLang.Clone(culture); - _documentSession.Store(document); - _documentSession.SaveChanges(); - } - - lock (Cache) - Cache[culture.LCID] = document; - - return document; - } - - #region Implementation of ILocalizedTypesRepository - - /// - /// Get all prompts - /// - /// Culture to get prompts for - /// Culture used as template to be able to include all non-translated prompts - /// The filter. - /// - /// Collection of translations - /// - public IEnumerable GetPrompts(CultureInfo cultureInfo, CultureInfo defaultCulture, - SearchFilter filter) - { - var ourDocument = GetOrCreateLanguage(cultureInfo); - if (defaultCulture == null || defaultCulture == cultureInfo) - return ourDocument.Prompts.Select(CreateTextPrompt); - - // get all prompts including not localized ones - var defaultDocument = GetOrCreateLanguage(defaultCulture); - var defaultPrompts = - defaultDocument.Prompts.Except(ourDocument.Prompts, new PromptEqualityComparer()).Select( - p => new TypePromptDocument(cultureInfo, p) - { - UpdatedAt = - DateTime.Now, - UpdatedBy = Thread.CurrentPrincipal.Identity.Name - }); - return ourDocument.Prompts.Union(defaultPrompts).Select(CreateTextPrompt); - } - - /// - /// Create translation for a new language - /// - /// Language to create - /// Language to use as a template - public void CreateLanguage(CultureInfo culture, CultureInfo templateCulture) - { - var templateLang = GetOrCreateLanguage(templateCulture); - var ourLang = new TypeLocalizationDocument - { - Id = culture.Name - }; - ourLang.Prompts = templateLang.Prompts.Select(p => new TypePromptDocument(culture, p)).ToList(); - - lock (_modifiedDocuments) - { - _modifiedDocuments.AddLast(ourLang); - } - } - - /// - /// Get a specific prompt - /// - /// Culture to get prompt for - /// Key which is unique in the current language - /// - /// Prompt if found; otherwise null. - /// - public TypePrompt GetPrompt(CultureInfo culture, TypePromptKey key) - { - var language = GetOrCreateLanguage(culture); - return (from p in language.Prompts - where p.LocaleId == culture.LCID && p.TextKey == key.ToString() - select CreateTextPrompt(p)).FirstOrDefault(); - } - - /// - /// Create or update a prompt - /// - /// Culture that the prompt is for - /// Type being localized - /// Property name and any additonal names (such as metadata name, use underscore as delimiter) - /// Translated text string - public void Save(CultureInfo culture, Type type, string name, string translatedText) - { - Save(culture, type.FullName, name,translatedText); - } - - /// - /// Create or update a prompt - /// - /// Culture that the prompt is for - /// Type.FullName for the type being localized - /// Property name and any additonal names (such as metadata name, use underscore as delimiter) - /// Translated text string - public void Save(CultureInfo culture, string fullTypeName, string name, string translatedText) - { - if (culture == null) throw new ArgumentNullException("culture"); - if (fullTypeName == null) throw new ArgumentNullException("fullTypeName"); - if (name == null) throw new ArgumentNullException("name"); - if (translatedText == null) throw new ArgumentNullException("translatedText"); - if (fullTypeName.IndexOf(".") == -1) - throw new ArgumentException("You must use Type.FullName", "fullTypeName"); - - var pos = fullTypeName.LastIndexOf("."); - var typeName = fullTypeName.Substring(pos + 1); - var key = new TypePromptKey(fullTypeName, name); - var language = GetOrCreateLanguage(culture); - var prompt = (from p in language.Prompts - where p.LocaleId == culture.LCID && p.TextKey == key.ToString() - select p).FirstOrDefault() ?? new TypePromptDocument - { - FullTypeName = fullTypeName, - LocaleId = culture.LCID, - TextName = name, - Text = translatedText, - TextKey = key.ToString(), - TypeName = typeName, - UpdatedAt = DateTime.Now, - UpdatedBy = Thread.CurrentPrincipal.Identity.Name - }; - - prompt.Text = translatedText; - _logger.Debug("Updating text for " + prompt.TypeName + "." + prompt.TextName + " to " + translatedText); - _documentSession.Store(language); - _documentSession.SaveChanges(); - } - - /// - /// Updates the specified culture. - /// - /// The culture. - /// The key. - /// The translated text. - public void Update(CultureInfo culture, TypePromptKey key, string translatedText) - { - if (culture == null) throw new ArgumentNullException("culture"); - if (key == null) throw new ArgumentNullException("key"); - if (translatedText == null) throw new ArgumentNullException("translatedText"); - - var language = GetOrCreateLanguage(culture); - var prompt = (from p in language.Prompts - where p.LocaleId == culture.LCID && p.TextKey == key.ToString() - select p).FirstOrDefault(); - if (prompt == null) - throw new InvalidOperationException("Prompt " + key + " do not exist."); - - prompt.Text = translatedText; - _logger.Debug("Updating text for " + prompt.TypeName + "." + prompt.TextName + " to " + translatedText); - _documentSession.Store(language); - _documentSession.SaveChanges(); - } - - /// - /// Delete a prompt. - /// - /// Culture to delete the prompt for - /// Key - public void Delete(CultureInfo culture, TypePromptKey key) - { - if (culture == null) throw new ArgumentNullException("culture"); - if (key == null) throw new ArgumentNullException("key"); - - var language = GetOrCreateLanguage(culture); - language.DeletePrompt(key); - _modifiedDocuments.AddLast(language); - } - - - /// - /// Get all languages that got partial or full translations. - /// - /// Cultures corresponding to the translations - public IEnumerable GetAvailableLanguages() - { - var languages = from p in _documentSession.Query() - select p.Id; - return languages.ToList().Select(p => new CultureInfo(p)); - } - - private static TypePrompt CreateTextPrompt(TypePromptDocument p) - { - //var type = Type.GetType(string.Format("{0}, {1}", p.FullTypeName, p.AssemblyName), true); - return new TypePrompt - { - LocaleId = p.LocaleId, - TypeFullName = p.FullTypeName, - TextName = p.TextName, - Key = new TypePromptKey(p.TextKey), - TranslatedText = p.Text, - UpdatedAt = p.UpdatedAt, - UpdatedBy = p.UpdatedBy - }; - } - - private class PromptEqualityComparer : IEqualityComparer - { - #region IEqualityComparer Members - - /// - /// Determines whether the specified objects are equal. - /// - /// - /// true if the specified objects are equal; otherwise, false. - /// - /// The first object of type TypePrompt to compare.The second object of type TypePrompt to compare. - public bool Equals(TypePromptDocument x, TypePromptDocument y) - { - return x.TextKey == y.TextKey; - } - - /// - /// Returns a hash code for the specified object. - /// - /// - /// A hash code for the specified object. - /// - /// The for which a hash code is to be returned.The type of is a reference type and is null. - public int GetHashCode(TypePromptDocument obj) - { - return obj.TextKey.GetHashCode(); - } - - #endregion - } - - #endregion - } +using Griffin.MvcContrib.Localization; +using Griffin.MvcContrib.Localization.Types; +using Griffin.MvcContrib.Logging; +using Raven.Client; +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Globalization; +using System.Linq; +using System.Threading; + +namespace Griffin.MvcContrib.RavenDb.Localization +{ + /// + /// Used to translate different types (and their properties) + /// + /// + /// You might want to specify , en-us is used per default. + /// + /// Class is not thread safe and are expected to have a short lifetime (per scope) + /// + /// Remember to set + /// + public class TypeLocalizationRepository : ILocalizedTypesRepository, IDisposable + { + private static readonly Dictionary Cache = + new Dictionary(); + + private readonly IDocumentSession _documentSession; + + private readonly ILogger _logger = LogProvider.Current.GetLogger(); + + private readonly LinkedList _modifiedDocuments = + new LinkedList(); + + /// + /// Initializes a new instance of the class. + /// + /// The document session used to work with the database. + public TypeLocalizationRepository(IDocumentSession documentSession) + { + _documentSession = documentSession; + CheckValidationPrompts(); + } + + #region IDisposable Members + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + /// 2 + public void Dispose() + { + lock (_modifiedDocuments) + { + if (_modifiedDocuments.Count > 0) + _logger.Debug("Writing cache"); + foreach (var document in _modifiedDocuments) + { + _documentSession.Store(document); + } + _modifiedDocuments.Clear(); + _documentSession.SaveChanges(); + } + } + + #endregion + + private void CheckValidationPrompts() + { + var language = GetOrCreateLanguage(DefaultUICulture.Value); + var prompt = language.Get(typeof(RequiredAttribute), "class"); + if (prompt != null) + return; + + var prompts = + ValidationAttributesStringProvider.Current.GetPrompts(DefaultUICulture.Value).Select( + p => new TypePromptDocument(DefaultUICulture.Value, p) + { + Text = p.TranslatedText + }); + + foreach (var p in prompts) + { + language.AddPrompt(p); + } + + _documentSession.Store(language); + } + + private TypeLocalizationDocument GetOrCreateLanguage(CultureInfo culture) + { + TypeLocalizationDocument document; + lock (Cache) + { + if (Cache.TryGetValue(culture.LCID, out document)) + return document; + } + + document = _documentSession.Load(culture.Name); + if (document == null) + { + _logger.Debug("Failed to find document for " + culture.Name + ", creating it."); + var defaultLang = DefaultUICulture.Is(culture) + ? new TypeLocalizationDocument { Id = culture.Name, Prompts = new List() } + : GetOrCreateLanguage(DefaultUICulture.Value); + + document = defaultLang.Clone(culture); + _documentSession.Store(document); + _documentSession.SaveChanges(); + } + + lock (Cache) + Cache[culture.LCID] = document; + + return document; + } + + #region Implementation of ILocalizedTypesRepository + + /// + /// Get all prompts + /// + /// Culture to get prompts for + /// Culture used as template to be able to include all non-translated prompts + /// The filter. + /// + /// Collection of translations + /// + public IEnumerable GetPrompts(CultureInfo cultureInfo, CultureInfo defaultCulture, + SearchFilter filter) + { + var ourDocument = GetOrCreateLanguage(cultureInfo); + if (defaultCulture == null || defaultCulture == cultureInfo) + return ourDocument.Prompts.Select(CreateTextPrompt); + + // get all prompts including not localized ones + var defaultDocument = GetOrCreateLanguage(defaultCulture); + var defaultPrompts = + defaultDocument.Prompts.Except(ourDocument.Prompts, new PromptEqualityComparer()).Select( + p => new TypePromptDocument(cultureInfo, p) + { + UpdatedAt = + DateTime.Now, + UpdatedBy = Thread.CurrentPrincipal.Identity.Name + }); + return ourDocument.Prompts.Union(defaultPrompts).Select(CreateTextPrompt); + } + + /// + /// Create translation for a new language + /// + /// Language to create + /// Language to use as a template + public void CreateLanguage(CultureInfo culture, CultureInfo templateCulture) + { + var templateLang = GetOrCreateLanguage(templateCulture); + var ourLang = new TypeLocalizationDocument + { + Id = culture.Name + }; + ourLang.Prompts = templateLang.Prompts.Select(p => new TypePromptDocument(culture, p)).ToList(); + + lock (_modifiedDocuments) + { + _modifiedDocuments.AddLast(ourLang); + } + } + + /// + /// Get a specific prompt + /// + /// Culture to get prompt for + /// Key which is unique in the current language + /// + /// Prompt if found; otherwise null. + /// + public TypePrompt GetPrompt(CultureInfo culture, TypePromptKey key) + { + var language = GetOrCreateLanguage(culture); + return (from p in language.Prompts + where p.LocaleId == culture.LCID && p.TextKey == key.ToString() + select CreateTextPrompt(p)).FirstOrDefault(); + } + + /// + /// Create or update a prompt + /// + /// Culture that the prompt is for + /// Type being localized + /// Property name and any additonal names (such as metadata name, use underscore as delimiter) + /// Translated text string + public void Save(CultureInfo culture, Type type, string name, string translatedText) + { + Save(culture, type.FullName, name, translatedText); + } + + /// + /// Create or update a prompt + /// + /// Culture that the prompt is for + /// Type.FullName for the type being localized + /// Property name and any additonal names (such as metadata name, use underscore as delimiter) + /// Translated text string + public void Save(CultureInfo culture, string fullTypeName, string name, string translatedText) + { + if (culture == null) throw new ArgumentNullException("culture"); + if (fullTypeName == null) throw new ArgumentNullException("fullTypeName"); + if (name == null) throw new ArgumentNullException("name"); + if (translatedText == null) throw new ArgumentNullException("translatedText"); + if (fullTypeName.IndexOf(".") == -1) + throw new ArgumentException("You must use Type.FullName", "fullTypeName"); + + var pos = fullTypeName.LastIndexOf("."); + var typeName = fullTypeName.Substring(pos + 1); + var key = new TypePromptKey(fullTypeName, name); + var language = GetOrCreateLanguage(culture); + var prompt = (from p in language.Prompts + where p.LocaleId == culture.LCID && p.TextKey == key.ToString() + select p).FirstOrDefault() ?? new TypePromptDocument + { + FullTypeName = fullTypeName, + LocaleId = culture.LCID, + TextName = name, + Text = translatedText, + TextKey = key.ToString(), + TypeName = typeName, + UpdatedAt = DateTime.Now, + UpdatedBy = Thread.CurrentPrincipal.Identity.Name + }; + + prompt.Text = translatedText; + _logger.Debug("Updating text for " + prompt.TypeName + "." + prompt.TextName + " to " + translatedText); + _documentSession.Store(language); + _documentSession.SaveChanges(); + } + + /// + /// Updates the specified culture. + /// + /// The culture. + /// The key. + /// The translated text. + public void Update(CultureInfo culture, TypePromptKey key, string translatedText) + { + if (culture == null) throw new ArgumentNullException("culture"); + if (key == null) throw new ArgumentNullException("key"); + if (translatedText == null) throw new ArgumentNullException("translatedText"); + + var language = GetOrCreateLanguage(culture); + var prompt = (from p in language.Prompts + where p.LocaleId == culture.LCID && p.TextKey == key.ToString() + select p).FirstOrDefault(); + if (prompt == null) + throw new InvalidOperationException("Prompt " + key + " do not exist."); + + prompt.Text = translatedText; + _logger.Debug("Updating text for " + prompt.TypeName + "." + prompt.TextName + " to " + translatedText); + _documentSession.Store(language); + _documentSession.SaveChanges(); + } + + /// + /// Delete a prompt. + /// + /// Culture to delete the prompt for + /// Key + public void Delete(CultureInfo culture, TypePromptKey key) + { + if (culture == null) throw new ArgumentNullException("culture"); + if (key == null) throw new ArgumentNullException("key"); + + var language = GetOrCreateLanguage(culture); + language.DeletePrompt(key); + _modifiedDocuments.AddLast(language); + } + + + /// + /// Get all languages that got partial or full translations. + /// + /// Cultures corresponding to the translations + public IEnumerable GetAvailableLanguages() + { + var languages = from p in _documentSession.Query() + select p.Id; + return languages.ToList().Select(p => new CultureInfo(p)); + } + + private static TypePrompt CreateTextPrompt(TypePromptDocument p) + { + //var type = Type.GetType(string.Format("{0}, {1}", p.FullTypeName, p.AssemblyName), true); + return new TypePrompt + { + LocaleId = p.LocaleId, + TypeFullName = p.FullTypeName, + TextName = p.TextName, + Key = new TypePromptKey(p.TextKey), + TranslatedText = p.Text, + UpdatedAt = p.UpdatedAt, + UpdatedBy = p.UpdatedBy + }; + } + + private class PromptEqualityComparer : IEqualityComparer + { + #region IEqualityComparer Members + + /// + /// Determines whether the specified objects are equal. + /// + /// + /// true if the specified objects are equal; otherwise, false. + /// + /// The first object of type TypePrompt to compare.The second object of type TypePrompt to compare. + public bool Equals(TypePromptDocument x, TypePromptDocument y) + { + return x.TextKey == y.TextKey; + } + + /// + /// Returns a hash code for the specified object. + /// + /// + /// A hash code for the specified object. + /// + /// The for which a hash code is to be returned.The type of is a reference type and is null. + public int GetHashCode(TypePromptDocument obj) + { + return obj.TextKey.GetHashCode(); + } + + #endregion + } + + #endregion + } } \ No newline at end of file diff --git a/source/Griffin.MvcContrib.RavenDb/Localization/ViewLocalizationRepository.cs b/source/Griffin.MvcContrib.RavenDb/Localization/ViewLocalizationRepository.cs index 7129e30..ad678c7 100644 --- a/source/Griffin.MvcContrib.RavenDb/Localization/ViewLocalizationRepository.cs +++ b/source/Griffin.MvcContrib.RavenDb/Localization/ViewLocalizationRepository.cs @@ -1,338 +1,335 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Threading; -using Griffin.MvcContrib.Localization; -using Griffin.MvcContrib.Localization.Views; -using Griffin.MvcContrib.Logging; -using Raven.Client; - -namespace Griffin.MvcContrib.RavenDb.Localization -{ - /// - /// RavenDB repository for view localizations - /// - /// Remember to set - public class ViewLocalizationRepository : IViewLocalizationRepository, IDisposable - { - private static readonly Dictionary Cache = - new Dictionary(); - - private readonly IDocumentSession _documentSession; - - private readonly ILogger _logger = LogProvider.Current.GetLogger(); - - private readonly LinkedList _modifiedDocuments = - new LinkedList(); - - /// - /// Initializes a new instance of the class. - /// - /// The document session. - public ViewLocalizationRepository(IDocumentSession documentSession) - { - _documentSession = documentSession; - } - - #region Implementation of IViewLocalizationRepository - - /// - /// Get all prompts that have been created for an language - /// - /// Culture to get translation for - /// Culture to find not translated prompts in (or same culture to disable) - /// Used to limit the search result - /// - /// A collection of prompts - /// - public IEnumerable GetAllPrompts(CultureInfo culture, CultureInfo templateCulture, - SearchFilter filter) - { - return GetOrCreateLanguage(culture, templateCulture).Prompts.Select(CreatePrompt); - } - - /// - /// Create translation for a new language - /// - /// Language to create - /// Language to use as a template - public void CreateLanguage(CultureInfo culture, CultureInfo templateCulture) - { - var sourceLang = GetLanguage(culture); - var newLang = new ViewLocalizationDocument - { - Id = culture.Name, - Prompts = sourceLang.Prompts.Select(p => new ViewPromptDocument(p) - { - UpdatedAt = DateTime.Now, - UpdatedBy = - Thread.CurrentPrincipal.Identity. - Name, - Text = "" - }).ToList() - }; - - lock (_modifiedDocuments) - { - _modifiedDocuments.AddLast(newLang); - } - } - - /// - /// Get all languages that have translations - /// - /// Collection of languages - public IEnumerable GetAvailableLanguages() - { - var languages = from p in _documentSession.Query() - select p.Id; - return languages.ToList().Select(p => new CultureInfo(p)); - } - - /// - /// Get a text using it's name. - /// - /// Culture to get prompt for - /// - /// Prompt if found; otherwise null. - public ViewPrompt GetPrompt(CultureInfo culture, ViewPromptKey key) - { - if (culture == null) throw new ArgumentNullException("culture"); - if (key == null) throw new ArgumentNullException("key"); - - var language = GetLanguage(culture); - if (language == null) - return null; - - return language.Prompts.Where(p => p.TextKey == key.ToString()).Select(CreatePrompt).FirstOrDefault(); - } - - /// - /// Save/Update a text prompt - /// - /// Language to save prompt in - /// Path to view. You can use - /// Text to translate - /// Translated text - public void Save(CultureInfo culture, string viewPath, string textName, string translatedText) - { - if (culture == null) throw new ArgumentNullException("culture"); - if (viewPath == null) throw new ArgumentNullException("viewPath"); - if (textName == null) throw new ArgumentNullException("textName"); - if (translatedText == null) throw new ArgumentNullException("translatedText"); - - var key = new ViewPromptKey(viewPath, textName); - var language = GetOrCreateLanguage(culture, culture); - var dbPrompt = language.Prompts.FirstOrDefault(p => p.TextKey == key.ToString()); - if (dbPrompt != null) - { - dbPrompt.Text = translatedText; - dbPrompt.UpdatedAt = DateTime.Now; - dbPrompt.UpdatedBy = Thread.CurrentPrincipal.Identity.Name; - } - else - { - dbPrompt = new ViewPromptDocument - { - LocaleId = culture.LCID, - TextName = textName, - Text = translatedText, - TextKey = key.ToString(), - UpdatedAt = DateTime.Now, - UpdatedBy = Thread.CurrentPrincipal.Identity.Name - }; - language.Prompts.Add(dbPrompt); - } - - _logger.Debug("Saving prompt " + dbPrompt.ViewPath + "/" + dbPrompt.TextName); - _documentSession.Store(language); - _documentSession.SaveChanges(); - } - - /// - /// checks if the specified language exists. - /// - /// Language to find - /// true if found; otherwise false. - public bool Exists(CultureInfo cultureInfo) - { - return GetLanguage(cultureInfo) != null; - } - - /// - /// Create a new prompt in the specified language - /// - /// Language that the translation is for - /// Path to view. You can use - /// Text to translate - /// Translated text - public void CreatePrompt(CultureInfo culture, string viewPath, string textName, string translatedText) - { - if (culture == null) throw new ArgumentNullException("culture"); - if (viewPath == null) throw new ArgumentNullException("viewPath"); - if (textName == null) throw new ArgumentNullException("textName"); - if (translatedText == null) throw new ArgumentNullException("translatedText"); - - var key = new ViewPromptKey(viewPath, textName); - - var language = GetOrCreateLanguage(culture, culture); - var dbPrompt = language.Prompts.FirstOrDefault(p => p.TextKey == key.ToString()); - if (dbPrompt == null) - { - _logger.Debug("Created prompt " + viewPath + " " + textName); - dbPrompt = new ViewPromptDocument - { - TextKey = key.ToString(), - Text = translatedText, - LocaleId = culture.LCID, - TextName = textName, - ViewPath = viewPath, - UpdatedAt = DateTime.Today, - UpdatedBy = Thread.CurrentPrincipal.Identity.Name - }; - language.Prompts.Add(dbPrompt); - } - else - { - dbPrompt.Text = translatedText; - } - SetAsModified(language); - } - - /// - /// Delete a prompt - /// - /// Culture to delete the prompt for - /// Prompt key - public void Delete(CultureInfo culture, ViewPromptKey key) - { - var language = GetOrCreateLanguage(culture, culture); - if (language != null && language.Delete(key)) - { - SetAsModified(language); - } - } - - /// - /// Get all prompts that have not been translated - /// - /// Culture to get translation for - /// Default language - /// A collection of prompts - /// - /// Default language will typically have more translated prompts than any other language - /// and is therefore used to detect missing prompts. - /// - public IEnumerable GetNotLocalizedPrompts(CultureInfo culture, CultureInfo defaultCulture) - { - var sourceLanguage = GetOrCreateLanguage(defaultCulture, defaultCulture); - var ourLanguage = GetLanguage(culture) ?? new ViewLocalizationDocument {Id = culture.Name}; - return - sourceLanguage.Prompts.Except(ourLanguage.Prompts.Where(p => p.Text != "")).Select(CreatePrompt).ToList(); - } - - /// - /// Create a new language - /// - /// Language to create - /// The default culture. - /// - /// Will add empty entries for all known entries. Entries are added automatically to the default language when views - /// are visited. This is NOT done for any other language. - /// - public void CreateForLanguage(CultureInfo culture, CultureInfo defaultCulture) - { - GetOrCreateLanguage(culture, defaultCulture); - } - - private void SetAsModified(ViewLocalizationDocument language) - { - lock (_modifiedDocuments) - { - if (!_modifiedDocuments.Contains(language)) - _modifiedDocuments.AddLast(language); - } - } - - private ViewLocalizationDocument GetOrCreateLanguage(CultureInfo culture, CultureInfo defaultCulture) - { - var document = GetLanguage(culture); - if (document == null) - { - _logger.Debug("Failed to find language " + culture.Name + ", creating it using " + defaultCulture.Name + - " as a template."); - var defaultLang = culture.LCID == defaultCulture.LCID - ? new ViewLocalizationDocument - {Id = culture.Name, Prompts = new List()} - : GetOrCreateLanguage(defaultCulture, defaultCulture); - - document = defaultLang.Clone(culture); - _documentSession.Store(document); - _documentSession.SaveChanges(); - lock (Cache) - Cache[culture.LCID] = document; - } - - return document; - } - - private ViewLocalizationDocument GetLanguage(CultureInfo culture) - { - ViewLocalizationDocument document; - lock (Cache) - { - if (Cache.TryGetValue(culture.LCID, out document)) - return document; - } - - document = (from p in _documentSession.Query() - where p.Id == culture.Name - select p).FirstOrDefault(); - lock (Cache) - { - Cache[culture.LCID] = document; - } - - return document; - } - - private ViewPrompt CreatePrompt(ViewPromptDocument prompt) - { - return new ViewPrompt - { - ViewPath = prompt.ViewPath, - LocaleId = prompt.LocaleId, - Key = new ViewPromptKey(prompt.TextKey), - TextName = prompt.TextName, - TranslatedText = prompt.Text - }; - } - - #endregion - - #region IDisposable Members - - /// - /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. - /// - /// 2 - public void Dispose() - { - lock (_modifiedDocuments) - { - if (_modifiedDocuments.Count > 0) - _logger.Debug("Writing cache"); - - foreach (var document in _modifiedDocuments) - { - _documentSession.Store(document); - } - _modifiedDocuments.Clear(); - _documentSession.SaveChanges(); - } - } - - #endregion - } +using Griffin.MvcContrib.Localization; +using Griffin.MvcContrib.Localization.Views; +using Griffin.MvcContrib.Logging; +using Raven.Client; +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; +using System.Threading; + +namespace Griffin.MvcContrib.RavenDb.Localization +{ + /// + /// RavenDB repository for view localizations + /// + /// Remember to set + public class ViewLocalizationRepository : IViewLocalizationRepository, IDisposable + { + private static readonly Dictionary Cache = + new Dictionary(); + + private readonly IDocumentSession _documentSession; + + private readonly ILogger _logger = LogProvider.Current.GetLogger(); + + private readonly LinkedList _modifiedDocuments = + new LinkedList(); + + /// + /// Initializes a new instance of the class. + /// + /// The document session. + public ViewLocalizationRepository(IDocumentSession documentSession) + { + _documentSession = documentSession; + } + + #region Implementation of IViewLocalizationRepository + + /// + /// Get all prompts that have been created for an language + /// + /// Culture to get translation for + /// Culture to find not translated prompts in (or same culture to disable) + /// Used to limit the search result + /// + /// A collection of prompts + /// + public IEnumerable GetAllPrompts(CultureInfo culture, CultureInfo templateCulture, + SearchFilter filter) + { + return GetOrCreateLanguage(culture, templateCulture).Prompts.Select(CreatePrompt); + } + + /// + /// Create translation for a new language + /// + /// Language to create + /// Language to use as a template + public void CreateLanguage(CultureInfo culture, CultureInfo templateCulture) + { + var sourceLang = GetLanguage(culture); + var newLang = new ViewLocalizationDocument + { + Id = culture.Name, + Prompts = sourceLang.Prompts.Select(p => new ViewPromptDocument(p) + { + UpdatedAt = DateTime.Now, + UpdatedBy = + Thread.CurrentPrincipal.Identity. + Name, + Text = "" + }).ToList() + }; + + lock (_modifiedDocuments) + { + _modifiedDocuments.AddLast(newLang); + } + } + + /// + /// Get all languages that have translations + /// + /// Collection of languages + public IEnumerable GetAvailableLanguages() + { + var languages = from p in _documentSession.Query() + select p.Id; + return languages.ToList().Select(p => new CultureInfo(p)); + } + + /// + /// Get a text using it's name. + /// + /// Culture to get prompt for + /// + /// Prompt if found; otherwise null. + public ViewPrompt GetPrompt(CultureInfo culture, ViewPromptKey key) + { + if (culture == null) throw new ArgumentNullException("culture"); + if (key == null) throw new ArgumentNullException("key"); + + var language = GetLanguage(culture); + if (language == null) + return null; + + return language.Prompts.Where(p => p.TextKey == key.ToString()).Select(CreatePrompt).FirstOrDefault(); + } + + /// + /// Save/Update a text prompt + /// + /// Language to save prompt in + /// Path to view. You can use + /// Text to translate + /// Translated text + public void Save(CultureInfo culture, string viewPath, string textName, string translatedText) + { + if (culture == null) throw new ArgumentNullException("culture"); + if (viewPath == null) throw new ArgumentNullException("viewPath"); + if (textName == null) throw new ArgumentNullException("textName"); + if (translatedText == null) throw new ArgumentNullException("translatedText"); + + var key = new ViewPromptKey(viewPath, textName); + var language = GetOrCreateLanguage(culture, culture); + var dbPrompt = language.Prompts.FirstOrDefault(p => p.TextKey == key.ToString()); + if (dbPrompt != null) + { + dbPrompt.Text = translatedText; + dbPrompt.UpdatedAt = DateTime.Now; + dbPrompt.UpdatedBy = Thread.CurrentPrincipal.Identity.Name; + } + else + { + dbPrompt = new ViewPromptDocument + { + LocaleId = culture.LCID, + TextName = textName, + Text = translatedText, + TextKey = key.ToString(), + UpdatedAt = DateTime.Now, + UpdatedBy = Thread.CurrentPrincipal.Identity.Name + }; + language.Prompts.Add(dbPrompt); + } + + _logger.Debug("Saving prompt " + dbPrompt.ViewPath + "/" + dbPrompt.TextName); + _documentSession.Store(language); + _documentSession.SaveChanges(); + } + + /// + /// checks if the specified language exists. + /// + /// Language to find + /// true if found; otherwise false. + public bool Exists(CultureInfo cultureInfo) + { + return GetLanguage(cultureInfo) != null; + } + + /// + /// Create a new prompt in the specified language + /// + /// Language that the translation is for + /// Path to view. You can use + /// Text to translate + /// Translated text + public void CreatePrompt(CultureInfo culture, string viewPath, string textName, string translatedText) + { + if (culture == null) throw new ArgumentNullException("culture"); + if (viewPath == null) throw new ArgumentNullException("viewPath"); + if (textName == null) throw new ArgumentNullException("textName"); + if (translatedText == null) throw new ArgumentNullException("translatedText"); + + var key = new ViewPromptKey(viewPath, textName); + + var language = GetOrCreateLanguage(culture, culture); + var dbPrompt = language.Prompts.FirstOrDefault(p => p.TextKey == key.ToString()); + if (dbPrompt == null) + { + _logger.Debug("Created prompt " + viewPath + " " + textName); + dbPrompt = new ViewPromptDocument + { + TextKey = key.ToString(), + Text = translatedText, + LocaleId = culture.LCID, + TextName = textName, + ViewPath = viewPath, + UpdatedAt = DateTime.Today, + UpdatedBy = Thread.CurrentPrincipal.Identity.Name + }; + language.Prompts.Add(dbPrompt); + } + else + { + dbPrompt.Text = translatedText; + } + SetAsModified(language); + } + + /// + /// Delete a prompt + /// + /// Culture to delete the prompt for + /// Prompt key + public void Delete(CultureInfo culture, ViewPromptKey key) + { + var language = GetOrCreateLanguage(culture, culture); + if (language != null && language.Delete(key)) + { + SetAsModified(language); + } + } + + /// + /// Get all prompts that have not been translated + /// + /// Culture to get translation for + /// Default language + /// A collection of prompts + /// + /// Default language will typically have more translated prompts than any other language + /// and is therefore used to detect missing prompts. + /// + public IEnumerable GetNotLocalizedPrompts(CultureInfo culture, CultureInfo defaultCulture) + { + var sourceLanguage = GetOrCreateLanguage(defaultCulture, defaultCulture); + var ourLanguage = GetLanguage(culture) ?? new ViewLocalizationDocument { Id = culture.Name }; + return + sourceLanguage.Prompts.Except(ourLanguage.Prompts.Where(p => p.Text != "")).Select(CreatePrompt).ToList(); + } + + /// + /// Create a new language + /// + /// Language to create + /// The default culture. + /// + /// Will add empty entries for all known entries. Entries are added automatically to the default language when views + /// are visited. This is NOT done for any other language. + /// + public void CreateForLanguage(CultureInfo culture, CultureInfo defaultCulture) + { + GetOrCreateLanguage(culture, defaultCulture); + } + + private void SetAsModified(ViewLocalizationDocument language) + { + lock (_modifiedDocuments) + { + if (!_modifiedDocuments.Contains(language)) + _modifiedDocuments.AddLast(language); + } + } + + private ViewLocalizationDocument GetOrCreateLanguage(CultureInfo culture, CultureInfo defaultCulture) + { + var document = GetLanguage(culture); + if (document == null) + { + _logger.Debug("Failed to find language " + culture.Name + ", creating it using " + defaultCulture.Name + + " as a template."); + var defaultLang = culture.LCID == defaultCulture.LCID + ? new ViewLocalizationDocument { Id = culture.Name, Prompts = new List() } + : GetOrCreateLanguage(defaultCulture, defaultCulture); + + document = defaultLang.Clone(culture); + _documentSession.Store(document); + _documentSession.SaveChanges(); + lock (Cache) + Cache[culture.LCID] = document; + } + + return document; + } + + private ViewLocalizationDocument GetLanguage(CultureInfo culture) + { + ViewLocalizationDocument document; + lock (Cache) + { + if (Cache.TryGetValue(culture.LCID, out document)) + return document; + } + + document = _documentSession.Load(culture.Name); + lock (Cache) + { + Cache[culture.LCID] = document; + } + + return document; + } + + private ViewPrompt CreatePrompt(ViewPromptDocument prompt) + { + return new ViewPrompt + { + ViewPath = prompt.ViewPath, + LocaleId = prompt.LocaleId, + Key = new ViewPromptKey(prompt.TextKey), + TextName = prompt.TextName, + TranslatedText = prompt.Text + }; + } + + #endregion + + #region IDisposable Members + + /// + /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. + /// + /// 2 + public void Dispose() + { + lock (_modifiedDocuments) + { + if (_modifiedDocuments.Count > 0) + _logger.Debug("Writing cache"); + + foreach (var document in _modifiedDocuments) + { + _documentSession.Store(document); + } + _modifiedDocuments.Clear(); + _documentSession.SaveChanges(); + } + } + + #endregion + } } \ No newline at end of file