mirror of https://github.com/abpframework/abp.git
23 changed files with 326 additions and 80 deletions
@ -0,0 +1,9 @@ |
|||||
|
<!DOCTYPE html> |
||||
|
<html lang="en" xmlns="http://www.w3.org/1999/xhtml"> |
||||
|
<head> |
||||
|
<meta charset="utf-8" /> |
||||
|
</head> |
||||
|
<body> |
||||
|
{{#content}} |
||||
|
</body> |
||||
|
</html> |
||||
@ -1,12 +1,42 @@ |
|||||
namespace Volo.Abp.Emailing.Templates |
using System.Text; |
||||
|
|
||||
|
namespace Volo.Abp.Emailing.Templates |
||||
{ |
{ |
||||
public class EmailTemplate |
public class EmailTemplate |
||||
{ |
{ |
||||
public string Content { get; } |
public EmailTemplateDefinition Definition { get; } |
||||
|
|
||||
|
public string Content => ContentBuilder.ToString(); |
||||
|
|
||||
|
protected StringBuilder ContentBuilder { get; set; } |
||||
|
|
||||
|
public EmailTemplate(string content, EmailTemplateDefinition definition) |
||||
|
{ |
||||
|
ContentBuilder = new StringBuilder(content); |
||||
|
Definition = definition; |
||||
|
} |
||||
|
|
||||
|
public virtual void SetLayout(EmailTemplate layoutTemplate) |
||||
|
{ |
||||
|
if (!layoutTemplate.Definition.IsLayout) |
||||
|
{ |
||||
|
throw new AbpException($"Given template is not a layout template: {layoutTemplate.Definition.Name}"); |
||||
|
} |
||||
|
|
||||
|
var newStrBuilder = new StringBuilder(layoutTemplate.Content); |
||||
|
newStrBuilder.Replace("{{#content}}", ContentBuilder.ToString()); |
||||
|
|
||||
|
ContentBuilder = newStrBuilder; |
||||
|
} |
||||
|
|
||||
|
public virtual void SetContent(string content) |
||||
|
{ |
||||
|
ContentBuilder = new StringBuilder(content); |
||||
|
} |
||||
|
|
||||
public EmailTemplate(string content) |
public virtual void Replace(string name, string value) |
||||
{ |
{ |
||||
Content = content; |
ContentBuilder.Replace("{{" + name + "}}", value); |
||||
} |
} |
||||
} |
} |
||||
} |
} |
||||
@ -0,0 +1,91 @@ |
|||||
|
using System; |
||||
|
using System.Threading.Tasks; |
||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Microsoft.Extensions.Options; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
using Volo.Abp.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.Emailing.Templates |
||||
|
{ |
||||
|
public class EmailTemplateProvider : IEmailTemplateProvider, ITransientDependency |
||||
|
{ |
||||
|
protected IServiceProvider ServiceProvider { get; } |
||||
|
protected ITemplateLocalizer TemplateLocalizer { get; } |
||||
|
protected EmailTemplateOptions Options { get; } |
||||
|
|
||||
|
public EmailTemplateProvider( |
||||
|
IOptions<EmailTemplateOptions> options, |
||||
|
IServiceProvider serviceProvider, |
||||
|
ITemplateLocalizer templateLocalizer) |
||||
|
{ |
||||
|
ServiceProvider = serviceProvider; |
||||
|
TemplateLocalizer = templateLocalizer; |
||||
|
Options = options.Value; |
||||
|
} |
||||
|
|
||||
|
public async Task<EmailTemplate> GetAsync(string name) |
||||
|
{ |
||||
|
using (var scope = ServiceProvider.CreateScope()) |
||||
|
{ |
||||
|
return await GetInternalAsync(scope.ServiceProvider, name); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task<EmailTemplate> GetInternalAsync(IServiceProvider serviceProvider, string name) |
||||
|
{ |
||||
|
var context = new EmailTemplateProviderContributorContext(name, serviceProvider); |
||||
|
|
||||
|
foreach (var provider in Options.Providers) |
||||
|
{ |
||||
|
await provider.ProvideAsync(context); |
||||
|
} |
||||
|
|
||||
|
if (context.Template == null) |
||||
|
{ |
||||
|
throw new AbpException($"Could not found the template: {name}"); |
||||
|
} |
||||
|
|
||||
|
await SetLayoutAsync(serviceProvider, context); |
||||
|
await LocalizeAsync(serviceProvider, context); |
||||
|
|
||||
|
return context.Template; |
||||
|
} |
||||
|
|
||||
|
protected virtual async Task SetLayoutAsync(IServiceProvider serviceProvider, EmailTemplateProviderContributorContext context) |
||||
|
{ |
||||
|
var layout = context.Template.Definition.Layout; |
||||
|
|
||||
|
if (layout.IsNullOrEmpty()) |
||||
|
{ |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
if (layout == EmailTemplateDefinition.DefaultLayoutPlaceHolder) |
||||
|
{ |
||||
|
layout = Options.DefaultLayout; |
||||
|
} |
||||
|
|
||||
|
var layoutTemplate = await GetInternalAsync(serviceProvider, layout); |
||||
|
context.Template.SetLayout(layoutTemplate); |
||||
|
} |
||||
|
|
||||
|
protected virtual Task LocalizeAsync(IServiceProvider serviceProvider, EmailTemplateProviderContributorContext context) |
||||
|
{ |
||||
|
if (context.Template.Definition.LocalizationResource == null) |
||||
|
{ |
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
|
||||
|
var localizer = serviceProvider |
||||
|
.GetRequiredService<IStringLocalizerFactory>() |
||||
|
.Create(context.Template.Definition.LocalizationResource); |
||||
|
|
||||
|
context.Template.SetContent( |
||||
|
TemplateLocalizer.Localize(localizer, context.Template.Content) |
||||
|
); |
||||
|
|
||||
|
return Task.CompletedTask; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -1,40 +0,0 @@ |
|||||
using System; |
|
||||
using System.Threading.Tasks; |
|
||||
using Microsoft.Extensions.DependencyInjection; |
|
||||
using Microsoft.Extensions.Options; |
|
||||
using Volo.Abp.DependencyInjection; |
|
||||
|
|
||||
namespace Volo.Abp.Emailing.Templates |
|
||||
{ |
|
||||
public class EmailTemplateStore : IEmailTemplateStore, ITransientDependency |
|
||||
{ |
|
||||
protected IServiceProvider ServiceProvider { get; } |
|
||||
protected EmailTemplateOptions Options { get; } |
|
||||
|
|
||||
public EmailTemplateStore(IOptions<EmailTemplateOptions> options, IServiceProvider serviceProvider) |
|
||||
{ |
|
||||
ServiceProvider = serviceProvider; |
|
||||
Options = options.Value; |
|
||||
} |
|
||||
|
|
||||
public async Task<EmailTemplate> GetAsync(string name) |
|
||||
{ |
|
||||
using (var scope = ServiceProvider.CreateScope()) |
|
||||
{ |
|
||||
var context = new EmailTemplateProviderContext(name, scope.ServiceProvider); |
|
||||
foreach (var provider in Options.Providers) |
|
||||
{ |
|
||||
await provider.ProvideAsync(context); |
|
||||
} |
|
||||
|
|
||||
if (context.Template == null) |
|
||||
{ |
|
||||
//TODO: Return a default email template!
|
|
||||
throw new NotImplementedException(); |
|
||||
} |
|
||||
|
|
||||
return context.Template; |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,9 @@ |
|||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace Volo.Abp.Emailing.Templates |
||||
|
{ |
||||
|
public interface IEmailTemplateProviderContributor |
||||
|
{ |
||||
|
Task ProvideAsync(EmailTemplateProviderContributorContext contributorContext); |
||||
|
} |
||||
|
} |
||||
@ -1,9 +0,0 @@ |
|||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Volo.Abp.Emailing.Templates |
|
||||
{ |
|
||||
public interface IEmailTemplateStore |
|
||||
{ |
|
||||
Task<EmailTemplate> GetAsync(string name); |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1 @@ |
|||||
|
{{message}} |
||||
@ -0,0 +1,8 @@ |
|||||
|
namespace Volo.Abp.Emailing.Templates |
||||
|
{ |
||||
|
public static class StandardEmailTemplates |
||||
|
{ |
||||
|
public const string DefaultLayout = "Abp.DefaultLayout"; |
||||
|
public const string SimpleMessage = "Abp.SimpleMessage"; |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,9 @@ |
|||||
|
using Microsoft.Extensions.Localization; |
||||
|
|
||||
|
namespace Volo.Abp.Localization |
||||
|
{ |
||||
|
public interface ITemplateLocalizer |
||||
|
{ |
||||
|
string Localize(IStringLocalizer localizer, string text); |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System.Text.RegularExpressions; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Volo.Abp.DependencyInjection; |
||||
|
|
||||
|
namespace Volo.Abp.Localization |
||||
|
{ |
||||
|
public class TemplateLocalizer : ITemplateLocalizer, ITransientDependency |
||||
|
{ |
||||
|
public string Localize(IStringLocalizer localizer, string text) |
||||
|
{ |
||||
|
return new Regex("\\{\\{#L:.+?\\}\\}") |
||||
|
.Replace( |
||||
|
text, |
||||
|
match => localizer[match.Value.Substring(5, match.Length - 7)] |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,62 @@ |
|||||
|
using Microsoft.Extensions.DependencyInjection; |
||||
|
using Microsoft.Extensions.Localization; |
||||
|
using Shouldly; |
||||
|
using Volo.Abp.Localization.TestResources.Source; |
||||
|
using Volo.Abp.Modularity; |
||||
|
using Volo.Abp.VirtualFileSystem; |
||||
|
using Xunit; |
||||
|
|
||||
|
namespace Volo.Abp.Localization |
||||
|
{ |
||||
|
public class TemplateLocalizer_Tests : AbpIntegratedTest<TemplateLocalizer_Tests.TestModule> |
||||
|
{ |
||||
|
private readonly ITemplateLocalizer _templateLocalizer; |
||||
|
private readonly IStringLocalizer<LocalizationTestResource> _testResource; |
||||
|
|
||||
|
public TemplateLocalizer_Tests() |
||||
|
{ |
||||
|
_testResource = GetRequiredService<IStringLocalizer<LocalizationTestResource>>(); |
||||
|
_templateLocalizer = GetRequiredService<ITemplateLocalizer>(); |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Localize() |
||||
|
{ |
||||
|
using (AbpCultureHelper.Use("en")) |
||||
|
{ |
||||
|
_templateLocalizer.Localize(_testResource, "<p>{{#L:CarPlural}} <b>{{#L:Universe}}</b></p>") |
||||
|
.ShouldBe("<p>Cars <b>Universe</b></p>"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[Fact] |
||||
|
public void Should_Work_Even_If_No_Text_To_Localize() |
||||
|
{ |
||||
|
using (AbpCultureHelper.Use("en")) |
||||
|
{ |
||||
|
_templateLocalizer.Localize(_testResource, "<p>test</p>") |
||||
|
.ShouldBe("<p>test</p>"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
[DependsOn(typeof(AbpTestBaseModule))] |
||||
|
[DependsOn(typeof(AbpLocalizationModule))] |
||||
|
public class TestModule : AbpModule |
||||
|
{ |
||||
|
public override void ConfigureServices(ServiceConfigurationContext context) |
||||
|
{ |
||||
|
context.Services.Configure<VirtualFileSystemOptions>(options => |
||||
|
{ |
||||
|
options.FileSets.AddEmbedded<AbpLocalization_Tests.TestModule>(); |
||||
|
}); |
||||
|
|
||||
|
context.Services.Configure<AbpLocalizationOptions>(options => |
||||
|
{ |
||||
|
options.Resources |
||||
|
.Add<LocalizationTestResource>("en") |
||||
|
.AddVirtualJson("/Volo/Abp/Localization/TestResources/Source"); |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue