From fd359b3634e55969ffa95717bbdb6f98de21fc4e Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 28 Mar 2026 18:03:41 +0800 Subject: [PATCH 1/7] =?UTF-8?q?feat:=20=E5=A2=9E=E5=8A=A0=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E8=B5=84=E6=BA=90=E6=96=87=E4=BB=B6=E9=94=AE=E5=80=BC?= =?UTF-8?q?=E7=BC=93=E5=AD=98=E6=B8=85=E7=A9=BA=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Localization/Json/JsonStringLocalizer.cs | 15 ++++++++-- .../Json/JsonStringLocalizerFactory.cs | 15 +++++++++- src/BootstrapBlazor/Services/CacheManager.cs | 10 +++++++ .../Localization/JsonStringLocalizerTest.cs | 30 ++++++++++++++++++- 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs index fb7386858d7..1e240ea0c83 100644 --- a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs +++ b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs @@ -106,6 +106,12 @@ public override LocalizedString this[string name] } private readonly ConcurrentDictionary _missingManifestCache = []; + + /// + /// 清除缓存方法 + /// + public void ResetMissingMainifestCache() => _missingManifestCache.Clear(); + private string? GetStringFromJson(string name) { // 从 json 本地化文件中获取字符串 @@ -172,11 +178,16 @@ private List MergeResolveLocalizers(IEnumerable? _allLocalizedStrings; diff --git a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs index bc9cf1600a7..6973b7dc8f1 100644 --- a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs +++ b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs @@ -19,6 +19,7 @@ internal class JsonStringLocalizerFactory : ResourceManagerStringLocalizerFactor private readonly JsonLocalizationOptions _jsonLocalizationOptions; private readonly ILocalizationMissingItemHandler _localizationMissingItemHandler; private string? _typeName; + private JsonStringLocalizer? _localizer; /// /// 构造函数 @@ -108,5 +109,17 @@ protected override string GetResourcePrefix(string baseResourceName, string base /// /// The assembly to create a forThe assembly to create a for /// The base name of the resource to search forThe base name of the resource to search for - protected override ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(Assembly assembly, string baseName) => new JsonStringLocalizer(assembly, _typeName!, baseName, _jsonLocalizationOptions, _loggerFactory.CreateLogger(), ResourceNamesCache, _localizationMissingItemHandler); + protected override ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(Assembly assembly, string baseName) + { + _localizer = new JsonStringLocalizer(assembly, _typeName!, baseName, _jsonLocalizationOptions, _loggerFactory.CreateLogger(), ResourceNamesCache, _localizationMissingItemHandler); + return _localizer; + } + + /// + /// 重置方法 + /// + public void Reset() + { + _localizer?.ResetMissingMainifestCache(); + } } diff --git a/src/BootstrapBlazor/Services/CacheManager.cs b/src/BootstrapBlazor/Services/CacheManager.cs index 400e72a2e7c..46dd9644f7c 100644 --- a/src/BootstrapBlazor/Services/CacheManager.cs +++ b/src/BootstrapBlazor/Services/CacheManager.cs @@ -110,6 +110,16 @@ public void Clear(object? key) else if (Cache is MemoryCache c) { c.Compact(100); + + // 资源文件 + var factories = Provider.GetServices(); + foreach (var factory in factories) + { + if (factory is JsonStringLocalizerFactory f) + { + f.Reset(); + } + } } } diff --git a/test/UnitTest/Localization/JsonStringLocalizerTest.cs b/test/UnitTest/Localization/JsonStringLocalizerTest.cs index 1d482e2b28b..be3c9fcb650 100644 --- a/test/UnitTest/Localization/JsonStringLocalizerTest.cs +++ b/test/UnitTest/Localization/JsonStringLocalizerTest.cs @@ -5,6 +5,7 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Localization; +using System.Collections.Concurrent; using System.ComponentModel.DataAnnotations; using System.Reflection; @@ -215,7 +216,8 @@ public void GetAllStrings_FromResource() Assert.NotEmpty(items); Assert.Equal("test-name", items.First(i => i.Name == "Name").Value); - var name = Utility.GetDisplayName(typeof(Dummy), "DummyName"); + var type = typeof(Dummy); + var name = Utility.GetDisplayName(type, "DummyName"); Assert.Equal("test-name", name); } @@ -498,5 +500,31 @@ public void GetAllStrings_FromInject() var localizer = provider.GetRequiredService>(); var item = localizer["Foo.Name"]; Assert.NotEqual("Foo.Name", item); + + item = localizer["missing-item"]; + Assert.True(item.ResourceNotFound); + + // 测试 Reset + var cacheManager = provider.GetRequiredService(); + cacheManager.Clear(); + + // 测试内部缓存值为空集合 + var localizerInfo = localizer.GetType().GetField("_localizer", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.NotNull(localizerInfo); + var v = localizerInfo.GetValue(localizer); + Assert.NotNull(v); + + var fieldInfo = v.GetType().GetField("_missingManifestCache", BindingFlags.Instance | BindingFlags.NonPublic); + Assert.NotNull(fieldInfo); + + var val = fieldInfo.GetValue(v); + Assert.NotNull(val); + + bool useCache = false; + if (val is ConcurrentDictionary cache) + { + useCache = cache.IsEmpty; + } + Assert.True(useCache); } } From 8ffbe08509ff1b94eff16a64c7b4c3b066015d81 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 28 Mar 2026 18:04:27 +0800 Subject: [PATCH 2/7] chore: bump version 10.5.0-beta03 --- src/BootstrapBlazor/BootstrapBlazor.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/BootstrapBlazor/BootstrapBlazor.csproj b/src/BootstrapBlazor/BootstrapBlazor.csproj index 66d50a785ea..c3d69e9e0a3 100644 --- a/src/BootstrapBlazor/BootstrapBlazor.csproj +++ b/src/BootstrapBlazor/BootstrapBlazor.csproj @@ -1,7 +1,7 @@  - 10.5.0-beta02 + 10.5.0-beta03 From bf5a058fa4fcaa2c89bad6f8f77df5a38b692753 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sat, 28 Mar 2026 18:09:28 +0800 Subject: [PATCH 3/7] =?UTF-8?q?doc:=20=E5=A2=9E=E5=8A=A0=E6=B3=A8=E9=87=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs | 4 +++- .../Localization/Json/JsonStringLocalizerFactory.cs | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs index 1e240ea0c83..84d29f2e44a 100644 --- a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs +++ b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs @@ -108,7 +108,9 @@ public override LocalizedString this[string name] private readonly ConcurrentDictionary _missingManifestCache = []; /// - /// 清除缓存方法 + /// 清除缓存方法 + /// Reset cache method + /// v10.5.0 /// public void ResetMissingMainifestCache() => _missingManifestCache.Clear(); diff --git a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs index 6973b7dc8f1..4e16cd3172c 100644 --- a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs +++ b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs @@ -116,7 +116,9 @@ protected override ResourceManagerStringLocalizer CreateResourceManagerStringLoc } /// - /// 重置方法 + /// 清除缓存方法 + /// Reset cache method + /// v10.5.0 /// public void Reset() { From c8a1a38b5ab0bd427598e7f3329b190f02be037a Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 29 Mar 2026 15:09:09 +0800 Subject: [PATCH 4/7] =?UTF-8?q?refactor:=20=E4=BF=AE=E5=A4=8D=E6=8B=BC?= =?UTF-8?q?=E5=86=99=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs | 2 +- .../Localization/Json/JsonStringLocalizerFactory.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs index 84d29f2e44a..20f5bd29aeb 100644 --- a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs +++ b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs @@ -112,7 +112,7 @@ public override LocalizedString this[string name] /// Reset cache method /// v10.5.0 /// - public void ResetMissingMainifestCache() => _missingManifestCache.Clear(); + public void ResetMissingManifestCache() => _missingManifestCache.Clear(); private string? GetStringFromJson(string name) { diff --git a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs index 4e16cd3172c..9ae227cd598 100644 --- a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs +++ b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs @@ -122,6 +122,6 @@ protected override ResourceManagerStringLocalizer CreateResourceManagerStringLoc /// public void Reset() { - _localizer?.ResetMissingMainifestCache(); + _localizer?.ResetMissingManifestCache(); } } From 675aa6724a6b1f32559d536e3908f68cf9ba8706 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 29 Mar 2026 15:14:08 +0800 Subject: [PATCH 5/7] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=20Reset=20?= =?UTF-8?q?=E6=96=B9=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Json/JsonStringLocalizerFactory.cs | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs index 9ae227cd598..bc9cf1600a7 100644 --- a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs +++ b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizerFactory.cs @@ -19,7 +19,6 @@ internal class JsonStringLocalizerFactory : ResourceManagerStringLocalizerFactor private readonly JsonLocalizationOptions _jsonLocalizationOptions; private readonly ILocalizationMissingItemHandler _localizationMissingItemHandler; private string? _typeName; - private JsonStringLocalizer? _localizer; /// /// 构造函数 @@ -109,19 +108,5 @@ protected override string GetResourcePrefix(string baseResourceName, string base /// /// The assembly to create a forThe assembly to create a for /// The base name of the resource to search forThe base name of the resource to search for - protected override ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(Assembly assembly, string baseName) - { - _localizer = new JsonStringLocalizer(assembly, _typeName!, baseName, _jsonLocalizationOptions, _loggerFactory.CreateLogger(), ResourceNamesCache, _localizationMissingItemHandler); - return _localizer; - } - - /// - /// 清除缓存方法 - /// Reset cache method - /// v10.5.0 - /// - public void Reset() - { - _localizer?.ResetMissingManifestCache(); - } + protected override ResourceManagerStringLocalizer CreateResourceManagerStringLocalizer(Assembly assembly, string baseName) => new JsonStringLocalizer(assembly, _typeName!, baseName, _jsonLocalizationOptions, _loggerFactory.CreateLogger(), ResourceNamesCache, _localizationMissingItemHandler); } From 1cf8635c752bd37be36267da6312cffaf0e3636f Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 29 Mar 2026 15:18:01 +0800 Subject: [PATCH 6/7] =?UTF-8?q?refactor:=20=E7=A7=BB=E9=99=A4=E7=BC=BA?= =?UTF-8?q?=E5=A4=B1=E8=B5=84=E6=BA=90=E9=94=AE=E5=80=BC=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Localization/Json/JsonStringLocalizer.cs | 45 +++++++------------ src/BootstrapBlazor/Services/CacheManager.cs | 10 ----- 2 files changed, 15 insertions(+), 40 deletions(-) diff --git a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs index 20f5bd29aeb..9bfcdfc3e01 100644 --- a/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs +++ b/src/BootstrapBlazor/Localization/Json/JsonStringLocalizer.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Localization; using Microsoft.Extensions.Logging; -using System.Collections.Concurrent; using System.Globalization; using System.Reflection; using System.Resources; @@ -105,41 +104,28 @@ public override LocalizedString this[string name] return ret; } - private readonly ConcurrentDictionary _missingManifestCache = []; - - /// - /// 清除缓存方法 - /// Reset cache method - /// v10.5.0 - /// - public void ResetMissingManifestCache() => _missingManifestCache.Clear(); - private string? GetStringFromJson(string name) { - // 从 json 本地化文件中获取字符串 - // get string from json localization file var localizerStrings = MergeResolveLocalizers(CacheManager.GetAllStringsByTypeName(Assembly, typeName)); var cacheKey = $"name={name}&culture={CultureInfo.CurrentUICulture.Name}"; string? ret = null; - if (!_missingManifestCache.ContainsKey(cacheKey)) + + var l = localizerStrings.Find(i => i.Name == name); + if (l is { ResourceNotFound: false }) { - var l = localizerStrings.Find(i => i.Name == name); - if (l is { ResourceNotFound: false }) - { - ret = l.Value; - } - else - { - // 如果没有找到资源信息则尝试从父类中查找 - // If resource info not found, try to find from base class - ret ??= GetStringFromBaseType(name); + ret = l.Value; + } + else + { + // 如果没有找到资源信息则尝试从父类中查找 + // If resource info not found, try to find from base class + ret ??= GetStringFromBaseType(name); - if (ret is null) - { - // 加入缺失资源信息缓存中 - // Add to missing resource info cache - HandleMissingResourceItem(name); - } + if (ret is null) + { + // 加入缺失资源信息缓存中 + // Add to missing resource info cache + HandleMissingResourceItem(name); } } return ret; @@ -182,7 +168,6 @@ private void HandleMissingResourceItem(string name) localizationMissingItemHandler.HandleMissingItem(name, typeName, CultureInfo.CurrentUICulture.Name); if (jsonLocalizationOptions.IgnoreLocalizerMissing) { - _missingManifestCache.TryAdd($"name={name}&culture={CultureInfo.CurrentUICulture.Name}", null); return; } diff --git a/src/BootstrapBlazor/Services/CacheManager.cs b/src/BootstrapBlazor/Services/CacheManager.cs index c529d9e99bc..0d459357f23 100644 --- a/src/BootstrapBlazor/Services/CacheManager.cs +++ b/src/BootstrapBlazor/Services/CacheManager.cs @@ -109,16 +109,6 @@ public void Clear(object? key) else if (Cache is MemoryCache c) { c.Compact(100); - - // 资源文件 - var factories = Provider.GetServices(); - foreach (var factory in factories) - { - if (factory is JsonStringLocalizerFactory f) - { - f.Reset(); - } - } } } From e77e6c607a8ced7e3bbb93368c085e49d0c04cd5 Mon Sep 17 00:00:00 2001 From: Argo Zhang Date: Sun, 29 Mar 2026 15:20:34 +0800 Subject: [PATCH 7/7] =?UTF-8?q?test:=20=E6=9B=B4=E6=96=B0=E5=8D=95?= =?UTF-8?q?=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Localization/JsonStringLocalizerTest.cs | 24 ------------------- 1 file changed, 24 deletions(-) diff --git a/test/UnitTest/Localization/JsonStringLocalizerTest.cs b/test/UnitTest/Localization/JsonStringLocalizerTest.cs index be3c9fcb650..2bc5c3ab7a8 100644 --- a/test/UnitTest/Localization/JsonStringLocalizerTest.cs +++ b/test/UnitTest/Localization/JsonStringLocalizerTest.cs @@ -5,7 +5,6 @@ using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Localization; -using System.Collections.Concurrent; using System.ComponentModel.DataAnnotations; using System.Reflection; @@ -503,28 +502,5 @@ public void GetAllStrings_FromInject() item = localizer["missing-item"]; Assert.True(item.ResourceNotFound); - - // 测试 Reset - var cacheManager = provider.GetRequiredService(); - cacheManager.Clear(); - - // 测试内部缓存值为空集合 - var localizerInfo = localizer.GetType().GetField("_localizer", BindingFlags.Instance | BindingFlags.NonPublic); - Assert.NotNull(localizerInfo); - var v = localizerInfo.GetValue(localizer); - Assert.NotNull(v); - - var fieldInfo = v.GetType().GetField("_missingManifestCache", BindingFlags.Instance | BindingFlags.NonPublic); - Assert.NotNull(fieldInfo); - - var val = fieldInfo.GetValue(v); - Assert.NotNull(val); - - bool useCache = false; - if (val is ConcurrentDictionary cache) - { - useCache = cache.IsEmpty; - } - Assert.True(useCache); } }