Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/BootstrapBlazor.Server/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@
}
},
"IgnoreLocalizerMissing": true,
"DisableGetLocalizerFromService": true,
"DisableGetLocalizerFromResourceManager": true,
"StepSettings": {
"Short": "1",
"Int": "1",
Expand Down
10 changes: 10 additions & 0 deletions src/BootstrapBlazor/Localization/Json/JsonLocalizationOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,16 @@ public class JsonLocalizationOptions : LocalizationOptions
/// </summary>
public bool UseKeyWhenValueIsNull { get; set; }

/// <summary>
/// 获得/设置 是否禁用从服务中获取本地化资源 默认 false 未禁用
/// </summary>
public bool DisableGetLocalizerFromService { get; set; }

/// <summary>
/// 获得/设置 是否禁用获取 <see cref="ResourceManagerStringLocalizer"/> 类型本地化资源 默认 false 未禁用
/// </summary>
public bool DisableGetLocalizerFromResourceManager { get; set; }

/// <summary>
/// 获得/设置 资源文件是否热加载 默认 false
/// </summary>
Expand Down
66 changes: 41 additions & 25 deletions src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,11 @@ namespace BootstrapBlazor.Components;
/// <param name="assembly"></param>
/// <param name="typeName"></param>
/// <param name="baseName"></param>
/// <param name="ignoreLocalizerMissing"></param>
/// <param name="jsonLocalizationOptions"></param>
/// <param name="logger"></param>
/// <param name="resourceNamesCache"></param>
/// <param name="localizationMissingItemHandler"></param>
internal class JsonStringLocalizer(Assembly assembly, string typeName, string baseName, bool ignoreLocalizerMissing, ILogger logger, IResourceNamesCache resourceNamesCache, ILocalizationMissingItemHandler localizationMissingItemHandler) : ResourceManagerStringLocalizer(new ResourceManager(baseName, assembly), assembly, baseName, resourceNamesCache, logger)
internal class JsonStringLocalizer(Assembly assembly, string typeName, string baseName, JsonLocalizationOptions jsonLocalizationOptions, ILogger logger, IResourceNamesCache resourceNamesCache, ILocalizationMissingItemHandler localizationMissingItemHandler) : ResourceManagerStringLocalizer(new ResourceManager(baseName, assembly), assembly, baseName, resourceNamesCache, logger)
{
private Assembly Assembly { get; } = assembly;

Expand Down Expand Up @@ -72,26 +72,39 @@ public override LocalizedString this[string name]
}
}

private string? GetStringSafely(string name) => GetStringFromService(name) ?? GetStringSafely(name, null) ?? GetStringSafelyFromJson(name);
private string? GetStringSafely(string name) => GetStringFromService(name) ?? GetStringFromResourceManager(name) ?? GetStringFromJson(name);

private string? GetStringFromService(string name)
{
// get string from inject service
string? ret = null;
var localizer = Utility.GetStringLocalizerFromService(Assembly, typeName);
if (localizer != null && localizer is not JsonStringLocalizer)
if (jsonLocalizationOptions.DisableGetLocalizerFromService == false)
{
var l = localizer[name];
if (!l.ResourceNotFound)
var localizer = Utility.GetStringLocalizerFromService(Assembly, typeName);
if (localizer != null && localizer is not JsonStringLocalizer)
{
ret = l.Value;
var l = localizer[name];
if (!l.ResourceNotFound)
{
ret = l.Value;
}
}
}
return ret;
}

private string? GetStringFromResourceManager(string name)
{
string? ret = null;
if (jsonLocalizationOptions.DisableGetLocalizerFromResourceManager == false)
{
ret = GetStringSafely(name, CultureInfo.CurrentUICulture);
}
return ret;
}

private readonly ConcurrentDictionary<string, object?> _missingManifestCache = [];
private string? GetStringSafelyFromJson(string name)
private string? GetStringFromJson(string name)
{
// get string from json localization file
var localizerStrings = MegerResolveLocalizers(CacheManager.GetAllStringsByTypeName(Assembly, typeName));
Expand All @@ -114,22 +127,18 @@ public override LocalizedString this[string name]

private List<LocalizedString> MegerResolveLocalizers(IEnumerable<LocalizedString>? localizerStrings)
{
var localizers = new List<LocalizedString>();
var resolveLocalizers = CacheManager.GetTypeStringsFromResolve(typeName);
localizers.AddRange(resolveLocalizers);

var localizers = new List<LocalizedString>(CacheManager.GetTypeStringsFromResolve(typeName));
if (localizerStrings != null)
{
localizers.AddRange(localizerStrings);
}
return localizers;
}


private void HandleMissingResourceItem(string name)
{
localizationMissingItemHandler.HandleMissingItem(name, typeName, CultureInfo.CurrentUICulture.Name);
if (!ignoreLocalizerMissing)
if (jsonLocalizationOptions.IgnoreLocalizerMissing == false)
{
Logger.LogInformation("{JsonStringLocalizerName} searched for '{Name}' in '{TypeName}' with culture '{CultureName}' not found.", nameof(JsonStringLocalizer), name, typeName, CultureInfo.CurrentUICulture.Name);
}
Expand Down Expand Up @@ -160,10 +169,13 @@ public override IEnumerable<LocalizedString> GetAllStrings(bool includeParentCul
IEnumerable<LocalizedString>? GetAllStringsFromService()
{
IEnumerable<LocalizedString>? ret = null;
var localizer = Utility.GetStringLocalizerFromService(Assembly, typeName);
if (localizer != null && localizer is not JsonStringLocalizer)
if (jsonLocalizationOptions.DisableGetLocalizerFromService == false)
{
ret = localizer.GetAllStrings(includeParentCultures);
var localizer = Utility.GetStringLocalizerFromService(Assembly, typeName);
if (localizer != null && localizer is not JsonStringLocalizer)
{
ret = localizer.GetAllStrings(includeParentCultures);
}
}
return ret;
}
Expand All @@ -172,14 +184,18 @@ public override IEnumerable<LocalizedString> GetAllStrings(bool includeParentCul
// get all strings from base json localization factory
IEnumerable<LocalizedString>? GetAllStringsFromBase()
{
IEnumerable<LocalizedString>? ret = base.GetAllStrings(includeParentCultures);
try
{
CheckMissing();
}
catch (MissingManifestResourceException)
IEnumerable<LocalizedString>? ret = null;
if (jsonLocalizationOptions.DisableGetLocalizerFromResourceManager == false)
{
ret = null;
ret = base.GetAllStrings(includeParentCultures);
try
{
CheckMissing();
}
catch (MissingManifestResourceException)
{
ret = null;
}
}
return ret;

Expand Down
51 changes: 21 additions & 30 deletions src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,10 @@ namespace BootstrapBlazor.Components;
/// </summary>
internal class JsonStringLocalizerFactory : ResourceManagerStringLocalizerFactory
{
private ILoggerFactory LoggerFactory { get; set; }

private ILocalizationMissingItemHandler LocalizationMissingItemHandler { get; set; }

[NotNull]
private string? TypeName { get; set; }

private bool IgnoreLocalizerMissing { get; set; }
private readonly ILoggerFactory _loggerFactory;
private readonly JsonLocalizationOptions _jsonLocalizationOptions;
private readonly ILocalizationMissingItemHandler _localizationMissingItemHandler;
private string? _typeName;

/// <summary>
/// 构造函数
Expand All @@ -35,7 +31,7 @@ internal class JsonStringLocalizerFactory : ResourceManagerStringLocalizerFactor
public JsonStringLocalizerFactory(
ICacheManager cacheManager,
ILocalizationMissingItemHandler localizationMissingItemHandler,
IOptionsMonitor<BootstrapBlazorOptions> options,
IOptions<BootstrapBlazorOptions> options,
IOptions<JsonLocalizationOptions> jsonLocalizationOptions,
IOptions<LocalizationOptions> localizationOptions,
ILoggerFactory loggerFactory) : base(localizationOptions, loggerFactory)
Expand All @@ -44,28 +40,23 @@ public JsonStringLocalizerFactory(
// 为了保证 CacheManager 内部 Instance 可用这里需要使 ICacheManager 先实例化
cacheManager.SetStartTime();

jsonLocalizationOptions.Value.FallbackCulture = options.CurrentValue.FallbackCulture;
jsonLocalizationOptions.Value.EnableFallbackCulture = options.CurrentValue.EnableFallbackCulture;
if (options.CurrentValue.IgnoreLocalizerMissing.HasValue)
jsonLocalizationOptions.Value.FallbackCulture = options.Value.FallbackCulture;
jsonLocalizationOptions.Value.EnableFallbackCulture = options.Value.EnableFallbackCulture;
if (options.Value.IgnoreLocalizerMissing.HasValue)
{
jsonLocalizationOptions.Value.IgnoreLocalizerMissing = options.CurrentValue.IgnoreLocalizerMissing.Value;
jsonLocalizationOptions.Value.IgnoreLocalizerMissing = options.Value.IgnoreLocalizerMissing.Value;
}
IgnoreLocalizerMissing = jsonLocalizationOptions.Value.IgnoreLocalizerMissing;
LocalizationMissingItemHandler = localizationMissingItemHandler;
LoggerFactory = loggerFactory;
options.OnChange(OnChange);

[ExcludeFromCodeCoverage]
void OnChange(BootstrapBlazorOptions op)
if (options.Value.DisableGetLocalizerFromService.HasValue)
{
jsonLocalizationOptions.Value.DisableGetLocalizerFromService = options.Value.DisableGetLocalizerFromService.Value;
}
if (options.Value.DisableGetLocalizerFromResourceManager.HasValue)
{
jsonLocalizationOptions.Value.EnableFallbackCulture = op.EnableFallbackCulture;
jsonLocalizationOptions.Value.FallbackCulture = op.FallbackCulture;
if (op.IgnoreLocalizerMissing.HasValue)
{
jsonLocalizationOptions.Value.IgnoreLocalizerMissing = op.IgnoreLocalizerMissing.Value;
IgnoreLocalizerMissing = op.IgnoreLocalizerMissing.Value;
}
jsonLocalizationOptions.Value.DisableGetLocalizerFromResourceManager = options.Value.DisableGetLocalizerFromResourceManager.Value;
}
_localizationMissingItemHandler = localizationMissingItemHandler;
_loggerFactory = loggerFactory;
_jsonLocalizationOptions = jsonLocalizationOptions.Value;
}

/// <summary>
Expand All @@ -86,7 +77,7 @@ protected override string GetResourcePrefix(TypeInfo typeInfo)
var index = typeName.IndexOf('`');
typeName = typeName[..index];
}
TypeName = typeName;
_typeName = typeName;

return base.GetResourcePrefix(typeInfo);
}
Expand All @@ -101,7 +92,7 @@ protected override string GetResourcePrefix(string baseResourceName, string base
{
// https://gitee.com/LongbowEnterprise/BootstrapBlazor/issues/I5SRA1
var resourcePrefix = base.GetResourcePrefix(baseResourceName, baseNamespace);
TypeName = $"{baseNamespace}.{baseResourceName}";
_typeName = $"{baseNamespace}.{baseResourceName}";

return resourcePrefix;
}
Expand All @@ -114,5 +105,5 @@ protected override string GetResourcePrefix(string baseResourceName, string base
/// <param name="assembly">The assembly to create a <see cref="ResourceManagerStringLocalizer"/> for</param>
/// <param name="baseName">The base name of the resource to search for</param>
/// <returns></returns>
protected override ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(Assembly assembly, string baseName) => new JsonStringLocalizer(assembly, TypeName, baseName, IgnoreLocalizerMissing, LoggerFactory.CreateLogger<JsonStringLocalizer>(), ResourceNamesCache, LocalizationMissingItemHandler);
protected override ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(Assembly assembly, string baseName) => new JsonStringLocalizer(assembly, _typeName!, baseName, _jsonLocalizationOptions, _loggerFactory.CreateLogger<JsonStringLocalizer>(), ResourceNamesCache, _localizationMissingItemHandler);
}
11 changes: 11 additions & 0 deletions src/BootstrapBlazor/Options/BootstrapBlazorOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

using Microsoft.Extensions.Localization;
using System.Globalization;

namespace BootstrapBlazor.Components;
Expand Down Expand Up @@ -58,6 +59,16 @@ public class BootstrapBlazorOptions : IOptions<BootstrapBlazorOptions>
/// <remarks>使用 <see cref="JsonLocalizationOptions.IgnoreLocalizerMissing"/> 默认值</remarks>
public bool? IgnoreLocalizerMissing { get; set; }

/// <summary>
/// 获得/设置 是否禁用从服务中获取本地化资源 默认 false 未禁用
/// </summary>
public bool? DisableGetLocalizerFromService { get; set; }

/// <summary>
/// 获得/设置 是否禁用获取 <see cref="ResourceManagerStringLocalizer"/> 类型本地化资源 默认 false 未禁用
/// </summary>
public bool? DisableGetLocalizerFromResourceManager { get; set; }

/// <summary>
/// 获得/设置 默认文化信息
/// </summary>
Expand Down
1 change: 0 additions & 1 deletion test/UnitTest/Components/SelectGenericTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ namespace UnitTest.Components;

public class SelectGenericTest : BootstrapBlazorTestBase
{

[Fact]
public void ScrollIntoViewBehavior_Ok()
{
Expand Down
23 changes: 23 additions & 0 deletions test/UnitTest/Localization/JsonStringLocalizerTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
// Maintainer: Argo Zhang([email protected]) Website: https://www.blazor.zone

using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using System.ComponentModel.DataAnnotations;
Expand Down Expand Up @@ -175,6 +176,27 @@ public void GetAllStrings_FromBase()
Assert.Empty(items);
}

[Fact]
public void DisableGetLocalizerFromResourceManager_Ok()
{
var sc = new ServiceCollection();
var builder = new ConfigurationBuilder();
builder.AddJsonFile("appsettings.json");
builder.AddInMemoryCollection(new Dictionary<string, string?>()
{
["BootstrapBlazorOptions:DisableGetLocalizerFromService"] = "true",
["BootstrapBlazorOptions:DisableGetLocalizerFromResourceManager"] = "true"
});
var config = builder.Build();
sc.AddSingleton<IConfiguration>(config);
sc.AddBootstrapBlazor();

var provider = sc.BuildServiceProvider();
var localizer = provider.GetRequiredService<IStringLocalizer<Dummy>>();
var items = localizer.GetAllStrings(false);
Assert.Empty(items);
}

[Fact]
public void GetAllStrings_FromResource()
{
Expand Down Expand Up @@ -243,6 +265,7 @@ public void HandleMissingItem()
var provider = sc.BuildServiceProvider();
var localizer = provider.GetRequiredService<IStringLocalizer<Foo>>();
var val = localizer["missing-item"];
Assert.True(val.ResourceNotFound);

var handler = provider.GetRequiredService<ILocalizationMissingItemHandler>();
MockLocalizationMissingItemHandler? mockHandler = null;
Expand Down
Loading