Browse Source

Allow to extend/override existing resources

pull/179/head
Halil İbrahim Kalkan 9 years ago
parent
commit
a26223b57b
  1. 2
      src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder.cs
  2. 4
      src/Volo.Abp/Volo/Abp/Localization/AbpLocalizationOptions.cs
  3. 12
      src/Volo.Abp/Volo/Abp/Localization/AbpStringLocalizerFactory.cs
  4. 4
      src/Volo.Abp/Volo/Abp/Localization/ILocalizationDictionaryProvider.cs
  5. 4
      src/Volo.Abp/Volo/Abp/Localization/Json/JsonEmbeddedFileLocalizationDictionaryProvider.cs
  6. 27
      src/Volo.Abp/Volo/Abp/Localization/LocalizationDictionaryProviderBase.cs
  7. 11
      src/Volo.Abp/Volo/Abp/Localization/LocalizationResource.cs
  8. 10
      src/Volo.Abp/Volo/Abp/Localization/LocalizationResourceDictionary.cs
  9. 9
      src/Volo.Abp/Volo/Abp/Localization/LocalizationResourceList.cs
  10. 50
      src/Volo.Abp/Volo/Abp/Localization/LocalizationResourceListExtensions.cs
  11. 9
      test/Volo.Abp.Tests/Volo.Abp.Tests.csproj
  12. 28
      test/Volo.Abp.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs
  13. 2
      test/Volo.Abp.Tests/Volo/Abp/Localization/Source/en.json
  14. 2
      test/Volo.Abp.Tests/Volo/Abp/Localization/Source/tr.json
  15. 7
      test/Volo.Abp.Tests/Volo/Abp/Localization/SourceExt/SourceExt.cs
  16. 6
      test/Volo.Abp.Tests/Volo/Abp/Localization/SourceExt/en.json
  17. 8
      test/Volo.Abp.Tests/Volo/Abp/Localization/SourceExt/it.json

2
src/Volo.Abp.AspNetCore.Mvc/Volo/Abp/AspNetCore/Mvc/ApplicationConfigurations/ApplicationConfigurationBuilder.cs

@ -37,7 +37,7 @@ namespace Volo.Abp.AspNetCore.Mvc.ApplicationConfigurations
var localizationConfig = new ApplicationLocalizationConfigurationDto(); var localizationConfig = new ApplicationLocalizationConfigurationDto();
foreach (var resource in _localizationOptions.Resources) foreach (var resource in _localizationOptions.Resources.Values)
{ {
var dictionary = new Dictionary<string, string>(); var dictionary = new Dictionary<string, string>();

4
src/Volo.Abp/Volo/Abp/Localization/AbpLocalizationOptions.cs

@ -2,11 +2,11 @@
{ {
public class AbpLocalizationOptions public class AbpLocalizationOptions
{ {
public LocalizationResourceList Resources { get; } public LocalizationResourceDictionary Resources { get; }
public AbpLocalizationOptions() public AbpLocalizationOptions()
{ {
Resources = new LocalizationResourceList(); Resources = new LocalizationResourceDictionary();
} }
} }
} }

12
src/Volo.Abp/Volo/Abp/Localization/AbpStringLocalizerFactory.cs

@ -1,11 +1,11 @@
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq; using System.Linq;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions; using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Options; using Microsoft.Extensions.Options;
using Volo.Abp.Localization.Json;
namespace Volo.Abp.Localization namespace Volo.Abp.Localization
{ {
@ -29,17 +29,15 @@ namespace Volo.Abp.Localization
_localizerCache = new ConcurrentDictionary<Type, AbpDictionaryBasedStringLocalizer>();; _localizerCache = new ConcurrentDictionary<Type, AbpDictionaryBasedStringLocalizer>();;
} }
public virtual IStringLocalizer Create(Type resourceSource) public virtual IStringLocalizer Create(Type resourceType)
{ {
//TODO: Optimize! var localizationResource = _abpLocalizationOptions.Resources.GetOrDefault(resourceType);
var localizationResource = _abpLocalizationOptions.Resources.FirstOrDefault(l => l.ResourceType == resourceSource);
if (localizationResource == null) if (localizationResource == null)
{ {
return _innerFactory.Create(resourceSource); return _innerFactory.Create(resourceType);
} }
return _localizerCache.GetOrAdd(resourceSource, _ => CreateAbpStringLocalizer(localizationResource)); return _localizerCache.GetOrAdd(resourceType, _ => CreateAbpStringLocalizer(localizationResource));
} }
private AbpDictionaryBasedStringLocalizer CreateAbpStringLocalizer(LocalizationResource resource) private AbpDictionaryBasedStringLocalizer CreateAbpStringLocalizer(LocalizationResource resource)

4
src/Volo.Abp/Volo/Abp/Localization/ILocalizationDictionaryProvider.cs

@ -7,7 +7,7 @@ namespace Volo.Abp.Localization
IDictionary<string, ILocalizationDictionary> Dictionaries { get; } IDictionary<string, ILocalizationDictionary> Dictionaries { get; }
void Initialize(); void Initialize();
void Extend(ILocalizationDictionary dictionary); void Extend(ILocalizationDictionaryProvider dictionaryProvider);
} }
} }

4
src/Volo.Abp/Volo/Abp/Localization/Json/JsonEmbeddedFileLocalizationDictionaryProvider.cs

@ -19,10 +19,12 @@ namespace Volo.Abp.Localization.Json
public override void Initialize() public override void Initialize()
{ {
var rootNameSpaceWithDot = _rootNamespace + ".";
var resourceNames = _assembly.GetManifestResourceNames(); var resourceNames = _assembly.GetManifestResourceNames();
foreach (var resourceName in resourceNames) foreach (var resourceName in resourceNames)
{ {
if (resourceName.StartsWith(_rootNamespace)) if (resourceName.StartsWith(rootNameSpaceWithDot))
{ {
using (var stream = _assembly.GetManifestResourceStream(resourceName)) using (var stream = _assembly.GetManifestResourceStream(resourceName))
{ {

27
src/Volo.Abp/Volo/Abp/Localization/LocalizationDictionaryProviderBase.cs

@ -17,19 +17,30 @@ namespace Volo.Abp.Localization
{ {
} }
public void Extend(ILocalizationDictionary dictionary) public virtual void Extend(ILocalizationDictionaryProvider dictionaryProvider)
{ {
//Add foreach (var dictionary in dictionaryProvider.Dictionaries.Values)
ILocalizationDictionary existingDictionary; {
if (!Dictionaries.TryGetValue(dictionary.CultureName, out existingDictionary)) Extend(dictionary);
}
}
protected virtual void Extend(ILocalizationDictionary dictionary)
{
var existingDictionary = Dictionaries.GetOrDefault(dictionary.CultureName);
if (existingDictionary == null)
{ {
Dictionaries[dictionary.CultureName] = dictionary; Dictionaries[dictionary.CultureName] = dictionary;
return;
} }
else
{
Overwrite(existingDictionary, dictionary);
}
}
//Override protected virtual void Overwrite(ILocalizationDictionary existingDictionary, ILocalizationDictionary dictionary)
var localizedStrings = dictionary.GetAllStrings(); {
foreach (var localizedString in localizedStrings) foreach (var localizedString in dictionary.GetAllStrings())
{ {
existingDictionary[localizedString.Name] = localizedString; existingDictionary[localizedString.Name] = localizedString;
} }

11
src/Volo.Abp/Volo/Abp/Localization/LocalizationResource.cs

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using JetBrains.Annotations; using JetBrains.Annotations;
namespace Volo.Abp.Localization namespace Volo.Abp.Localization
@ -20,6 +21,8 @@ namespace Volo.Abp.Localization
} }
private ILocalizationDictionaryProvider _dictionaryProvider; private ILocalizationDictionaryProvider _dictionaryProvider;
public List<ILocalizationDictionaryProvider> Extensions { get; }
public LocalizationResource([NotNull] Type resourceType, [NotNull] string defaultCultureName, [NotNull] ILocalizationDictionaryProvider dictionaryProvider) public LocalizationResource([NotNull] Type resourceType, [NotNull] string defaultCultureName, [NotNull] ILocalizationDictionaryProvider dictionaryProvider)
{ {
Check.NotNull(resourceType, nameof(resourceType)); Check.NotNull(resourceType, nameof(resourceType));
@ -29,11 +32,19 @@ namespace Volo.Abp.Localization
ResourceType = resourceType; ResourceType = resourceType;
DefaultCultureName = defaultCultureName; DefaultCultureName = defaultCultureName;
DictionaryProvider = dictionaryProvider; DictionaryProvider = dictionaryProvider;
Extensions = new List<ILocalizationDictionaryProvider>();
} }
public virtual void Initialize(IServiceProvider serviceProvider) //TODO: Create a LocalizationResourceInitializationContext! public virtual void Initialize(IServiceProvider serviceProvider) //TODO: Create a LocalizationResourceInitializationContext!
{ {
DictionaryProvider.Initialize(); DictionaryProvider.Initialize();
foreach (var extension in Extensions)
{
extension.Initialize();
DictionaryProvider.Extend(extension);
}
} }
} }
} }

10
src/Volo.Abp/Volo/Abp/Localization/LocalizationResourceDictionary.cs

@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;
namespace Volo.Abp.Localization
{
public class LocalizationResourceDictionary : Dictionary<Type, LocalizationResource>
{
}
}

9
src/Volo.Abp/Volo/Abp/Localization/LocalizationResourceList.cs

@ -1,9 +0,0 @@
using System.Collections.Generic;
namespace Volo.Abp.Localization
{
public class LocalizationResourceList : List<LocalizationResource>
{
}
}

50
src/Volo.Abp/Volo/Abp/Localization/LocalizationResourceListExtensions.cs

@ -1,24 +1,50 @@
using JetBrains.Annotations; using System.Collections.Generic;
using JetBrains.Annotations;
using Volo.Abp.Localization.Json; using Volo.Abp.Localization.Json;
namespace Volo.Abp.Localization namespace Volo.Abp.Localization
{ {
public static class LocalizationResourceListExtensions public static class LocalizationResourceListExtensions
{ {
public static void AddJson<TResource>(this LocalizationResourceList resourceList, [NotNull] string defaultCultureName) public static void AddJson<TResource>([NotNull] this LocalizationResourceDictionary resourceDictionary, [NotNull] string defaultCultureName)
{ {
var type = typeof(TResource); Check.NotNull(resourceDictionary, nameof(resourceDictionary));
Check.NotNull(defaultCultureName, nameof(defaultCultureName));
resourceList.Add(
new LocalizationResource( var resourceType = typeof(TResource);
type,
defaultCultureName, if (resourceDictionary.ContainsKey(resourceType))
new JsonEmbeddedFileLocalizationDictionaryProvider( {
type.Assembly, throw new AbpException("There is already a resource with given type: " + resourceType.AssemblyQualifiedName);
type.Namespace }
)
resourceDictionary[resourceType] = new LocalizationResource(
resourceType,
defaultCultureName,
new JsonEmbeddedFileLocalizationDictionaryProvider(
resourceType.Assembly,
resourceType.Namespace
) )
); );
} }
public static void ExtendWithJson<TResource, TResourceExt>([NotNull] this LocalizationResourceDictionary resourceDictionary)
{
Check.NotNull(resourceDictionary, nameof(resourceDictionary));
var resourceType = typeof(TResource);
var resourceExtType = typeof(TResourceExt);
var resource = resourceDictionary.GetOrDefault(resourceType);
if (resource == null)
{
throw new AbpException("Can not find a resource with given type: " + resourceType.AssemblyQualifiedName);
}
resource.Extensions.Add(new JsonEmbeddedFileLocalizationDictionaryProvider(
resourceExtType.Assembly,
resourceExtType.Namespace
));
}
} }
} }

9
test/Volo.Abp.Tests/Volo.Abp.Tests.csproj

@ -12,13 +12,8 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<None Remove="Volo\Abp\Localization\Source\en.json" /> <EmbeddedResource Include="Volo\Abp\Localization\SourceExt\*.json" />
<None Remove="Volo\Abp\Localization\Source\tr.json" /> <EmbeddedResource Include="Volo\Abp\Localization\Source\*.json" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="Volo\Abp\Localization\Source\en.json" />
<EmbeddedResource Include="Volo\Abp\Localization\Source\tr.json" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

28
test/Volo.Abp.Tests/Volo/Abp/Localization/AbpLocalization_Tests.cs

@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization; using Microsoft.Extensions.Localization;
using Shouldly; using Shouldly;
using Volo.Abp.Localization.Source; using Volo.Abp.Localization.Source;
using Volo.Abp.Localization.SourceExt;
using Volo.Abp.Modularity; using Volo.Abp.Modularity;
using Volo.Abp.TestBase; using Volo.Abp.TestBase;
using Xunit; using Xunit;
@ -40,6 +41,30 @@ namespace Volo.Abp.Localization
_localizer["Car"].Value.ShouldBe("Araba"); _localizer["Car"].Value.ShouldBe("Araba");
_localizer["CarPlural"].Value.ShouldBe("Araba"); _localizer["CarPlural"].Value.ShouldBe("Araba");
} }
using (AbpCultureHelper.Use("it"))
{
_localizer["Car"].Value.ShouldBe("Auto");
}
}
[Fact]
public void Should_Get_Extension_Texts()
{
using (AbpCultureHelper.Use("en"))
{
_localizer["SeeYou"].Value.ShouldBe("See you");
}
using (AbpCultureHelper.Use("tr"))
{
_localizer["SeeYou"].Value.ShouldBe("See you"); //Not defined in tr
}
using (AbpCultureHelper.Use("it"))
{
_localizer["SeeYou"].Value.ShouldBe("Ci vediamo");
}
} }
[Fact] [Fact]
@ -48,7 +73,7 @@ namespace Volo.Abp.Localization
_localizer.WithCulture(CultureInfo.GetCultureInfo("en"))["Car"].Value.ShouldBe("Car"); _localizer.WithCulture(CultureInfo.GetCultureInfo("en"))["Car"].Value.ShouldBe("Car");
_localizer.WithCulture(CultureInfo.GetCultureInfo("en"))["CarPlural"].Value.ShouldBe("Cars"); _localizer.WithCulture(CultureInfo.GetCultureInfo("en"))["CarPlural"].Value.ShouldBe("Cars");
_localizer.WithCulture(CultureInfo.GetCultureInfo("tr"))["CarPlural"].Value.ShouldBe("Araba"); _localizer.WithCulture(CultureInfo.GetCultureInfo("tr"))["Car"].Value.ShouldBe("Araba");
_localizer.WithCulture(CultureInfo.GetCultureInfo("tr"))["CarPlural"].Value.ShouldBe("Araba"); _localizer.WithCulture(CultureInfo.GetCultureInfo("tr"))["CarPlural"].Value.ShouldBe("Araba");
} }
@ -60,6 +85,7 @@ namespace Volo.Abp.Localization
services.Configure<AbpLocalizationOptions>(options => services.Configure<AbpLocalizationOptions>(options =>
{ {
options.Resources.AddJson<LocalizationTestResource>("en"); options.Resources.AddJson<LocalizationTestResource>("en");
options.Resources.ExtendWithJson<LocalizationTestResource, LocalizationTestResourceExt>();
}); });
} }
} }

2
test/Volo.Abp.Tests/Volo/Abp/Localization/Source/en.json

@ -1,7 +1,7 @@
{ {
"culture": "en", "culture": "en",
"texts": { "texts": {
"Hello <b>{0}</b>.": "Hello <b>{0}</b>", "Hello <b>{0}</b>.": "Hello <b>{0}</b>.",
"Car": "Car", "Car": "Car",
"CarPlural": "Cars" "CarPlural": "Cars"
} }

2
test/Volo.Abp.Tests/Volo/Abp/Localization/Source/tr.json

@ -1,7 +1,7 @@
{ {
"culture": "tr", "culture": "tr",
"texts": { "texts": {
"Hello <b>{0}</b>.": "Merhaba <b>{0}</b>", "Hello <b>{0}</b>.": "Merhaba <b>{0}</b>.",
"Car": "Araba", "Car": "Araba",
"CarPlural": "Araba" "CarPlural": "Araba"
} }

7
test/Volo.Abp.Tests/Volo/Abp/Localization/SourceExt/SourceExt.cs

@ -0,0 +1,7 @@
namespace Volo.Abp.Localization.SourceExt
{
internal sealed class LocalizationTestResourceExt
{
}
}

6
test/Volo.Abp.Tests/Volo/Abp/Localization/SourceExt/en.json

@ -0,0 +1,6 @@
{
"culture": "en",
"texts": {
"SeeYou": "See you"
}
}

8
test/Volo.Abp.Tests/Volo/Abp/Localization/SourceExt/it.json

@ -0,0 +1,8 @@
{
"culture": "it",
"texts": {
"Hello <b>{0}</b>.": "Ciao <b>{0}</b>.",
"Car": "Auto",
"SeeYou": "Ci vediamo"
}
}
Loading…
Cancel
Save