Skip to content

Commit

Permalink
Merge pull request #254 from DentallApp/feat/select-language-culture
Browse files Browse the repository at this point in the history
feat: Implement a strategy to select the language/culture for each request in a localized ASP.NET Core app
  • Loading branch information
MrDave1999 authored Jul 1, 2024
2 parents ca9ea08 + a967325 commit 307cd48
Show file tree
Hide file tree
Showing 10 changed files with 80 additions and 20 deletions.
1 change: 0 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ FRONTEND_APP_BASE_URL=http://localhost:80/
MAX_DAYS_IN_CALENDAR=60
BUSINESS_NAME=World Dental CO
DENTAL_SERVICES_IMAGES_PATH=/app/dental_services
LANGUAGE=es
PLUGINS="
Plugin.ChatBot.dll
Plugin.AppointmentReminders.dll
Expand Down
1 change: 1 addition & 0 deletions DentallApp.sln
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Elements", "Soluti
.env.example = .env.example
tests\IntegrationTests\.env.test = tests\IntegrationTests\.env.test
tests\IntegrationTests\.env.test.example = tests\IntegrationTests\.env.test.example
src\HostApplication\appsettings.json = src\HostApplication\appsettings.json
Directory.Build.props = Directory.Build.props
Directory.Packages.props = Directory.Packages.props
EndProjectSection
Expand Down
4 changes: 3 additions & 1 deletion src/HostApplication/Extensions/AuthenticationJwtBearer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

public static class AuthenticationJwtBearer
{
public static IServiceCollection AddAuthenticationJwtBearer(this IServiceCollection services, AppSettings settings)
public static IServiceCollection AddAuthenticationJwtBearer(
this IServiceCollection services,
AppSettings settings)
{
services.AddAuthentication(options =>
{
Expand Down
31 changes: 31 additions & 0 deletions src/HostApplication/Extensions/LanguageExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace DentallApp.HostApplication.Extensions;

public static class LanguageExtensions
{
public static IServiceCollection ConfigureLanguages(
this IServiceCollection services,
IConfiguration configuration)
{
services.Configure<RequestLocalizationOptions>(options =>
{
List<CultureInfo> supportedCultures = [];
var languages = configuration.GetLanguages();
foreach (var language in languages)
supportedCultures.Add(new CultureInfo(language));

var defaultLanguage = configuration.GetDefaultLanguage();
options.DefaultRequestCulture = new RequestCulture(defaultLanguage);
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
});
return services;
}

public static string[] GetLanguages(this IConfiguration configuration)
=> configuration
.GetRequiredSection("Languages")
.Get<string[]>() ?? [];

public static string GetDefaultLanguage(this IConfiguration configuration)
=> configuration.GetValue<string>("DefaultLanguage") ?? "es";
}
32 changes: 30 additions & 2 deletions src/HostApplication/Extensions/SwaggerGen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ public static class SwaggerGen
public static IServiceCollection AddSwagger(this IServiceCollection services)
{
services.AddSwaggerGen(options =>
{
{
options.OperationFilter<AcceptLanguageHeaderParameter>();
options.EnableAnnotations();
options.SwaggerDoc("v1", new OpenApiInfo { Title = "DentallApi", Version = "v1" });
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
Expand All @@ -27,7 +28,7 @@ public static IServiceCollection AddSwagger(this IServiceCollection services)
Id = "Bearer"
}
},
new string[] { }
Array.Empty<string>()
}
});
var coreAssemblyName = typeof(GetDependentsByCurrentUserIdUseCase).Assembly.GetName().Name;
Expand All @@ -44,4 +45,31 @@ public static IServiceCollection AddSwagger(this IServiceCollection services)
});
return services;
}

private class AcceptLanguageHeaderParameter(IConfiguration configuration) : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
operation.Parameters ??= [];
var languageOptions = new List<IOpenApiAny>();
var languages = configuration.GetLanguages();
var defaultLanguage = configuration.GetDefaultLanguage();
foreach (var language in languages)
languageOptions.Add(new OpenApiString(language));

operation.Parameters.Add(new OpenApiParameter
{
Name = "Accept-Language",
Description = "Language preference for the response.",
In = ParameterLocation.Header,
Required = false,
Schema = new OpenApiSchema
{
Type = "string",
Default = new OpenApiString(defaultLanguage),
Enum = languageOptions
}
});
}
}
}
4 changes: 4 additions & 0 deletions src/HostApplication/GlobalUsings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@
global using DentallApp.Shared.Configuration;

global using System.Reflection;
global using System.Globalization;
global using System.Net;
global using System.Text;
global using System.Text.Encodings.Web;
global using System.Text.Json.Serialization;

global using Microsoft.AspNetCore.Localization;
global using Microsoft.AspNetCore.Mvc.ApplicationParts;
global using Microsoft.AspNetCore.Authentication;
global using Microsoft.AspNetCore.Authentication.JwtBearer;
Expand All @@ -31,6 +33,8 @@
global using Microsoft.Extensions.Options;
global using Microsoft.Extensions.DependencyInjection.Extensions;
global using Microsoft.OpenApi.Models;
global using Microsoft.OpenApi.Any;
global using Swashbuckle.AspNetCore.SwaggerGen;
global using EntityFramework.Exceptions.Common;

global using DotEnv.Core;
Expand Down
4 changes: 2 additions & 2 deletions src/HostApplication/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
builder.Services.AddSwagger();
builder.Services.AddAuthenticationJwtBearer(appSettings);
builder.Services.AddValidators();
builder.Services.ConfigureLanguages(builder.Configuration);

builder.Services
.AddExceptionHandler<ReferenceConstraintExceptionHandler>()
Expand All @@ -44,8 +45,7 @@
app.UseExceptionHandler("/");
}

app.UseRequestLocalization(appSettings.Language);

app.UseRequestLocalization();
app.UseWebSockets()
.UsePathBase(new PathString("/api"))
.UseRouting()
Expand Down
9 changes: 0 additions & 9 deletions src/HostApplication/appsettings.Development.json

This file was deleted.

13 changes: 9 additions & 4 deletions src/HostApplication/appsettings.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
{
"MicrosoftAppType": "",
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"MicrosoftAppTenantId": ""
"MicrosoftAppType": "",
"MicrosoftAppId": "",
"MicrosoftAppPassword": "",
"MicrosoftAppTenantId": "",
"DefaultLanguage": "es",
"Languages": [
"es",
"en"
]
}
1 change: 0 additions & 1 deletion src/Shared/Configuration/AppSettings.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ public class AppSettings
{
public string BusinessName { get; set; } = string.Empty;
public string DentalServicesImagesPath { get; set; } = string.Empty;
public string Language { get; set; } = string.Empty;

public string AccessTokenKey { get; set; } = string.Empty;
public double AccessTokenExpires { get; set; }
Expand Down

0 comments on commit 307cd48

Please sign in to comment.