using System.Text.RegularExpressions; using System.Xml; using Microsoft.Net.Http.Headers; using Nop.Core; using Nop.Core.Http; using Nop.Core.Infrastructure; using Nop.Data; using Nop.Services.Common; namespace Nop.Web.Infrastructure.Installation; /// /// Localization service for installation process /// public partial class InstallationLocalizationService : IInstallationLocalizationService { #region Fields protected readonly IHttpContextAccessor _httpContextAccessor; protected readonly INopFileProvider _fileProvider; protected readonly IWebHelper _webHelper; protected IList _availableLanguages; #endregion #region Ctor public InstallationLocalizationService(IHttpContextAccessor httpContextAccessor, INopFileProvider fileProvider, IWebHelper webHelper) { _httpContextAccessor = httpContextAccessor; _fileProvider = fileProvider; _webHelper = webHelper; } #endregion #region Methods /// /// Get locale resource value /// /// Resource name /// Resource value public string GetResource(string resourceName) { var language = GetCurrentLanguage(); if (language == null) return resourceName; var resourceValue = language.Resources .Where(r => r.Name.Equals(resourceName, StringComparison.InvariantCultureIgnoreCase)) .Select(r => r.Value).FirstOrDefault(); if (string.IsNullOrEmpty(resourceValue)) return resourceName; return resourceValue; } /// /// Get current browser culture /// /// Current culture public string GetBrowserCulture() { _httpContextAccessor.HttpContext.Request.Headers.TryGetValue(HeaderNames.AcceptLanguage, out var userLanguages); return userLanguages.FirstOrDefault()?.Split(',').FirstOrDefault() ?? NopCommonDefaults.DefaultLanguageCulture; } /// /// Get current language for the installation page /// /// Current language public virtual InstallationLanguage GetCurrentLanguage() { var httpContext = _httpContextAccessor.HttpContext; //try to get cookie var cookieName = $"{NopCookieDefaults.Prefix}{NopCookieDefaults.InstallationLanguageCookie}"; httpContext.Request.Cookies.TryGetValue(cookieName, out var cookieLanguageCode); //ensure it's available (it could be delete since the previous installation) var availableLanguages = GetAvailableLanguages(); var language = availableLanguages .FirstOrDefault(l => l.Code.Equals(cookieLanguageCode, StringComparison.InvariantCultureIgnoreCase)); if (language != null) return language; //let's find by current browser culture if (httpContext.Request.Headers.TryGetValue(HeaderNames.AcceptLanguage, out var userLanguages)) { var userLanguage = userLanguages.FirstOrDefault()?.Split(',').FirstOrDefault() ?? string.Empty; if (!string.IsNullOrEmpty(userLanguage)) { //right. we do "StartsWith" (not "Equals") because we have shorten codes (not full culture names) language = availableLanguages.FirstOrDefault(l => userLanguage.StartsWith(l.Code, StringComparison.InvariantCultureIgnoreCase)); } } if (language != null) return language; //let's return the default one language = availableLanguages.FirstOrDefault(l => l.IsDefault); if (language != null) return language; //return any available language language = availableLanguages.FirstOrDefault(); return language; } /// /// Save a language for the installation page /// /// Language code public virtual void SaveCurrentLanguage(string languageCode) { var httpContext = _httpContextAccessor.HttpContext; var cookieOptions = new CookieOptions { Expires = DateTime.Now.AddHours(24), HttpOnly = true, Secure = _webHelper.IsCurrentConnectionSecured() }; var cookieName = $"{NopCookieDefaults.Prefix}{NopCookieDefaults.InstallationLanguageCookie}"; httpContext.Response.Cookies.Delete(cookieName); httpContext.Response.Cookies.Append(cookieName, languageCode, cookieOptions); } /// /// Get a list of available languages /// /// Available installation languages public virtual IList GetAvailableLanguages() { if (_availableLanguages != null) return _availableLanguages; _availableLanguages = new List(); foreach (var filePath in _fileProvider.EnumerateFiles(_fileProvider.MapPath("~/App_Data/Localization/Installation/"), "*.xml")) { var xmlDocument = new XmlDocument(); xmlDocument.Load(filePath); //get language code var languageCode = ""; //we file name format: installation.{languagecode}.xml var r = new Regex(Regex.Escape("installation.") + "(.*?)" + Regex.Escape(".xml")); var matches = r.Matches(_fileProvider.GetFileName(filePath)); foreach (Match match in matches) languageCode = match.Groups[1].Value; //at now we use language codes only (not full culture names) languageCode = languageCode[..2]; var languageNode = xmlDocument.SelectSingleNode(@"//Language"); if (languageNode == null || languageNode.Attributes == null) continue; //get language friendly name var languageName = languageNode.Attributes["Name"].InnerText.Trim(); //is default var isDefaultAttribute = languageNode.Attributes["IsDefault"]; var isDefault = isDefaultAttribute != null && Convert.ToBoolean(isDefaultAttribute.InnerText.Trim()); //is default var isRightToLeftAttribute = languageNode.Attributes["IsRightToLeft"]; var isRightToLeft = isRightToLeftAttribute != null && Convert.ToBoolean(isRightToLeftAttribute.InnerText.Trim()); //create language var language = new InstallationLanguage { Code = languageCode, Name = languageName, IsDefault = isDefault, IsRightToLeft = isRightToLeft, }; //load resources var resources = xmlDocument.SelectNodes(@"//Language/LocaleResource"); if (resources == null) continue; foreach (XmlNode resNode in resources) { if (resNode.Attributes == null) continue; var resNameAttribute = resNode.Attributes["Name"]; var resValueNode = resNode.SelectSingleNode("Value"); if (resNameAttribute == null) throw new NopException("All installation resources must have an attribute Name=\"Value\"."); var resourceName = resNameAttribute.Value.Trim(); if (string.IsNullOrEmpty(resourceName)) throw new NopException("All installation resource attributes 'Name' must have a value.'"); if (resValueNode == null) throw new NopException("All installation resources must have an element \"Value\"."); var resourceValue = resValueNode.InnerText.Trim(); language.Resources.Add(new InstallationLocaleResource { Name = resourceName, Value = resourceValue }); } _availableLanguages.Add(language); _availableLanguages = _availableLanguages.OrderBy(l => l.Name).ToList(); } return _availableLanguages; } /// /// Get a dictionary of available data provider types /// /// Values to exclude /// Localize /// Key-value pairs of available data providers types public Dictionary GetAvailableProviderTypes(int[] valuesToExclude = null, bool useLocalization = true) { return Enum.GetValues(typeof(DataProviderType)) .Cast() .Where(enumValue => enumValue != DataProviderType.Unknown && (valuesToExclude == null || !valuesToExclude.Contains(Convert.ToInt32(enumValue)))) .ToDictionary( enumValue => Convert.ToInt32(enumValue), enumValue => useLocalization ? GetResource(enumValue.ToString()) : CommonHelper.SplitCamelCaseWord(enumValue.ToString())); } #endregion }