-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(288016): Add localization to template (#40)
* Added localization strategy + shared resources to template * Add localize test * Remove change in csproj * Add Internationalization to startup * Revert format by csharpier * Reverse format by csharpier part.2 * Remove unused usings * Add internationalization to functions and console projects * Add key and resource to resw file
- Loading branch information
Showing
24 changed files
with
454 additions
and
9 deletions.
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
69 changes: 69 additions & 0 deletions
69
...Content/Backend/NV.Templates.Backend.Core/Framework/Internationalization/CultureConfig.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,69 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Linq; | ||
|
||
namespace NV.Templates.Backend.Core.Framework.Internationalization | ||
{ | ||
public static class CultureConfig | ||
{ | ||
public static readonly CultureInfo DefaultCulture = new CultureInfo("en"); | ||
|
||
public static readonly IEnumerable<CultureInfo> SupportedCultures = new[] | ||
{ | ||
DefaultCulture, | ||
new CultureInfo("fr-CA"), | ||
}; | ||
|
||
public static readonly IEnumerable<LanguageModel> SupportedLanguages = SupportedCultures | ||
.Select(culture => new LanguageModel | ||
{ | ||
DisplayName = culture.NativeName, | ||
CultureName = culture.Name, | ||
}) | ||
.Distinct(); | ||
|
||
public static bool TryMatchCulture(string languageOrCultureName, out CultureInfo culture, CultureInfo? defaultCulture = null) | ||
{ | ||
CultureInfo? match = null; | ||
if (!string.IsNullOrWhiteSpace(languageOrCultureName)) | ||
{ | ||
match = SupportedCultures | ||
// The exact matching culture first | ||
.OrderByDescending(culture => culture.Name.Equals(languageOrCultureName, StringComparison.OrdinalIgnoreCase)) | ||
|
||
// Then the other matching languages | ||
.ThenByDescending(culture => culture.TwoLetterISOLanguageName.StartsWith(languageOrCultureName, StringComparison.OrdinalIgnoreCase) || | ||
languageOrCultureName.StartsWith(culture.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase)) | ||
|
||
// Get the first that either exactly matches the culture, of the first culture that matches the language. | ||
.FirstOrDefault(culture => culture.Name.Equals(languageOrCultureName, StringComparison.OrdinalIgnoreCase) || | ||
culture.TwoLetterISOLanguageName.StartsWith(languageOrCultureName, StringComparison.OrdinalIgnoreCase) || | ||
languageOrCultureName.StartsWith(culture.TwoLetterISOLanguageName, StringComparison.OrdinalIgnoreCase)); | ||
} | ||
|
||
culture = match ?? defaultCulture ?? DefaultCulture; | ||
|
||
return match != null; | ||
} | ||
|
||
public static void SetCulture(string languageOrCultureName, CultureInfo? fallback = null) | ||
{ | ||
TryMatchCulture(languageOrCultureName, out var culture, fallback); | ||
SetCulture(culture); | ||
} | ||
|
||
public static void SetCulture(CultureInfo culture) | ||
{ | ||
CultureInfo.CurrentUICulture = culture; | ||
CultureInfo.CurrentCulture = culture; | ||
} | ||
|
||
public class LanguageModel | ||
{ | ||
public string? DisplayName { get; set; } | ||
|
||
public string? CultureName { get; set; } | ||
} | ||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
...kend/NV.Templates.Backend.Core/Framework/Internationalization/RequestCultureMiddleware.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,28 @@ | ||
using System.Threading.Tasks; | ||
using Microsoft.AspNetCore.Http; | ||
using Microsoft.AspNetCore.Localization; | ||
|
||
namespace NV.Templates.Backend.Core.Framework.Internationalization | ||
{ | ||
public class RequestCultureMiddleware | ||
{ | ||
private readonly RequestDelegate _next; | ||
|
||
public RequestCultureMiddleware(RequestDelegate next) | ||
{ | ||
_next = next; | ||
} | ||
|
||
public async Task Invoke(HttpContext context) | ||
{ | ||
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>(); | ||
var culture = requestCultureFeature!.RequestCulture.Culture; | ||
|
||
CultureConfig.SetCulture(culture); | ||
|
||
context.Request.Headers["Accept-Language"] = culture.Name; | ||
|
||
await _next.Invoke(context); | ||
} | ||
} | ||
} |
18 changes: 18 additions & 0 deletions
18
...d/NV.Templates.Backend.Core/Framework/Internationalization/ServiceCollectionExtensions.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,18 @@ | ||
using Microsoft.Extensions.Configuration; | ||
using Microsoft.Extensions.Localization; | ||
using NV.Templates.Backend.Core.Framework.Internationalization.Services.Impl; | ||
using NV.Templates.Resources; | ||
|
||
namespace Microsoft.Extensions.DependencyInjection | ||
{ | ||
public static class ServiceCollectionExtensions | ||
{ | ||
public static IServiceCollection AddInternationalization(this IServiceCollection services, IConfiguration configuration) | ||
{ | ||
return services | ||
.AddLocalization() | ||
.AddSingleton<IStringLocalizer>(sp => sp.GetRequiredService<IStringLocalizer<SharedResources>>()) | ||
.AddSingleton<IStringLocalizerEx, StringLocalizerEx>(); | ||
} | ||
} | ||
} |
9 changes: 9 additions & 0 deletions
9
...ckend/NV.Templates.Backend.Core/Framework/Internationalization/Services/GetStringsMode.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,9 @@ | ||
namespace NV.Templates.Backend.Core.Framework.Internationalization | ||
{ | ||
public enum GetStringsMode | ||
{ | ||
OnePerLanguage, | ||
|
||
OnePerCulture, | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
...d/NV.Templates.Backend.Core/Framework/Internationalization/Services/IStringLocalizerEx.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,15 @@ | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using Microsoft.Extensions.Localization; | ||
|
||
namespace NV.Templates.Backend.Core.Framework.Internationalization | ||
{ | ||
public interface IStringLocalizerEx : IStringLocalizer | ||
{ | ||
string GetString(string name, CultureInfo culture, params object[] arguments); | ||
|
||
IDictionary<string, string> GetStrings(string name, GetStringsMode getStringsMode = GetStringsMode.OnePerCulture, params object[] arguments); | ||
|
||
IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures, params object[] arguments); | ||
} | ||
} |
67 changes: 67 additions & 0 deletions
67
....Templates.Backend.Core/Framework/Internationalization/Services/Impl/StringLocalizerEx.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,67 @@ | ||
#nullable disable | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Globalization; | ||
using System.Linq; | ||
using System.Resources; | ||
using Microsoft.Extensions.Localization; | ||
using NV.Templates.Resources; | ||
|
||
namespace NV.Templates.Backend.Core.Framework.Internationalization.Services.Impl | ||
{ | ||
public class StringLocalizerEx : ResourceManager, IStringLocalizerEx | ||
{ | ||
private readonly IStringLocalizer _localizer; | ||
|
||
public StringLocalizerEx(IStringLocalizer localizer) | ||
: base(typeof(SharedResources)) | ||
{ | ||
_localizer = localizer; | ||
} | ||
|
||
public LocalizedString this[string name] => _localizer[name]; | ||
|
||
public LocalizedString this[string name, params object[] arguments] => _localizer[name, arguments]; | ||
|
||
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures) => GetAllStrings(includeParentCultures, Array.Empty<object>()); | ||
|
||
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures, params object[] arguments) | ||
=> _localizer.GetAllStrings(includeParentCultures).Select(localizedString => | ||
{ | ||
var value = localizedString.Value; | ||
if (!localizedString.ResourceNotFound) | ||
{ | ||
value = string.Format(CultureInfo.CurrentCulture, value, arguments); | ||
} | ||
return new LocalizedString(localizedString.Name, value, localizedString.ResourceNotFound, localizedString.SearchedLocation); | ||
}); | ||
|
||
public string GetString(string name, CultureInfo culture, params object[] arguments) | ||
=> string.Format(culture, base.GetString(name, culture) ?? $"[{name}]", arguments); | ||
|
||
public IDictionary<string, string> GetStrings(string name, GetStringsMode getStringsMode = GetStringsMode.OnePerCulture, params object[] arguments) | ||
{ | ||
switch (getStringsMode) | ||
{ | ||
case GetStringsMode.OnePerLanguage: | ||
return CultureConfig | ||
.SupportedLanguages | ||
.ToDictionary( | ||
language => language.CultureName, | ||
language => CultureConfig.TryMatchCulture(language.CultureName, out var culture) ? | ||
GetString(name, culture, arguments) : | ||
string.Format(culture, $"[{name}]", arguments)); | ||
case GetStringsMode.OnePerCulture: | ||
return CultureConfig | ||
.SupportedCultures | ||
.ToDictionary( | ||
culture => culture.Name, | ||
culture => GetString(name, culture, arguments)); | ||
default: | ||
throw new ArgumentOutOfRangeException(nameof(getStringsMode)); | ||
} | ||
} | ||
} | ||
} |
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
5 changes: 4 additions & 1 deletion
5
src/Content/Backend/NV.Templates.Backend.Web/ClientApp/package-lock.json
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
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
Oops, something went wrong.