Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use localized Razor pages as e-mail templates

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

enter image description here

like image 499
Dev Avatar asked Feb 10 '20 21:02

Dev


2 Answers

I see at least two options for you:

  1. Use different resource files for different cultures.
  2. Use different cshtml file for different cultures.

Optoin 1 - Use different resource files for different cultures

Follow these steps:

  1. 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>();
    
  2. 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     خوش آمدید              
    
  3. 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.

  1. Use SR["resource key in resource file"] whenever you want to show a string from resource file:

     @SR["Welcome"]
    
  2. Add culture as parameter to RenderViewToStringAsync of IRazorViewToStringRenderer:

     Task<string> RenderViewToStringAsync<TModel>
         (string viewName, TModel model, string culture);
    
  3. 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);
     ...
    
  4. 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);
like image 152
Reza Aghaei Avatar answered Oct 10 '22 02:10

Reza Aghaei


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);
like image 27
Dev Avatar answered Oct 10 '22 04:10

Dev