Browse Source

Resolved #176: Allow to change localization and see the result without recompile on development time.

pull/183/head
Halil İbrahim Kalkan 9 years ago
parent
commit
abaebd37d9
  1. 8
      src/Volo.Abp.Localization/Volo/Abp/Localization/AbpStringLocalizerFactory.cs
  2. 2
      src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationDictionary.cs
  3. 5
      src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationDictionaryProvider.cs
  4. 7
      src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationDictionary.cs
  5. 8
      src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationDictionaryProviderBase.cs
  6. 27
      src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationResource.cs
  7. 2
      src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/Json/JsonEmbeddedFileLocalizationDictionaryProvider.cs
  8. 52
      src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationDictionaryProviderBase.cs
  9. 2
      src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileProvider.cs

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

@ -20,13 +20,14 @@ namespace Volo.Abp.Localization
//TODO: It's better to use decorator pattern for IStringLocalizerFactory instead of getting ResourceManagerStringLocalizerFactory as a dependency. //TODO: It's better to use decorator pattern for IStringLocalizerFactory instead of getting ResourceManagerStringLocalizerFactory as a dependency.
public AbpStringLocalizerFactory( public AbpStringLocalizerFactory(
ResourceManagerStringLocalizerFactory innerFactory, ResourceManagerStringLocalizerFactory innerFactory,
IOptions<AbpLocalizationOptions> abpLocalizationOptions, IServiceProvider serviceProvider) IOptions<AbpLocalizationOptions> abpLocalizationOptions,
IServiceProvider serviceProvider)
{ {
_innerFactory = innerFactory; _innerFactory = innerFactory;
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
_abpLocalizationOptions = abpLocalizationOptions.Value; _abpLocalizationOptions = abpLocalizationOptions.Value;
_localizerCache = new ConcurrentDictionary<Type, AbpDictionaryBasedStringLocalizer>();; _localizerCache = new ConcurrentDictionary<Type, AbpDictionaryBasedStringLocalizer>();
} }
public virtual IStringLocalizer Create(Type resourceType) public virtual IStringLocalizer Create(Type resourceType)
@ -42,7 +43,8 @@ namespace Volo.Abp.Localization
private AbpDictionaryBasedStringLocalizer CreateAbpStringLocalizer(LocalizationResource resource) private AbpDictionaryBasedStringLocalizer CreateAbpStringLocalizer(LocalizationResource resource)
{ {
resource.Initialize(_serviceProvider); resource.Initialize(_serviceProvider); //TODO: Use CreateScope?
return new AbpDictionaryBasedStringLocalizer( return new AbpDictionaryBasedStringLocalizer(
resource, resource,
resource.BaseResourceTypes.Select(Create).ToList() resource.BaseResourceTypes.Select(Create).ToList()

2
src/Volo.Abp.Localization/Volo/Abp/Localization/ILocalizationDictionary.cs

@ -29,5 +29,7 @@ namespace Volo.Abp.Localization
IReadOnlyList<LocalString> GetAllStrings(); IReadOnlyList<LocalString> GetAllStrings();
void Extend(ILocalizationDictionary dictionary); void Extend(ILocalizationDictionary dictionary);
void Clear();
} }
} }

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

@ -1,4 +1,5 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
namespace Volo.Abp.Localization namespace Volo.Abp.Localization
{ {
@ -6,6 +7,8 @@ namespace Volo.Abp.Localization
{ {
IDictionary<string, ILocalizationDictionary> Dictionaries { get; } IDictionary<string, ILocalizationDictionary> Dictionaries { get; }
event EventHandler Updated;
void Initialize(LocalizationResourceInitializationContext context); void Initialize(LocalizationResourceInitializationContext context);
void Extend(ILocalizationDictionaryProvider dictionaryProvider); void Extend(ILocalizationDictionaryProvider dictionaryProvider);

7
src/Volo.Abp.Localization/Volo/Abp/Localization/LocalizationDictionary.cs

@ -11,7 +11,7 @@ namespace Volo.Abp.Localization
{ {
/// <inheritdoc/> /// <inheritdoc/>
public string CultureName { get; } public string CultureName { get; }
/// <inheritdoc/> /// <inheritdoc/>
public virtual LocalString this[string name] public virtual LocalString this[string name]
{ {
@ -51,6 +51,11 @@ namespace Volo.Abp.Localization
} }
} }
public void Clear()
{
_dictionary.Clear();
}
/// <inheritdoc/> /// <inheritdoc/>
public virtual IEnumerator<LocalString> GetEnumerator() public virtual IEnumerator<LocalString> GetEnumerator()
{ {

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

@ -1,3 +1,4 @@
using System;
using System.Collections.Generic; using System.Collections.Generic;
namespace Volo.Abp.Localization namespace Volo.Abp.Localization
@ -6,6 +7,8 @@ namespace Volo.Abp.Localization
{ {
public IDictionary<string, ILocalizationDictionary> Dictionaries { get; } public IDictionary<string, ILocalizationDictionary> Dictionaries { get; }
public event EventHandler Updated;
protected LocalizationDictionaryProviderBase() protected LocalizationDictionaryProviderBase()
{ {
Dictionaries = new Dictionary<string, ILocalizationDictionary>(); Dictionaries = new Dictionary<string, ILocalizationDictionary>();
@ -35,5 +38,10 @@ namespace Volo.Abp.Localization
existingDictionary.Extend(dictionary); existingDictionary.Extend(dictionary);
} }
} }
protected virtual void OnUpdated()
{
Updated.InvokeSafely(this);
}
} }
} }

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

@ -38,10 +38,30 @@ namespace Volo.Abp.Localization
public virtual void Initialize(IServiceProvider serviceProvider) 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(serviceProvider);
DictionaryProvider.Initialize(context); InitializeDictionaryProvider(context);
InitializeExtensions(context);
DictionaryProvider.Updated += (sender, args) =>
{
InitializeExtensions(context);
};
foreach (var extension in Extensions)
{
extension.Updated += (sender, args) =>
{
InitializeDictionaryProvider(context);
InitializeExtensions(context);
};
}
}
private void InitializeExtensions(LocalizationResourceInitializationContext context)
{
foreach (var extension in Extensions) foreach (var extension in Extensions)
{ {
extension.Initialize(context); extension.Initialize(context);
@ -49,6 +69,11 @@ namespace Volo.Abp.Localization
} }
} }
private void InitializeDictionaryProvider(LocalizationResourceInitializationContext context)
{
DictionaryProvider.Initialize(context);
}
protected virtual void AddBaseResourceTypes() protected virtual void AddBaseResourceTypes()
{ {
var descriptors = ResourceType var descriptors = ResourceType

2
src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/Json/JsonEmbeddedFileLocalizationDictionaryProvider.cs

@ -17,7 +17,7 @@ namespace Volo.Abp.Localization.VirtualFiles.Json
return file.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase); return file.Name.EndsWith(".json", StringComparison.OrdinalIgnoreCase);
} }
protected override ILocalizationDictionary CreateDictionary(string jsonString) protected override ILocalizationDictionary CreateDictionaryFromFileContent(string jsonString)
{ {
return JsonLocalizationDictionaryBuilder.BuildFromJsonString(jsonString); //TODO: Use composition over inheritance! return JsonLocalizationDictionaryBuilder.BuildFromJsonString(jsonString); //TODO: Use composition over inheritance!
} }

52
src/Volo.Abp.Localization/Volo/Abp/Localization/VirtualFiles/VirtualFileLocalizationDictionaryProviderBase.cs

@ -1,5 +1,7 @@
using Microsoft.Extensions.DependencyInjection; using System;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders; using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
using Volo.Abp.Internal; using Volo.Abp.Internal;
using Volo.Abp.VirtualFileSystem; using Volo.Abp.VirtualFileSystem;
@ -9,6 +11,8 @@ namespace Volo.Abp.Localization.VirtualFiles
{ {
private readonly string _virtualPath; private readonly string _virtualPath;
private bool _subscribedForChanges;
protected VirtualFileLocalizationDictionaryProviderBase(string virtualPath) protected VirtualFileLocalizationDictionaryProviderBase(string virtualPath)
{ {
_virtualPath = virtualPath; _virtualPath = virtualPath;
@ -17,32 +21,52 @@ namespace Volo.Abp.Localization.VirtualFiles
public override void Initialize(LocalizationResourceInitializationContext context) //TODO: Extract initialization to a factory..? public override void Initialize(LocalizationResourceInitializationContext context) //TODO: Extract initialization to a factory..?
{ {
var virtualFileProvider = context.ServiceProvider.GetRequiredService<IVirtualFileProvider>(); var virtualFileProvider = context.ServiceProvider.GetRequiredService<IVirtualFileProvider>();
var directoryContents = virtualFileProvider.GetDirectoryContents(_virtualPath);
foreach (var file in directoryContents) CreateDictionaries(virtualFileProvider);
if (!_subscribedForChanges)
{
ChangeToken.OnChange(() => virtualFileProvider.Watch(_virtualPath.EnsureEndsWith('/') + "**/*.*"), () =>
{
CreateDictionaries(virtualFileProvider);
OnUpdated();
});
_subscribedForChanges = true;
}
}
private void CreateDictionaries(IFileProvider fileProvider)
{
Dictionaries.Clear();
foreach (var file in fileProvider.GetDirectoryContents(_virtualPath))
{ {
if (file.IsDirectory || !CanParseFile(file)) if (file.IsDirectory || !CanParseFile(file))
{ {
continue; continue;
} }
using (var stream = file.CreateReadStream()) var dictionary = CreateDictionaryFromFile(file);
if (Dictionaries.ContainsKey(dictionary.CultureName))
{ {
var fileContent = Utf8Helper.ReadStringFromStream(stream); throw new AbpException($"{file.PhysicalPath} dictionary has a culture name '{dictionary.CultureName}' which is already defined!");
var dictionary = CreateDictionary(fileContent);
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;
} }
} }
protected abstract bool CanParseFile(IFileInfo file); protected abstract bool CanParseFile(IFileInfo file);
protected abstract ILocalizationDictionary CreateDictionary(string fileContent); protected virtual ILocalizationDictionary CreateDictionaryFromFile(IFileInfo file)
{
using (var stream = file.CreateReadStream())
{
return CreateDictionaryFromFileContent(Utf8Helper.ReadStringFromStream(stream));
}
}
protected abstract ILocalizationDictionary CreateDictionaryFromFileContent(string fileContent);
} }
} }

2
src/Volo.Abp.VirtualFileSystem/Volo/Abp/VirtualFileSystem/VirtualFileProvider.cs

@ -41,7 +41,7 @@ namespace Volo.Abp.VirtualFileSystem
if (_options.FileSets.PhysicalPaths.Any()) if (_options.FileSets.PhysicalPaths.Any())
{ {
var fileProviders = _options.FileSets.PhysicalPaths var fileProviders = _options.FileSets.PhysicalPaths
.Select(p => new PhysicalFileProvider(p)) .Select(rootPath => new PhysicalFileProvider(rootPath))
.Cast<IFileProvider>() .Cast<IFileProvider>()
.ToList(); .ToList();

Loading…
Cancel
Save