NopCommerce为了语言的国际化,它支持多国家的语言,你可以系统在添加任意多个国家语言。我之前的文章NopCommerce源码架构详解--使用FluentValidation创建Model自定义Validator验证源码分析就有提高到过nop的-Localization多语言。今天我就来详细介绍一下Nop是怎么实现的Localization多语言本地化。
首先,来看看Nop中与语言相关的表。
Nop主要有两个表来存储语言,分别是LocaleStringResource(每个语言相关明细--资源字符串)和Language(语言种类)
LocaleStringResource表:
SELECT TOP 1000 [Id] ,[LanguageId] ,[ResourceName] ,[ResourceValue] FROM [LocaleStringResource]

Language表:
SELECT TOP 1000 [Id] ,[Name] ,[LanguageCulture] ,[UniqueseoCode] ,[FlagImageFileName] ,[Rtl] ,[LimitedToStores] ,[DefaultCurrencyId] ,[Published] ,[DisplayOrder] FROM [Language]

接下来我们来通过一个验证提示信息类BlogPostValidator来看看这个多语言是怎么实现的?Nop的验证Validator可以参考:NopCommerce源码架构详解--使用FluentValidation创建Model自定义Validator验证源码分析
BlogPostValidator.cs:
public class BlogPostValidator : AbstractValidator<BlogPostModel> { public BlogPostValidator(ILocalizationService localizationService) { RuleFor(x => x.Title) .NotEmpty() .WithMessage(localizationService.GetResource("Admin.ContentManagement.Blog.BlogPosts.Fields.Title.Required")); RuleFor(x => x.Body) .NotEmpty() .WithMessage(localizationService.GetResource("Admin.ContentManagement.Blog.BlogPosts.Fields.Body.Required")); } }
接口ILocalizationService的真正实现类是Nop.Services.Localization.LocalizationService,其中里面的方法GetResource为:
public virtual string GetResource(string resourceKey, int languageId, bool logIfNotFound = true, string defaultValue = "", bool returnEmptyIfNotFound = false) { string result = string.Empty; if (resourceKey == null) resourceKey = string.Empty; resourceKey = resourceKey.Trim().ToLowerInvariant(); if (_localizationSettings.LoadAllLocaleRecordsOnStartup) { //load all records (we know they are cached) var resources = GetAllResourceValues(languageId); if (resources.ContainsKey(resourceKey)) { result = resources[resourceKey].Value; } } else { //gradual loading string key = string.Format(LOCALSTRINGRESOURCES_BY_RESOURCENAME_KEY, languageId, resourceKey); string lsr = _cacheManager.Get(key, () => { var query = from l in _lsrRepository.Table where l.ResourceName == resourceKey && l.LanguageId == languageId select l.ResourceValue; return query.FirstOrDefault(); }); if (lsr != null) result = lsr; } if (String.IsNullOrEmpty(result)) { if (logIfNotFound) _logger.Warning(string.Format("Resource string ({0}) is not found. Language ID = {1}", resourceKey, languageId)); if (!String.IsNullOrEmpty(defaultValue)) { result = defaultValue; } else { if (!returnEmptyIfNotFound) result = resourceKey; } } return result; }
public virtual string GetResource(string resourceKey) { if (_workContext.WorkingLanguage != null) return GetResource(resourceKey, _workContext.WorkingLanguage.Id); return ""; }
接口IWorkContext真正实现类是Nop.Web.Framework.WebWorkContext,里面有一个获取语言的属性。
public virtual Language WorkingLanguage { get { if (_cachedLanguage != null) return _cachedLanguage; Language detectedLanguage = null; if (_localizationSettings.SeoFriendlyUrlsForLanguagesEnabled) { //从URL中获取语言 detectedLanguage = GetLanguageFromUrl(); } if (detectedLanguage == null && _localizationSettings.AutomaticallyDetectLanguage) { //get language from browser settings //but we do it only once if (!this.CurrentCustomer.GetAttribute<bool>(SystemCustomerAttributeNames.LanguageAutomaticallyDetected, _genericAttributeService, _storeContext.CurrentStore.Id)) { detectedLanguage = GetLanguageFromBrowserSettings(); if (detectedLanguage != null) { _genericAttributeService.SaveAttribute(this.CurrentCustomer, SystemCustomerAttributeNames.LanguageAutomaticallyDetected, true, _storeContext.CurrentStore.Id); } } } if (detectedLanguage != null) { //the language is detected. now we need to save it if (this.CurrentCustomer.GetAttribute<int>(SystemCustomerAttributeNames.LanguageId, _genericAttributeService, _storeContext.CurrentStore.Id) != detectedLanguage.Id) { _genericAttributeService.SaveAttribute(this.CurrentCustomer, SystemCustomerAttributeNames.LanguageId, detectedLanguage.Id, _storeContext.CurrentStore.Id); } } var allLanguages = _languageService.GetAllLanguages(storeId: _storeContext.CurrentStore.Id); //find current customer language var languageId = this.CurrentCustomer.GetAttribute<int>(SystemCustomerAttributeNames.LanguageId, _genericAttributeService, _storeContext.CurrentStore.Id); var language = allLanguages.FirstOrDefault(x => x.Id == languageId); if (language == null) { //如果没有指定语言,默认返回系统中的第一种语言 language = allLanguages.FirstOrDefault(); } if (language == null) { //it not specified, then return the first found one language = _languageService.GetAllLanguages().FirstOrDefault(); } //cache _cachedLanguage = language; return _cachedLanguage; } set { var languageId = value != null ? value.Id : 0; _genericAttributeService.SaveAttribute(this.CurrentCustomer, SystemCustomerAttributeNames.LanguageId, languageId, _storeContext.CurrentStore.Id); //reset cache _cachedLanguage = null; } }