-
Notifications
You must be signed in to change notification settings - Fork 10
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
22 changed files
with
4,840 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
76 changes: 76 additions & 0 deletions
76
src/Indice.AspNetCore/Features/Translations/TranslationsGraphFeatureExtensions.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
#if NET8_0_OR_GREATER | ||
#nullable enable | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Routing.Constraints; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Microsoft.Extensions.Localization; | ||
using Microsoft.Extensions.Options; | ||
using System.Diagnostics.CodeAnalysis; | ||
using System.Reflection; | ||
|
||
namespace Microsoft.AspNetCore.Routing; | ||
|
||
/// <summary> | ||
/// Extension methods to configure the Translations json endpoint. | ||
/// </summary> | ||
public static class TranslationsGraphFeatureExtensions | ||
{ | ||
|
||
/// <summary> | ||
/// Adds translation dependencies. This will configure a resex file key value pair as source and produce a json. | ||
/// </summary> | ||
/// <param name="services">The service collection</param> | ||
/// <param name="configureAction">The action to configure the translations endpoint source of key value pairs</param> | ||
/// <returns>The service collection for further configuration</returns> | ||
public static IServiceCollection AddTranslationGraph(this IServiceCollection services, Action<TranslationsGraphOptions>? configureAction = null) { | ||
services.AddLocalization(); | ||
services.Configure<RouteOptions>(options => options.ConstraintMap.Add("culture", typeof(CultureRouteConstraint))); | ||
var options = new TranslationsGraphOptions(); | ||
configureAction?.Invoke(options); | ||
services.Configure<TranslationsGraphOptions>((o) => { | ||
o.TranslationsBaseName = options.TranslationsBaseName; | ||
o.TranslationsLocation = options.TranslationsLocation; | ||
o.EndpointRoutePattern = options.EndpointRoutePattern; | ||
}); | ||
return services; | ||
} | ||
|
||
/// <summary> | ||
/// Maps the Json Translations endpoint. | ||
/// </summary> | ||
/// <param name="routes">The endpoint route builder</param> | ||
/// <returns>The builder for further configureation</returns> | ||
|
||
public static IEndpointRouteBuilder MapTranslationGraph(this IEndpointRouteBuilder routes) { | ||
var options = routes.ServiceProvider.GetRequiredService<IOptions<TranslationsGraphOptions>>().Value; | ||
routes.MapGet(options.EndpointRoutePattern, (string lang, IStringLocalizerFactory factory) => { | ||
var strings = factory.Create(options.TranslationsBaseName, options.TranslationsLocation); | ||
return TypedResults.Ok(strings.ToObjectGraph(new System.Globalization.CultureInfo(lang))); | ||
}); | ||
return routes; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Translation json options. Will be used to configure <see cref="TranslationsGraphFeatureExtensions"/> | ||
/// </summary> | ||
public class TranslationsGraphOptions | ||
{ | ||
/// <summary> | ||
/// A dot dlimited path to the folder containing the Resex file with the translations key values. Defaults to <strong>"Resources.UiTranslations"</strong> | ||
/// </summary> | ||
public string TranslationsBaseName { get; set; } = "Resources.UiTranslations"; | ||
|
||
/// <summary> | ||
/// The assembly name containing the translation resex files as embeded resources. Defaults to <strong>Assembly.GetEntryAssembly()!.GetName().Name!</strong> | ||
/// </summary> | ||
public string TranslationsLocation { get; set; } = Assembly.GetEntryAssembly()!.GetName().Name!; | ||
/// <summary> | ||
/// The endpoint route pattern defaults to <strong>"/translations.{lang:culture}.json"</strong>. If changes are made to the path we must paintain the lang parameter. | ||
/// </summary> | ||
[StringSyntax("Route")] | ||
public string EndpointRoutePattern { get; set; } = "/translations.{lang:culture}.json"; | ||
} | ||
#nullable disable | ||
#endif |
14 changes: 14 additions & 0 deletions
14
src/Indice.AspNetCore/Http/Routing/CultureRouteConstraint.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
namespace Microsoft.AspNetCore.Routing.Constraints; | ||
|
||
|
||
/// <summary> | ||
/// Culture route constratint. | ||
/// </summary> | ||
public class CultureRouteConstraint : RegexRouteConstraint | ||
{ | ||
/// <summary> | ||
/// Constructor | ||
/// </summary> | ||
public CultureRouteConstraint() | ||
: base(@"^[a-zA-Z]{2}(\-[a-zA-Z]{2})?$") { } | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
src/Indice.Features.Identity.AdminUI.App/Indice.Features.Identity.AdminUI.App.esproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
src/Indice.Features.Messages.App/Indice.Features.Messages.App.esproj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
#if NET8_0_OR_GREATER | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Builder; | ||
using Microsoft.AspNetCore.Hosting; | ||
using Microsoft.AspNetCore.TestHost; | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.DependencyInjection; | ||
using Xunit; | ||
using Xunit.Abstractions; | ||
using Microsoft.AspNetCore.Routing; | ||
|
||
namespace Indice.Services.Tests; | ||
public class EndpointTests : IAsyncDisposable | ||
{ | ||
// Constants | ||
private const string BASE_URL = "https://server"; | ||
// Private fields | ||
private readonly HttpClient _httpClient; | ||
private readonly ITestOutputHelper _output; | ||
private ServiceProvider _serviceProvider; | ||
|
||
public EndpointTests(ITestOutputHelper output) { | ||
_output = output; | ||
var builder = new WebHostBuilder(); | ||
builder.ConfigureAppConfiguration(builder => { | ||
builder.AddInMemoryCollection(new Dictionary<string, string> { | ||
["MySection:MyKey"] = "TestValue" | ||
}); | ||
}); | ||
builder.ConfigureServices(services => { | ||
var configuration = services.BuildServiceProvider().GetService<IConfiguration>(); | ||
services.AddTransient<IEventDispatcherFactory, DefaultEventDispatcherFactory>(); | ||
services.AddRouting(); | ||
|
||
services.AddTranslationGraph((o) => { | ||
o.TranslationsBaseName = "Resources.TranslationsApi"; | ||
o.TranslationsLocation = typeof(EndpointTests).Assembly.GetName().Name; | ||
}); | ||
_serviceProvider = services.BuildServiceProvider(); | ||
}); | ||
builder.Configure(app => { | ||
app.UseRouting(); | ||
app.UseEndpoints(e => e.MapTranslationGraph()); | ||
}); | ||
var server = new TestServer(builder); | ||
var handler = server.CreateHandler(); | ||
_httpClient = new HttpClient(handler) { | ||
BaseAddress = new Uri(BASE_URL) | ||
}; | ||
} | ||
|
||
#region Facts | ||
[Fact] | ||
public async Task Test_GetTranslatio_English() { | ||
//Create the Campaign | ||
var translationResponse = await _httpClient.GetAsync("/translations.en.json"); | ||
var translationResponseJson = await translationResponse.Content.ReadAsStringAsync(); | ||
if (!translationResponse.IsSuccessStatusCode) { | ||
_output.WriteLine(translationResponseJson); | ||
} | ||
|
||
Assert.True(translationResponse.IsSuccessStatusCode); | ||
Assert.NotEmpty(translationResponseJson); | ||
} | ||
[Fact] | ||
public async Task Test_GetTranslatio_Greek() { | ||
//Create the Campaign | ||
var translationResponse = await _httpClient.GetAsync("/translations.el.json"); | ||
var translationResponseJson = await translationResponse.Content.ReadAsStringAsync(); | ||
if (!translationResponse.IsSuccessStatusCode) { | ||
_output.WriteLine(translationResponseJson); | ||
} | ||
|
||
Assert.True(translationResponse.IsSuccessStatusCode); | ||
Assert.NotEmpty(translationResponseJson); | ||
} | ||
[Fact] | ||
public async Task Test_GetTranslation_For_Culture_Not_Exists() { | ||
//Create the Campaign | ||
var translationResponse = await _httpClient.GetAsync("/translations.ru.json"); | ||
var translationResponseJson = await translationResponse.Content.ReadAsStringAsync(); | ||
if (!translationResponse.IsSuccessStatusCode) { | ||
_output.WriteLine(translationResponseJson); | ||
} | ||
|
||
Assert.True(translationResponse.IsSuccessStatusCode); | ||
Assert.NotEmpty(translationResponseJson); | ||
} | ||
[Fact] | ||
public async Task Test_GetTranslation_For_Invalid_Culture() { | ||
//Create the Campaign | ||
var translationResponse = await _httpClient.GetAsync("/translations.invalid.json"); | ||
Assert.False(translationResponse.IsSuccessStatusCode); | ||
} | ||
#endregion | ||
|
||
public async ValueTask DisposeAsync() { | ||
await _serviceProvider.DisposeAsync(); | ||
} | ||
} | ||
|
||
|
||
#endif |
Oops, something went wrong.