diff --git a/docs/Localization.md b/docs/Localization.md index e98864381b..b7cb9e5ea4 100644 --- a/docs/Localization.md +++ b/docs/Localization.md @@ -53,10 +53,9 @@ public class MyModule : AbpModule services.Configure(options => { - options.Resources.AddVirtualJson( - "en", - "/Localization/Resources/Test" - ); + options.Resources + .Add("en") + .AddVirtualJson("/Localization/Resources/Test"); }); } } @@ -64,6 +63,7 @@ public class MyModule : AbpModule In this example; +* Added a new localization resource with "en" (English) as the default culture. * Used JSON files to store the localization strings. * JSON files are embedded into the assembly using the [virtual file system](Virtual-File-System.md). @@ -90,7 +90,7 @@ A JSON localization file content is shown below: Localization resources are also available in the client (JavaScript) side. So, setting a short name for the localization resource makes it easy to use localization texts. Example: ````C# -[ShortLocalizationResourceName("Test")] +[LocalizationResourceName("Test")] public class TestResource { } @@ -114,10 +114,10 @@ Alternative inheritance by configuring the `AbpLocalizationOptions`: ````C# services.Configure(options => { - options.Resources.AddVirtualJson("en", "/Localization/Resources/Test"); - - //Inherit from an existing resource - options.Resources.AddBaseTypes(typeof(AbpValidationResource)); + options.Resources + .Add("en") //Define the resource by "en" default culture + .AddVirtualJson("/Localization/Resources/Test") //Add strings from virtual json files + .AddBaseTypes(typeof(AbpValidationResource)); //Inherit from an existing resource }); ```` @@ -131,13 +131,13 @@ Inheriting from a resource creates a new resource without modifying the existing ````C# services.Configure(options => { - options.Resources.ExtendWithVirtualJson( - "/Localization/Resources/Test/Extensions" - ); + options.Resources + .Get() + .AddVirtualJson("/Localization/Resources/Test/Extensions"); }); ```` -If an extension file defines the same localized string, it overrides the string. +* If an extension file defines the same localized string, it overrides the string. #### Getting Localized Texts diff --git a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder.cs b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder.cs index 9e0ea0e825..9ad4d2343e 100644 --- a/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder.cs +++ b/src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Authorization; using Microsoft.Extensions.DependencyInjection; @@ -74,12 +73,8 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations dictionary[localizedString.Name] = localizedString.Value; } - var resourceShortName = resource.ResourceType - .GetCustomAttributes(true) - .OfType() - .FirstOrDefault()?.Name ?? resource.ResourceType.FullName; - - localizationConfig.Values[resourceShortName] = dictionary; + var resourceName = LocalizationResourceNameAttribute.GetName(resource.ResourceType); + localizationConfig.Values[resourceName] = dictionary; } return localizationConfig; diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs index a7a80a10b9..9d24a97909 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpDictionaryBasedStringLocalizer.cs @@ -72,7 +72,7 @@ namespace Volo.Abp.Localization protected virtual LocalizedString GetLocalizedStringOrNull(string name, string cultureName, bool tryDefaults = true) { - var dictionaries = Resource.DictionaryProvider.Dictionaries; + var dictionaries = Resource.Dictionaries; //Try to get from original dictionary (with country code) if (dictionaries.TryGetValue(cultureName, out var originalDictionary)) @@ -124,7 +124,7 @@ namespace Volo.Abp.Localization { //TODO: Can be optimized (example: if it's already default dictionary, skip overriding) - var dictionaries = Resource.DictionaryProvider.Dictionaries; + var dictionaries = Resource.Dictionaries; var allStrings = new Dictionary(); diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs index 8770b36b38..85dc4b42d5 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/AbpLocalizationModule.cs @@ -19,7 +19,9 @@ namespace Volo.Abp.Localization services.Configure(options => { - options.Resources.AddVirtualJson("en", "/Localization/Resources/AbpValidation"); + options.Resources + .Add("en") + .AddVirtualJson("/Localization/Resources/AbpValidation"); }); services.AddAssemblyOf(); diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationDictionaryProvider.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationDictionaryProvider.cs deleted file mode 100644 index be06f4dd88..0000000000 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationDictionaryProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Volo.Abp.Localization -{ - public interface ILocalizationDictionaryProvider - { - IDictionary Dictionaries { get; } - - event EventHandler Updated; - - void Initialize(LocalizationResourceInitializationContext context); - - void Extend(ILocalizationDictionaryProvider dictionaryProvider); - } -} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs new file mode 100644 index 0000000000..4e0c304aa6 --- /dev/null +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationResourceContributor.cs @@ -0,0 +1,12 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.Localization +{ + public interface ILocalizationResourceContributor + { + event EventHandler Updated; + + List GetDictionaries(LocalizationResourceInitializationContext context); + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationDictionaryProviderBase.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationDictionaryProviderBase.cs deleted file mode 100644 index 28bcd22625..0000000000 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationDictionaryProviderBase.cs +++ /dev/null @@ -1,47 +0,0 @@ -using System; -using System.Collections.Generic; - -namespace Volo.Abp.Localization -{ - public abstract class LocalizationDictionaryProviderBase : ILocalizationDictionaryProvider - { - public IDictionary Dictionaries { get; } - - public event EventHandler Updated; - - protected LocalizationDictionaryProviderBase() - { - Dictionaries = new Dictionary(); - } - - public virtual void Initialize(LocalizationResourceInitializationContext context) - { - } - - public virtual void Extend(ILocalizationDictionaryProvider dictionaryProvider) - { - foreach (var dictionary in dictionaryProvider.Dictionaries.Values) - { - Extend(dictionary); - } - } - - protected virtual void Extend(ILocalizationDictionary dictionary) - { - var existingDictionary = Dictionaries.GetOrDefault(dictionary.CultureName); - if (existingDictionary == null) - { - Dictionaries[dictionary.CultureName] = dictionary; - } - else - { - existingDictionary.Extend(dictionary); - } - } - - protected virtual void OnUpdated() - { - Updated.InvokeSafely(this); - } - } -} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs index d79c3c48ff..1dfc8e8b55 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs @@ -10,71 +10,78 @@ namespace Volo.Abp.Localization [NotNull] public Type ResourceType { get; } + [NotNull] + public string ResourceName => LocalizationResourceNameAttribute.GetName(ResourceType); + [CanBeNull] public string DefaultCultureName { get; set; } [NotNull] - public ILocalizationDictionaryProvider DictionaryProvider { get; } + public IDictionary Dictionaries { get; } [NotNull] - public List Extensions { get; } + public List Contributors { get; } [NotNull] public List BaseResourceTypes { get; } public LocalizationResource( [NotNull] Type resourceType, - [CanBeNull] string defaultCultureName, //TODO: defaultCultureName should be optional (and second argument) because it's not required for the LocalizationResource! - [NotNull] ILocalizationDictionaryProvider dictionaryProvider) + [CanBeNull] string defaultCultureName = null, + [CanBeNull] ILocalizationResourceContributor initialContributor = null) { ResourceType = Check.NotNull(resourceType, nameof(resourceType)); - DictionaryProvider = Check.NotNull(dictionaryProvider, nameof(dictionaryProvider)); DefaultCultureName = defaultCultureName; + Dictionaries = new Dictionary(); + BaseResourceTypes = new List(); - Extensions = new List(); + Contributors = new List(); + + if (initialContributor != null) + { + Contributors.Add(initialContributor); + } AddBaseResourceTypes(); } public virtual void Initialize(IServiceProvider serviceProvider) { - //TODO: We should refactor here to create a better design! - - var context = new LocalizationResourceInitializationContext(serviceProvider); + var context = new LocalizationResourceInitializationContext(this, serviceProvider); - InitializeDictionaryProvider(context); - InitializeExtensions(context); + Dictionaries.Clear(); + InitializeContributors(context); - DictionaryProvider.Updated += (sender, args) => + foreach (var contributor in Contributors) { - InitializeExtensions(context); - }; - - foreach (var extension in Extensions) - { - extension.Updated += (sender, args) => + contributor.Updated += (sender, args) => { - InitializeDictionaryProvider(context); - InitializeExtensions(context); + Dictionaries.Clear(); + InitializeContributors(context); }; } } - private void InitializeExtensions(LocalizationResourceInitializationContext context) + protected virtual void InitializeContributors(LocalizationResourceInitializationContext context) { - foreach (var extension in Extensions) + foreach (var contributor in Contributors) { - extension.Initialize(context); - DictionaryProvider.Extend(extension); + foreach (var dictionary in contributor.GetDictionaries(context)) + { + var existingDictionary = Dictionaries.GetOrDefault(dictionary.CultureName); + if (existingDictionary == null) + { + Dictionaries[dictionary.CultureName] = dictionary; + } + else + { + existingDictionary.Extend(dictionary); + } + } } } - private void InitializeDictionaryProvider(LocalizationResourceInitializationContext context) - { - DictionaryProvider.Initialize(context); - } - protected virtual void AddBaseResourceTypes() { var descriptors = ResourceType diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorBase.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorBase.cs new file mode 100644 index 0000000000..a7269d5767 --- /dev/null +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceContributorBase.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.Localization +{ + //TODO: Delete this class! + public abstract class LocalizationResourceContributorBase : ILocalizationResourceContributor + { + public event EventHandler Updated; + + public abstract List GetDictionaries(LocalizationResourceInitializationContext context); + + protected virtual void OnUpdated() + { + Updated.InvokeSafely(this); + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs index 1c378b78b6..dc94d589a4 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceDictionary.cs @@ -1,10 +1,37 @@ using System; using System.Collections.Generic; +using JetBrains.Annotations; namespace Volo.Abp.Localization { public class LocalizationResourceDictionary : Dictionary { - + public LocalizationResource Add([CanBeNull] string defaultCultureName = null) + { + return Add(typeof(TResouce), defaultCultureName); + } + + public LocalizationResource Add(Type resourceType, [CanBeNull] string defaultCultureName = null) + { + if (ContainsKey(resourceType)) + { + throw new AbpException("This resource is already added before: " + resourceType.AssemblyQualifiedName); + } + + return this[resourceType] = new LocalizationResource(resourceType, defaultCultureName); + } + + public LocalizationResource Get() + { + var resourceType = typeof(TResource); + + var resource = this.GetOrDefault(resourceType); + if (resource == null) + { + throw new AbpException("Can not find a resource with given type: " + resourceType.AssemblyQualifiedName); + } + + return resource; + } } } \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs new file mode 100644 index 0000000000..c2e4cd3178 --- /dev/null +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceExtensions.cs @@ -0,0 +1,80 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Volo.Abp.Localization.VirtualFiles.Json; + +namespace Volo.Abp.Localization +{ + public static class LocalizationResourceExtensions + { + public static LocalizationResource AddVirtualJson( + [NotNull] this LocalizationResource localizationResource, + [NotNull] string virtualPath) + { + Check.NotNull(localizationResource, nameof(localizationResource)); + Check.NotNull(virtualPath, nameof(virtualPath)); + + localizationResource.Contributors.Add(new JsonVirtualFileLocalizationResourceContributor( + virtualPath.EnsureStartsWith('/') + )); + + return localizationResource; + } + + public static LocalizationResource AddBaseTypes( + [NotNull] this LocalizationResource localizationResource, + [NotNull] params Type[] types) + { + Check.NotNull(localizationResource, nameof(localizationResource)); + Check.NotNull(types, nameof(types)); + + foreach (var type in types) + { + localizationResource.BaseResourceTypes.AddIfNotContains(type); + } + + return localizationResource; + } + + //public static LocalizationResource AddVirtualJson( + // [NotNull] this LocalizationResourceDictionary resourceDictionary, + // [CanBeNull] string defaultCultureName, + // [NotNull] string virtualPath) + //{ + // Check.NotNull(resourceDictionary, nameof(resourceDictionary)); + // Check.NotNull(virtualPath, nameof(virtualPath)); + + // return resourceDictionary + // .Add(defaultCultureName) + // .AddVirtualJson(virtualPath); + //} + + //public static LocalizationResource ExtendWithVirtualJson( + // [NotNull] this LocalizationResourceDictionary resourceDictionary, + // [NotNull] string virtualPath) + //{ + // Check.NotNull(resourceDictionary, nameof(resourceDictionary)); + + // return resourceDictionary + // .Get() + // .AddVirtualJson(virtualPath); + //} + + //public static LocalizationResource AddBaseTypes( + // [NotNull] this LocalizationResourceDictionary resourceDictionary, + // [NotNull] params Type[] types) + //{ + // Check.NotNull(resourceDictionary, nameof(resourceDictionary)); + // Check.NotNull(types, nameof(types)); + + // var localizationResource = resourceDictionary.Get(); + + // foreach (var type in types) + // { + // localizationResource.BaseResourceTypes.AddIfNotContains(type); + // } + + // return localizationResource; + //} + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceInitializationContext.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceInitializationContext.cs index d7b9ff71b1..3a04cbcecb 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceInitializationContext.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceInitializationContext.cs @@ -4,10 +4,13 @@ namespace Volo.Abp.Localization { public class LocalizationResourceInitializationContext { + public LocalizationResource Resource { get; } + public IServiceProvider ServiceProvider { get; } - public LocalizationResourceInitializationContext(IServiceProvider serviceProvider) + public LocalizationResourceInitializationContext(LocalizationResource resource, IServiceProvider serviceProvider) { + Resource = resource; ServiceProvider = serviceProvider; } } diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceListExtensions.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceListExtensions.cs deleted file mode 100644 index 1c51f0592a..0000000000 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceListExtensions.cs +++ /dev/null @@ -1,77 +0,0 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; -using Volo.Abp.Localization.VirtualFiles.Json; - -namespace Volo.Abp.Localization -{ - public static class LocalizationResourceListExtensions - { - public static LocalizationResource AddVirtualJson( - [NotNull] this LocalizationResourceDictionary resourceDictionary, - [CanBeNull] string defaultCultureName, //TODO: defaultCultureName should be optional (and second argument) because it's not required for the LocalizationResource! - [NotNull] string virtualPath) - { - Check.NotNull(resourceDictionary, nameof(resourceDictionary)); - Check.NotNull(virtualPath, nameof(virtualPath)); - - virtualPath = virtualPath.EnsureStartsWith('/'); - - var resourceType = typeof(TResource); - - if (resourceDictionary.ContainsKey(resourceType)) - { - throw new AbpException("There is already a resource with given type: " + resourceType.AssemblyQualifiedName); - } - - return resourceDictionary[resourceType] = new LocalizationResource( - resourceType, - defaultCultureName, - new JsonEmbeddedFileLocalizationDictionaryProvider( - virtualPath - ) - ); - } - - public static void ExtendWithVirtualJson( - [NotNull] this LocalizationResourceDictionary resourceDictionary, - [NotNull] string virtualPath) - { - Check.NotNull(resourceDictionary, nameof(resourceDictionary)); - - resourceDictionary.GetResource().Extensions.Add( - new JsonEmbeddedFileLocalizationDictionaryProvider( - virtualPath - ) - ); - } - - public static void AddBaseTypes( - [NotNull] this LocalizationResourceDictionary resourceDictionary, - [NotNull] params Type[] types) - { - Check.NotNull(resourceDictionary, nameof(resourceDictionary)); - Check.NotNull(types, nameof(types)); - - var resource = resourceDictionary.GetResource(); - - foreach (var type in types) - { - resource.BaseResourceTypes.AddIfNotContains(type); - } - } - - public static LocalizationResource GetResource(this LocalizationResourceDictionary resourceDictionary) - { - var resourceType = typeof(TResource); - - var resource = resourceDictionary.GetOrDefault(resourceType); - if (resource == null) - { - throw new AbpException("Can not find a resource with given type: " + resourceType.AssemblyQualifiedName); - } - - return resource; - } - } -} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceNameAttribute.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceNameAttribute.cs new file mode 100644 index 0000000000..5b2f8dc098 --- /dev/null +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResourceNameAttribute.cs @@ -0,0 +1,28 @@ +using System; +using System.Linq; + +namespace Volo.Abp.Localization +{ + public class LocalizationResourceNameAttribute : Attribute + { + public string Name { get; } + + public LocalizationResourceNameAttribute(string name) + { + Name = name; + } + + public static LocalizationResourceNameAttribute GetOrNull(Type resourceType) + { + return resourceType + .GetCustomAttributes(true) + .OfType() + .FirstOrDefault(); + } + + public static string GetName(Type resourceType) + { + return GetOrNull(resourceType)?.Name ?? resourceType.FullName; + } + } +} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/AbpValidationResource.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/AbpValidationResource.cs index 0fe4f6d7d3..667244886c 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/AbpValidationResource.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/Resources/AbpValidation/AbpValidationResource.cs @@ -2,7 +2,7 @@ { //TODO: Move to Volo.Abp.Validation! - [ShortLocalizationResourceName("AbpValidation")] + [LocalizationResourceName("AbpValidation")] public class AbpValidationResource { diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/ShortLocalizationResourceNameAttribute.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/ShortLocalizationResourceNameAttribute.cs deleted file mode 100644 index c84fe060b4..0000000000 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/ShortLocalizationResourceNameAttribute.cs +++ /dev/null @@ -1,14 +0,0 @@ -using System; - -namespace Volo.Abp.Localization -{ - public class ShortLocalizationResourceNameAttribute : Attribute - { - public string Name { get; } - - public ShortLocalizationResourceNameAttribute(string name) - { - Name = name; - } - } -} \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/Json/JsonEmbeddedFileLocalizationDictionaryProvider.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/Json/JsonVirtualFileLocalizationResourceContributor.cs similarity index 70% rename from src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/Json/JsonEmbeddedFileLocalizationDictionaryProvider.cs rename to src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/Json/JsonVirtualFileLocalizationResourceContributor.cs index 9a9c92aa07..26df0d4e89 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/Json/JsonEmbeddedFileLocalizationDictionaryProvider.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/Json/JsonVirtualFileLocalizationResourceContributor.cs @@ -4,9 +4,11 @@ using Volo.Abp.Localization.Json; namespace Volo.Abp.Localization.VirtualFiles.Json { - public class JsonEmbeddedFileLocalizationDictionaryProvider : VirtualFileLocalizationDictionaryProviderBase + //TODO: Use composition over inheritance..? + + public class JsonVirtualFileLocalizationResourceContributor : VirtualFileLocalizationResourceContributorBase { - public JsonEmbeddedFileLocalizationDictionaryProvider(string virtualPath) + public JsonVirtualFileLocalizationResourceContributor(string virtualPath) : base(virtualPath) { @@ -19,7 +21,7 @@ namespace Volo.Abp.Localization.VirtualFiles.Json protected override ILocalizationDictionary CreateDictionaryFromFileContent(string jsonString) { - return JsonLocalizationDictionaryBuilder.BuildFromJsonString(jsonString); //TODO: Use composition over inheritance! + return JsonLocalizationDictionaryBuilder.BuildFromJsonString(jsonString); } } } \ No newline at end of file diff --git a/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationDictionaryProviderBase.cs b/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs similarity index 68% rename from src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationDictionaryProviderBase.cs rename to src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs index de469bd213..a467dacc8b 100644 --- a/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationDictionaryProviderBase.cs +++ b/src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationResourceContributorBase.cs @@ -1,4 +1,6 @@ using System; +using System.Collections.Generic; +using System.Linq; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.Primitives; @@ -7,38 +9,37 @@ using Volo.Abp.VirtualFileSystem; namespace Volo.Abp.Localization.VirtualFiles { - public abstract class VirtualFileLocalizationDictionaryProviderBase : LocalizationDictionaryProviderBase + public abstract class VirtualFileLocalizationResourceContributorBase : LocalizationResourceContributorBase { private readonly string _virtualPath; private bool _subscribedForChanges; - protected VirtualFileLocalizationDictionaryProviderBase(string virtualPath) + protected VirtualFileLocalizationResourceContributorBase(string virtualPath) { _virtualPath = virtualPath; } - public override void Initialize(LocalizationResourceInitializationContext context) //TODO: Extract initialization to a factory..? + public override List GetDictionaries(LocalizationResourceInitializationContext context) { var virtualFileProvider = context.ServiceProvider.GetRequiredService(); - CreateDictionaries(virtualFileProvider); - if (!_subscribedForChanges) { - ChangeToken.OnChange(() => virtualFileProvider.Watch(_virtualPath.EnsureEndsWith('/') + "**/*.*"), () => + ChangeToken.OnChange(() => virtualFileProvider.Watch(_virtualPath.EnsureEndsWith('/') + "*.*"), () => { - CreateDictionaries(virtualFileProvider); OnUpdated(); }); _subscribedForChanges = true; } + + return CreateDictionaries(virtualFileProvider); } - private void CreateDictionaries(IFileProvider fileProvider) + private List CreateDictionaries(IFileProvider fileProvider) { - Dictionaries.Clear(); + var dictionaries = new Dictionary(); foreach (var file in fileProvider.GetDirectoryContents(_virtualPath)) { @@ -48,13 +49,15 @@ namespace Volo.Abp.Localization.VirtualFiles } var dictionary = CreateDictionaryFromFile(file); - if (Dictionaries.ContainsKey(dictionary.CultureName)) + if (dictionaries.ContainsKey(dictionary.CultureName)) { throw new AbpException($"{file.PhysicalPath} dictionary has a culture name '{dictionary.CultureName}' which is already defined!"); } - Dictionaries[dictionary.CultureName] = dictionary; + dictionaries[dictionary.CultureName] = dictionary; } + + return dictionaries.Values.ToList(); } protected abstract bool CanParseFile(IFileInfo file); diff --git a/src/Volo.Abp.UI/Localization/Resources/AbpUi/AbpUiResource.cs b/src/Volo.Abp.UI/Localization/Resources/AbpUi/AbpUiResource.cs index 89836b8497..9eb90832e5 100644 --- a/src/Volo.Abp.UI/Localization/Resources/AbpUi/AbpUiResource.cs +++ b/src/Volo.Abp.UI/Localization/Resources/AbpUi/AbpUiResource.cs @@ -2,7 +2,7 @@ namespace Localization.Resources.AbpUi { - [ShortLocalizationResourceName("AbpUi")] + [LocalizationResourceName("AbpUi")] public class AbpUiResource { } diff --git a/src/Volo.Abp.UI/Volo/Abp/Ui/AbpUiModule.cs b/src/Volo.Abp.UI/Volo/Abp/Ui/AbpUiModule.cs index 3459eda5cd..6e61b65831 100644 --- a/src/Volo.Abp.UI/Volo/Abp/Ui/AbpUiModule.cs +++ b/src/Volo.Abp.UI/Volo/Abp/Ui/AbpUiModule.cs @@ -13,16 +13,16 @@ namespace Volo.Abp.UI { public override void ConfigureServices(IServiceCollection services) { - services.Configure(options => + services.Configure(options => { - options.Resources.AddVirtualJson("en", "/Localization/Resources/AbpUi"); + options.FileSets.AddEmbedded(); }); - services.Configure(options => + services.Configure(options => { - options.FileSets.AddEmbedded(""); + options.Resources.Add("en").AddVirtualJson("/Localization/Resources/AbpUi"); }); - + services.AddAssemblyOf(); } } diff --git a/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs b/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs index e8ce00dd4b..06cc5c2324 100644 --- a/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs +++ b/test/Volo.Abp.Localization.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs @@ -117,10 +117,10 @@ namespace Volo.Abp.Localization services.Configure(options => { - options.Resources.AddVirtualJson("en", "/Volo/Abp/Localization/TestResources/Base/Validation"); - options.Resources.AddVirtualJson("en", "/Volo/Abp/Localization/TestResources/Base/CountryNames"); - options.Resources.AddVirtualJson("en", "/Volo/Abp/Localization/TestResources/Source"); - options.Resources.ExtendWithVirtualJson("/Volo/Abp/Localization/TestResources/SourceExt"); + options.Resources.Add("en").AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/Validation"); + options.Resources.Add("en").AddVirtualJson("/Volo/Abp/Localization/TestResources/Base/CountryNames"); + options.Resources.Add("en").AddVirtualJson("/Volo/Abp/Localization/TestResources/Source"); + options.Resources.Get().AddVirtualJson("/Volo/Abp/Localization/TestResources/SourceExt"); }); } }