I am developing a .NET Core project where I send Razor pages as e-mail templates. I followed this tutorial: https://scottsauber.com/2018/07/07/walkthrough-creating-an-html-email-template-with-razor-and-razor-class-libraries-and-rendering-it-from-a-net-standard-class-library/ The only thing I couldn't find was how to send a localized e-mail by passing the needed language as a parameter (example):
public async Task<string> RenderViewToStringAsync<TModel>(string viewName, TModel model, string lang)
I found some stuff online about POs
and resx
files but everything required a Startup
implementation. The razor pages is not the main project, the main project is just an API, while the front-end is handled by another Angular project.
How can I implement localization in a Razor Class Library without a Startup file?
This is the project files
I see at least two options for you:
Optoin 1 - Use different resource files for different cultures
Follow these steps:
In API project, register IStringLocalizerFactory
and IStringLocalizer<>
:
services.AddSingleton<IStringLocalizerFactory, ResourceManagerStringLocalizerFactory>();
services.AddScoped(typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
services.AddScoped<IRegisterAccountService, RegisterAccountService>();
services.AddScoped<IRazorViewToStringRenderer, RazorViewToStringRenderer>();
Create a Resources.Resx file in Razor View Library and set its custom tool to PublicResXFileCodeGenerator
. Then for each language, create the resource file like Resources.fa-IR.Resx
and clear the custom tool to not generate code for the language files. Then add resource name and value, for example for fa-IR
:
Name Value Comment
=========================================
Welcome خوش آمدید
Inject string localizer to the views that you want:
@using Microsoft.Extensions.Localization
@inject IStringLocalizer<RazorHtmlEmails.RazorClassLib.SharedResources> SR
In above example, RazorHtmlEmails.RazorClassLib
is namespace of the resource.
Use SR["resource key in resource file"]
whenever you want to show a string from resource file:
@SR["Welcome"]
Add culture as parameter to RenderViewToStringAsync
of IRazorViewToStringRenderer
:
Task<string> RenderViewToStringAsync<TModel>
(string viewName, TModel model, string culture);
Add culture to implementation of RenderViewToStringAsync
in RazorViewToStringRenderer
:
public async Task<string> RenderViewToStringAsync<TModel>
(string viewName, TModel model, string culture)
{
Thread.CurrentThread.CurrentCulture = CultureInfo.GetCultureInfo(culture);
Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo(culture);
...
Use it:
string body = await _razorViewToStringRenderer.RenderViewToStringAsync(
"/Views/Emails/ConfirmAccount/ConfirmAccountEmail.cshtml",
confirmAccountModel, "fa-IR");
Option 2 - Use different cshtml file for different cultures
If you don't want to use resource files and you want to have different cshtml files for different cultures, just use naming convention. For example create a template.fa-IR.cshtml
for Persian language and then when rendering, use that view:
string body = await _razorViewToStringRenderer.RenderViewToStringAsync(
"/Views/Emails/ConfirmAccount/ConfirmAccountEmail.fa-IR.cshtml",
confirmAccountModel);
As an addition to the accepted answer, this is how you can have the translation effect from the resources in the e-mail subject:
Edit RegisterAccountService
class like this:
private readonly IStringLocalizer<RazorHtmlEmails.RazorClassLib.SharedResources> _localizer;
Replace RazorHtmlEmails.RazorClassLib.SharedResources
with your namespace, then:
public RegisterAccountService(IRazorViewToStringRenderer razorViewToStringRenderer, IStringLocalizer<RazorHtmlEmails.RazorClassLib.SharedResources> localizer)
{
_razorViewToStringRenderer = razorViewToStringRenderer;
_localizer = localizer;
}
and apply:
SendEmail(toAddresses, "[email protected]", _localizer["My_Email_Subject_Translation"].Value, body);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With