diff --git a/DysonNetwork.Sphere/Account/MagicSpellController.cs b/DysonNetwork.Sphere/Account/MagicSpellController.cs new file mode 100644 index 0000000..d29bb7d --- /dev/null +++ b/DysonNetwork.Sphere/Account/MagicSpellController.cs @@ -0,0 +1,19 @@ +using Microsoft.AspNetCore.Mvc; + +namespace DysonNetwork.Sphere.Account; + +[ApiController] +[Route("/spells")] +public class MagicSpellController(AppDatabase db, MagicSpellService sp) : ControllerBase +{ + [HttpPost("{spellId:guid}/resend")] + public async Task ResendMagicSpell(Guid spellId) + { + var spell = db.MagicSpells.FirstOrDefault(x => x.Id == spellId); + if (spell == null) + return NotFound(); + + await sp.NotifyMagicSpell(spell, true); + return Ok(); + } +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Account/MagicSpellService.cs b/DysonNetwork.Sphere/Account/MagicSpellService.cs index f5e92f3..5dd4120 100644 --- a/DysonNetwork.Sphere/Account/MagicSpellService.cs +++ b/DysonNetwork.Sphere/Account/MagicSpellService.cs @@ -1,13 +1,23 @@ +using System.Globalization; using System.Security.Cryptography; using DysonNetwork.Sphere.Account.Email; using DysonNetwork.Sphere.Pages.Emails; using DysonNetwork.Sphere.Permission; +using DysonNetwork.Sphere.Resources.Localization; +using DysonNetwork.Sphere.Resources.Pages.Emails; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.Localization; using NodaTime; namespace DysonNetwork.Sphere.Account; -public class MagicSpellService(AppDatabase db, EmailService email, IConfiguration configuration, ILogger logger) +public class MagicSpellService( + AppDatabase db, + EmailService email, + IConfiguration configuration, + ILogger logger, + IStringLocalizer localizer +) { public async Task CreateMagicSpell( Account account, @@ -48,6 +58,15 @@ public class MagicSpellService(AppDatabase db, EmailService email, IConfiguratio logger.LogInformation("Sending magic spell... {Link}", link); + var accountLanguage = await db.Accounts + .Where(a => a.Id == spell.AccountId) + .Select(a => a.Language) + .FirstOrDefaultAsync(); + + var cultureInfo = new CultureInfo(accountLanguage ?? "en-us", false); + CultureInfo.CurrentCulture = cultureInfo; + CultureInfo.CurrentUICulture = cultureInfo; + try { switch (spell.Type) @@ -56,7 +75,7 @@ public class MagicSpellService(AppDatabase db, EmailService email, IConfiguratio await email.SendTemplatedEmailAsync( contact.Account.Name, contact.Content, - "Confirm your registration", + localizer["EmailLandingTitle"], new LandingEmailModel { Name = contact.Account.Name, diff --git a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj index e31f505..99c938f 100644 --- a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj +++ b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj @@ -92,6 +92,24 @@ ResXFileCodeGenerator SharedResource.Designer.cs + + ResXFileCodeGenerator + LandingEmail.Designer.cs + + + ResXFileCodeGenerator + NotificationResource.Designer.cs + + + ResXFileCodeGenerator + Email.LandingResource.Designer.cs + + + SharedResource.resx + + + AccountEventResource.resx + @@ -105,6 +123,16 @@ True SharedResource.resx + + True + True + LandingEmailResource.resx + + + True + True + NotificationResource.resx + diff --git a/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj.DotSettings.user b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj.DotSettings.user new file mode 100644 index 0000000..157ce4d --- /dev/null +++ b/DysonNetwork.Sphere/DysonNetwork.Sphere.csproj.DotSettings.user @@ -0,0 +1,2 @@ + + CFF62EFA-F4C2-4FC7-8D97-25570B4DB452/d:Resources/d:Localization/f:EmailResource.resx \ No newline at end of file diff --git a/DysonNetwork.Sphere/Localization/EmailResource.cs b/DysonNetwork.Sphere/Localization/EmailResource.cs new file mode 100644 index 0000000..19d588e --- /dev/null +++ b/DysonNetwork.Sphere/Localization/EmailResource.cs @@ -0,0 +1,6 @@ +namespace DysonNetwork.Sphere.Localization; + +public class EmailResource +{ + +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Localization/NotificationResource.cs b/DysonNetwork.Sphere/Localization/NotificationResource.cs new file mode 100644 index 0000000..146041c --- /dev/null +++ b/DysonNetwork.Sphere/Localization/NotificationResource.cs @@ -0,0 +1,6 @@ +namespace DysonNetwork.Sphere.Localization; + +public class NotificationResource +{ + +} \ No newline at end of file diff --git a/DysonNetwork.Sphere/Pages/Emails/LandingEmail.razor b/DysonNetwork.Sphere/Pages/Emails/LandingEmail.razor index 04321a7..437ae06 100644 --- a/DysonNetwork.Sphere/Pages/Emails/LandingEmail.razor +++ b/DysonNetwork.Sphere/Pages/Emails/LandingEmail.razor @@ -1,9 +1,13 @@ +@using DysonNetwork.Sphere.Localization +@using Microsoft.Extensions.Localization +@using EmailResource = DysonNetwork.Sphere.Localization.EmailResource + @@ -11,14 +15,13 @@ @@ -26,10 +29,10 @@ @@ -37,16 +40,16 @@ @@ -56,4 +59,7 @@ @code { [Parameter] public required string Name { get; set; } [Parameter] public required string VerificationLink { get; set; } + + [Inject] IStringLocalizer Localizer { get; set; } = null!; + [Inject] IStringLocalizer LocalizerShared { get; set; } = null!; } \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/Localization/EmailResource.Designer.cs b/DysonNetwork.Sphere/Resources/Localization/EmailResource.Designer.cs new file mode 100644 index 0000000..4c51f5a --- /dev/null +++ b/DysonNetwork.Sphere/Resources/Localization/EmailResource.Designer.cs @@ -0,0 +1,90 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DysonNetwork.Sphere.Resources.Pages.Emails { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class EmailResource { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal EmailResource() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.Localization.EmailResource", typeof(EmailResource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + internal static string LandingHeader1 { + get { + return ResourceManager.GetString("LandingHeader1", resourceCulture); + } + } + + internal static string LandingPara1 { + get { + return ResourceManager.GetString("LandingPara1", resourceCulture); + } + } + + internal static string LandingPara2 { + get { + return ResourceManager.GetString("LandingPara2", resourceCulture); + } + } + + internal static string LandingPara3 { + get { + return ResourceManager.GetString("LandingPara3", resourceCulture); + } + } + + internal static string LandingButton1 { + get { + return ResourceManager.GetString("LandingButton1", resourceCulture); + } + } + + internal static string LandingPara4 { + get { + return ResourceManager.GetString("LandingPara4", resourceCulture); + } + } + + internal static string EmailLandingTitle { + get { + return ResourceManager.GetString("EmailLandingTitle", resourceCulture); + } + } + } +} diff --git a/DysonNetwork.Sphere/Resources/Localization/EmailResource.resx b/DysonNetwork.Sphere/Resources/Localization/EmailResource.resx new file mode 100644 index 0000000..ac09e68 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/Localization/EmailResource.resx @@ -0,0 +1,42 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Welcome to the Solar Network! + + + Dear, + + + Thank you for creating an account on the Solar Network. We're excited to have you join our community! + + + To access all features and ensure the security of your account, please confirm your registration by clicking the button below: + + + Confirm Registration + + + If you didn't create this account, please ignore this email. + + + Confirm your registration + + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/Localization/EmailResource.zh-hans.resx b/DysonNetwork.Sphere/Resources/Localization/EmailResource.zh-hans.resx new file mode 100644 index 0000000..bc06cb4 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/Localization/EmailResource.zh-hans.resx @@ -0,0 +1,35 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 欢迎来到 Solar Network! + + + 尊敬的 + + + 确认注册 + + + 感谢你在 Solar Network 上注册帐号,我们很激动你即将加入我们的社区! + + + 点击下方按钮来确认你的注册以获得所有功能的权限。 + + + 如果你并没有注册帐号,你可以忽略此邮件。 + + + 确认你的注册 + + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/Localization/NotificationResource.Designer.cs b/DysonNetwork.Sphere/Resources/Localization/NotificationResource.Designer.cs new file mode 100644 index 0000000..8bbd20e --- /dev/null +++ b/DysonNetwork.Sphere/Resources/Localization/NotificationResource.Designer.cs @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DysonNetwork.Sphere.Resources.Localization { + using System; + + + [System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [System.Diagnostics.DebuggerNonUserCodeAttribute()] + [System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class NotificationResource { + + private static System.Resources.ResourceManager resourceMan; + + private static System.Globalization.CultureInfo resourceCulture; + + [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal NotificationResource() { + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Resources.ResourceManager ResourceManager { + get { + if (object.Equals(null, resourceMan)) { + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.Localization.NotificationResource", typeof(NotificationResource).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)] + internal static System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + } +} diff --git a/DysonNetwork.Sphere/Resources/Localization/NotificationResource.resx b/DysonNetwork.Sphere/Resources/Localization/NotificationResource.resx new file mode 100644 index 0000000..a4c5284 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/Localization/NotificationResource.resx @@ -0,0 +1,21 @@ + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/Localization/NotificationResource.zh-hans.resx b/DysonNetwork.Sphere/Resources/Localization/NotificationResource.zh-hans.resx new file mode 100644 index 0000000..0db1973 --- /dev/null +++ b/DysonNetwork.Sphere/Resources/Localization/NotificationResource.zh-hans.resx @@ -0,0 +1,14 @@ + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/Localization/SharedResource.Designer.cs b/DysonNetwork.Sphere/Resources/Localization/SharedResource.Designer.cs index 80f343a..9498628 100644 --- a/DysonNetwork.Sphere/Resources/Localization/SharedResource.Designer.cs +++ b/DysonNetwork.Sphere/Resources/Localization/SharedResource.Designer.cs @@ -28,7 +28,7 @@ namespace DysonNetwork.Sphere.Resources { internal static System.Resources.ResourceManager ResourceManager { get { if (object.Equals(null, resourceMan)) { - System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.SharedResource", typeof(SharedResource).Assembly); + System.Resources.ResourceManager temp = new System.Resources.ResourceManager("DysonNetwork.Sphere.Resources.Localization.SharedResource", typeof(SharedResource).Assembly); resourceMan = temp; } return resourceMan; @@ -44,5 +44,23 @@ namespace DysonNetwork.Sphere.Resources { resourceCulture = value; } } + + internal static string EmailLinkHint { + get { + return ResourceManager.GetString("EmailLinkHint", resourceCulture); + } + } + + internal static string EmailFooter1 { + get { + return ResourceManager.GetString("EmailFooter1", resourceCulture); + } + } + + internal static string EmailFooter2 { + get { + return ResourceManager.GetString("EmailFooter2", resourceCulture); + } + } } } diff --git a/DysonNetwork.Sphere/Resources/Localization/SharedResource.resx b/DysonNetwork.Sphere/Resources/Localization/SharedResource.resx index a4c5284..9b403ff 100644 --- a/DysonNetwork.Sphere/Resources/Localization/SharedResource.resx +++ b/DysonNetwork.Sphere/Resources/Localization/SharedResource.resx @@ -18,4 +18,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + If the button doesn't work, you can also copy and paste this link into your browser: + + + Best regards, + + + The Solar Network Team + \ No newline at end of file diff --git a/DysonNetwork.Sphere/Resources/Localization/SharedResource.zh-hans.resx b/DysonNetwork.Sphere/Resources/Localization/SharedResource.zh-hans.resx index 0db1973..23a16ed 100644 --- a/DysonNetwork.Sphere/Resources/Localization/SharedResource.zh-hans.resx +++ b/DysonNetwork.Sphere/Resources/Localization/SharedResource.zh-hans.resx @@ -11,4 +11,13 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 此致 + + + Solar Network 团队 + + + 如果上方的按钮不起作用,你也可以复制下面的链接到浏览器。 + \ No newline at end of file diff --git a/DysonNetwork.sln.DotSettings.user b/DysonNetwork.sln.DotSettings.user index ae4f23f..42826b1 100644 --- a/DysonNetwork.sln.DotSettings.user +++ b/DysonNetwork.sln.DotSettings.user @@ -26,7 +26,9 @@ ForceIncluded ForceIncluded ForceIncluded + ForceIncluded ForceIncluded + ForceIncluded ForceIncluded ForceIncluded ForceIncluded @@ -79,7 +81,19 @@ False True True - True + False + False + True + False + True + True + True + False + False + False + True + False + True False True @@ -87,4 +101,5 @@ True True + False False \ No newline at end of file

- Welcome to the Solar Network! + @(Localizer["LandingHeader1"])

- Dear @Name, + @(Localizer["LandingPara1"]) @@@Name,

- Thank you for creating an account on the Solar Network. We're excited to have you join our community! + @(Localizer["LandingPara2"])

- To access all features and ensure the security of your account, please confirm your registration by - clicking the button below: + @(Localizer["LandingPara3"])

- + + @(Localizer["LandingButton1"]) +

- If the button doesn't work, you can also copy and paste this link into your browser: + @(LocalizerShared["EmailLinkHint"])
@VerificationLink

- If you didn't create this account, please ignore this email. + @(Localizer["LandingPara4"])

- Best regards,
- The Solar Network Team + @(LocalizerShared["EmailFooter1"])
+ @(LocalizerShared["EmailFooter2"])