diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs index 946076b65b..d400cc1d56 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/CachedObjectExtensionsDtoService.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; using Volo.Abp.DependencyInjection; +using Volo.Abp.Localization; using Volo.Abp.ObjectExtending; using Volo.Abp.Reflection; @@ -58,7 +59,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending Type = TypeHelper.GetFullNameHandlingNullableAndGenerics(propertyConfig.Type), TypeSimple = TypeHelper.GetSimplifiedName(propertyConfig.Type), Attributes = new List(), - DisplayName = LocalizedDisplayNameDto.CreateOrNull(propertyConfig.DisplayName), + DisplayName = CreateDisplayNameDto(propertyConfig), Ui = new ModuleObjectExtraPropertyUiExtensionDto { CreateForm = new ModuleObjectExtraPropertyUiFormExtensionDto @@ -88,5 +89,34 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending return objectExtensionsDto; } + + private static LocalizableStringDto CreateDisplayNameDto( + ModuleEntityObjectPropertyExtensionConfiguration propertyConfig) + { + if (propertyConfig.DisplayName == null) + { + return null; + } + + if (propertyConfig.DisplayName is LocalizableString localizableStringInstance) + { + return new LocalizableStringDto + { + Name = localizableStringInstance.Name, + Resource = LocalizationResourceNameAttribute.GetName(localizableStringInstance.ResourceType) + }; + } + + if (propertyConfig.DisplayName is FixedLocalizableString fixedLocalizableString) + { + return new LocalizableStringDto + { + Name = fixedLocalizableString.Value, + Resource = "_" + }; + } + + return null; + } } } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/LocalizableStringDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/LocalizableStringDto.cs new file mode 100644 index 0000000000..307831315b --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/LocalizableStringDto.cs @@ -0,0 +1,14 @@ +using System; +using JetBrains.Annotations; + +namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending +{ + [Serializable] + public class LocalizableStringDto + { + public string Name { get; set; } + + [CanBeNull] + public string Resource { get; set; } + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/LocalizedDisplayNameDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/LocalizedDisplayNameDto.cs deleted file mode 100644 index 748daa58b9..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/LocalizedDisplayNameDto.cs +++ /dev/null @@ -1,37 +0,0 @@ -using System; -using JetBrains.Annotations; -using Volo.Abp.Localization; - -namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending -{ - [Serializable] - public class LocalizedDisplayNameDto - { - public string Name { get; set; } - - public string Resource { get; set; } - - [CanBeNull] - public static LocalizedDisplayNameDto CreateOrNull(ILocalizableString localizableString) - { - if (localizableString is LocalizableString localizableStringInstance) - { - return new LocalizedDisplayNameDto - { - Name = localizableStringInstance.Name, - Resource = LocalizationResourceNameAttribute.GetName(localizableStringInstance.ResourceType) - }; - } - - if (localizableString is FixedLocalizableString fixedLocalizableString) - { - return new LocalizedDisplayNameDto - { - Name = fixedLocalizableString.Value, - }; - } - - return null; - } - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ModuleObjectExtraPropertyExtensionDto.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ModuleObjectExtraPropertyExtensionDto.cs index 853a27e294..661da59f60 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ModuleObjectExtraPropertyExtensionDto.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.Contracts/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ObjectExtending/ModuleObjectExtraPropertyExtensionDto.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using JetBrains.Annotations; namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending { @@ -10,7 +11,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations.ObjectExtending public string TypeSimple { get; set; } - public LocalizedDisplayNameDto DisplayName { get; set; } + [CanBeNull] + public LocalizableStringDto DisplayName { get; set; } public ModuleObjectExtraPropertyUiExtensionDto Ui { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ViewFeatures/AbpValidationHtmlAttributeProvider.cs b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ViewFeatures/AbpValidationHtmlAttributeProvider.cs index f0c4c628b8..563ebe9d4a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ViewFeatures/AbpValidationHtmlAttributeProvider.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ViewFeatures/AbpValidationHtmlAttributeProvider.cs @@ -103,7 +103,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ViewFeatures if (modelExplorer.Metadata is DefaultModelMetadata metadata) { metadata.DisplayMetadata.DisplayName = - () => extensionPropertyInfo.DisplayName.Localize(_stringLocalizerFactory); + () => extensionPropertyInfo.GetDisplayName(_stringLocalizerFactory); } foreach (var validationAttribute in extensionPropertyInfo.GetValidationAttributes()) diff --git a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs index 34931bfc95..3995bf4440 100644 --- a/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs +++ b/framework/src/Volo.Abp.Core/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs @@ -1,6 +1,6 @@ namespace Microsoft.Extensions.Localization { - public static class AbpStringLocalizerFactoryExtensions + public static class AbpCoreStringLocalizerFactoryExtensions { public static IStringLocalizer Create(this IStringLocalizerFactory localizerFactory) { diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs new file mode 100644 index 0000000000..0ba8d0daed --- /dev/null +++ b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/AbpStringLocalizerFactoryExtensions.cs @@ -0,0 +1,11 @@ +namespace Microsoft.Extensions.Localization +{ + public static class AbpStringLocalizerFactoryExtensions + { + public static IStringLocalizer CreateDefaultOrNull(this IStringLocalizerFactory localizerFactory) + { + return (localizerFactory as IAbpStringLocalizerFactoryWithDefaultResourceSupport) + ?.CreateDefaultOrNull(); + } + } +} diff --git a/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactoryWithDefaultResourceSupport.cs b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactoryWithDefaultResourceSupport.cs new file mode 100644 index 0000000000..b749e454a3 --- /dev/null +++ b/framework/src/Volo.Abp.Localization.Abstractions/Microsoft/Extensions/Localization/IAbpStringLocalizerFactoryWithDefaultResourceSupport.cs @@ -0,0 +1,10 @@ +using JetBrains.Annotations; + +namespace Microsoft.Extensions.Localization +{ + public interface IAbpStringLocalizerFactoryWithDefaultResourceSupport + { + [CanBeNull] + IStringLocalizer CreateDefaultOrNull(); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs index 103567248f..cd347d8437 100644 --- a/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs +++ b/framework/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs @@ -9,13 +9,12 @@ using Microsoft.Extensions.Options; namespace Volo.Abp.Localization { - public class AbpStringLocalizerFactory : IStringLocalizerFactory + public class AbpStringLocalizerFactory : IStringLocalizerFactory, IAbpStringLocalizerFactoryWithDefaultResourceSupport { - private readonly ResourceManagerStringLocalizerFactory _innerFactory; - private readonly AbpLocalizationOptions _abpLocalizationOptions; - private readonly IServiceProvider _serviceProvider; - - private readonly ConcurrentDictionary _localizerCache; + protected internal AbpLocalizationOptions AbpLocalizationOptions { get; } + protected ResourceManagerStringLocalizerFactory InnerFactory { get; } + protected IServiceProvider ServiceProvider { get; } + protected ConcurrentDictionary LocalizerCache { get; } //TODO: It's better to use decorator pattern for IStringLocalizerFactory instead of getting ResourceManagerStringLocalizerFactory as a dependency. public AbpStringLocalizerFactory( @@ -23,29 +22,29 @@ namespace Volo.Abp.Localization IOptions abpLocalizationOptions, IServiceProvider serviceProvider) { - _innerFactory = innerFactory; - _serviceProvider = serviceProvider; - _abpLocalizationOptions = abpLocalizationOptions.Value; + InnerFactory = innerFactory; + ServiceProvider = serviceProvider; + AbpLocalizationOptions = abpLocalizationOptions.Value; - _localizerCache = new ConcurrentDictionary(); + LocalizerCache = new ConcurrentDictionary(); } public virtual IStringLocalizer Create(Type resourceType) { - var resource = _abpLocalizationOptions.Resources.GetOrDefault(resourceType); + var resource = AbpLocalizationOptions.Resources.GetOrDefault(resourceType); if (resource == null) { - return _innerFactory.Create(resourceType); + return InnerFactory.Create(resourceType); } - if (_localizerCache.TryGetValue(resourceType, out var cacheItem)) + if (LocalizerCache.TryGetValue(resourceType, out var cacheItem)) { return cacheItem.Localizer; } - lock (_localizerCache) + lock (LocalizerCache) { - return _localizerCache.GetOrAdd( + return LocalizerCache.GetOrAdd( resourceType, _ => CreateStringLocalizerCacheItem(resource) ).Localizer; @@ -54,12 +53,12 @@ namespace Volo.Abp.Localization private StringLocalizerCacheItem CreateStringLocalizerCacheItem(LocalizationResource resource) { - foreach (var globalContributor in _abpLocalizationOptions.GlobalContributors) + foreach (var globalContributor in AbpLocalizationOptions.GlobalContributors) { resource.Contributors.Add((ILocalizationResourceContributor) Activator.CreateInstance(globalContributor)); } - using (var scope = _serviceProvider.CreateScope()) + using (var scope = ServiceProvider.CreateScope()) { var context = new LocalizationResourceInitializationContext(resource, scope.ServiceProvider); @@ -81,7 +80,7 @@ namespace Volo.Abp.Localization { //TODO: Investigate when this is called? - return _innerFactory.Create(baseName, location); + return InnerFactory.Create(baseName, location); } internal static void Replace(IServiceCollection services) @@ -90,7 +89,7 @@ namespace Volo.Abp.Localization services.AddSingleton(); } - private class StringLocalizerCacheItem + protected class StringLocalizerCacheItem { public AbpDictionaryBasedStringLocalizer Localizer { get; } @@ -99,5 +98,15 @@ namespace Volo.Abp.Localization Localizer = localizer; } } + + public IStringLocalizer CreateDefaultOrNull() + { + if (AbpLocalizationOptions.DefaultResourceType == null) + { + return null; + } + + return Create(AbpLocalizationOptions.DefaultResourceType); + } } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ModuleEntityObjectPropertyExtensionConfiguration.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ModuleEntityObjectPropertyExtensionConfiguration.cs index bdc8d37e1e..bf965ba955 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ModuleEntityObjectPropertyExtensionConfiguration.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ModuleEntityObjectPropertyExtensionConfiguration.cs @@ -22,17 +22,8 @@ namespace Volo.Abp.ObjectExtending [NotNull] public List> Validators { get; } - [NotNull] - public ILocalizableString DisplayName - { - get => _displayName; - set - { - Check.NotNull(value, nameof(value)); - _displayName = value; - } - } - private ILocalizableString _displayName; + [CanBeNull] + public ILocalizableString DisplayName { get; set; } [NotNull] public Dictionary Configuration { get; } @@ -49,8 +40,6 @@ namespace Volo.Abp.ObjectExtending Type = Check.NotNull(type, nameof(type)); Name = Check.NotNull(name, nameof(name)); - DisplayName = new FixedLocalizableString(Name); - Configuration = new Dictionary(); Attributes = new List(); Validators = new List>(); diff --git a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs index c0792fbe51..59f42b1494 100644 --- a/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs +++ b/framework/src/Volo.Abp.ObjectExtending/Volo/Abp/ObjectExtending/ObjectExtensionPropertyInfo.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.ComponentModel.DataAnnotations; using JetBrains.Annotations; +using Microsoft.Extensions.Localization; using Volo.Abp.Localization; namespace Volo.Abp.ObjectExtending @@ -27,17 +28,8 @@ namespace Volo.Abp.ObjectExtending [NotNull] public List> Validators { get; } - [NotNull] - public ILocalizableString DisplayName - { - get => _displayName; - set - { - Check.NotNull(value, nameof(value)); - _displayName = value; - } - } - private ILocalizableString _displayName; + [CanBeNull] + public ILocalizableString DisplayName { get; set; } /// /// Indicates whether to check the other side of the object mapping @@ -65,12 +57,40 @@ namespace Volo.Abp.ObjectExtending Type = Check.NotNull(type, nameof(type)); Name = Check.NotNull(name, nameof(name)); - DisplayName = new FixedLocalizableString(Name); - Configuration = new Dictionary(); ValidationAttributes = new List(); Attributes = new List(); Validators = new List>(); } + + [NotNull] + public string GetDisplayName( + [NotNull] IStringLocalizerFactory stringLocalizerFactory) + { + if (DisplayName != null) + { + return DisplayName.Localize(stringLocalizerFactory); + } + + var defaultStringLocalizer = stringLocalizerFactory.CreateDefaultOrNull(); + if (defaultStringLocalizer == null) + { + return Name; + } + + var localizedString = defaultStringLocalizer[$"DisplayName:{Name}"]; + if (!localizedString.ResourceNotFound) + { + return localizedString; + } + + localizedString = defaultStringLocalizer[Name]; + if (!localizedString.ResourceNotFound) + { + return localizedString; + } + + return Name; + } } } diff --git a/npm/packs/core/src/abp.js b/npm/packs/core/src/abp.js index 730db8bc97..fa42828306 100644 --- a/npm/packs/core/src/abp.js +++ b/npm/packs/core/src/abp.js @@ -76,10 +76,17 @@ var abp = abp || {}; abp.localization.values = {}; abp.localization.localize = function (key, sourceName) { + if (sourceName === '_') { //A convention to suppress the localization + return key; + } + sourceName = sourceName || abp.localization.defaultResourceName; + if (!sourceName) { + abp.log.warn('Localization source name is not specified and the defaultResourceName was not defined!'); + return key; + } var source = abp.localization.values[sourceName]; - if (!source) { abp.log.warn('Could not find localization source: ' + sourceName); return key; @@ -97,6 +104,29 @@ var abp = abp || {}; return abp.utils.formatString.apply(this, copiedArguments); }; + abp.localization.isLocalized = function (key, sourceName) { + if (sourceName === '_') { //A convention to suppress the localization + return true; + } + + sourceName = sourceName || abp.localization.defaultResourceName; + if (!sourceName) { + return false; + } + + var source = abp.localization.values[sourceName]; + if (!source) { + return false; + } + + var value = source[key]; + if (value === undefined) { + return false; + } + + return true; + }; + abp.localization.getResource = function (name) { return function () { var copiedArguments = Array.prototype.slice.call(arguments, 0);