From 80879c06209e25bb776fa3f27957a55c19e969bd Mon Sep 17 00:00:00 2001 From: ShaoHua <345265198@qqcom> Date: Sun, 28 Dec 2025 01:08:55 +0800 Subject: [PATCH 1/5] support chinese language --- .../Pages/_Host.cshtml | 3 +- .../Shared/MainLayout.razor | 13 +- .../Shared/NavMenu.razor | 13 +- demo/RulesEngineEditorServer/Startup.cs | 11 + .../wwwroot/culture.js | 14 + demo/RulesEngineEditorWebAssembly/Program.cs | 14 +- .../Shared/MainLayout.razor | 13 +- .../Shared/NavMenu.razor | 12 +- .../wwwroot/culture.js | 14 + .../wwwroot/index.html | 1 + .../Components/CultureSwitcher.razor | 18 + .../Components/InputEditor.razor | 19 +- .../Components/InputParamEditor.razor | 7 +- .../Components/RuleEditor.razor | 54 +- src/RulesEngineEditor/Components/Rules.razor | 5 +- .../Components/ScopedParamEditor.razor | 7 +- .../Components/ScopedParams.razor | 9 +- .../Components/WorkflowEditor.razor | 7 +- .../Pages/RulesEngineEditorPage.razor | 49 +- .../Pages/RulesEngineEditorPage.razor.cs | 59 +- .../Resources/SharedResources.Designer.cs | 828 ++++++++++++++++++ .../Resources/SharedResources.cs | 6 + .../Resources/SharedResources.resx | 316 +++++++ .../Resources/SharedResources.zh-CN.resx | 316 +++++++ .../wwwroot/css/reeditor.css | 37 +- .../wwwroot/fonts/consolas/README.txt | 7 + 26 files changed, 1743 insertions(+), 109 deletions(-) create mode 100644 demo/RulesEngineEditorServer/wwwroot/culture.js create mode 100644 demo/RulesEngineEditorWebAssembly/wwwroot/culture.js create mode 100644 src/RulesEngineEditor/Components/CultureSwitcher.razor create mode 100644 src/RulesEngineEditor/Resources/SharedResources.Designer.cs create mode 100644 src/RulesEngineEditor/Resources/SharedResources.cs create mode 100644 src/RulesEngineEditor/Resources/SharedResources.resx create mode 100644 src/RulesEngineEditor/Resources/SharedResources.zh-CN.resx create mode 100644 src/RulesEngineEditor/wwwroot/fonts/consolas/README.txt diff --git a/demo/RulesEngineEditorServer/Pages/_Host.cshtml b/demo/RulesEngineEditorServer/Pages/_Host.cshtml index cf1d136e..f5f6f032 100644 --- a/demo/RulesEngineEditorServer/Pages/_Host.cshtml +++ b/demo/RulesEngineEditorServer/Pages/_Host.cshtml @@ -1,4 +1,4 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @@ -38,5 +38,6 @@ + diff --git a/demo/RulesEngineEditorServer/Shared/MainLayout.razor b/demo/RulesEngineEditorServer/Shared/MainLayout.razor index b8542a86..002f15e7 100644 --- a/demo/RulesEngineEditorServer/Shared/MainLayout.razor +++ b/demo/RulesEngineEditorServer/Shared/MainLayout.razor @@ -1,8 +1,9 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @inherits LayoutComponentBase +@using RulesEngineEditor.Resources
@@ -14,11 +15,13 @@ - Rules Engine Editor + @RulesEngineEditor.Resources.SharedResources.RulesEngineEditorTitle
@@ -37,4 +40,4 @@ { collapseNavMenu = !collapseNavMenu; } -} \ No newline at end of file +} diff --git a/demo/RulesEngineEditorServer/Shared/NavMenu.razor b/demo/RulesEngineEditorServer/Shared/NavMenu.razor index 560f37a1..cfddfe3c 100644 --- a/demo/RulesEngineEditorServer/Shared/NavMenu.razor +++ b/demo/RulesEngineEditorServer/Shared/NavMenu.razor @@ -1,32 +1,33 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ +@using RulesEngineEditor.Resources
diff --git a/demo/RulesEngineEditorServer/Startup.cs b/demo/RulesEngineEditorServer/Startup.cs index ca9167ce..6c4e07fd 100644 --- a/demo/RulesEngineEditorServer/Startup.cs +++ b/demo/RulesEngineEditorServer/Startup.cs @@ -16,6 +16,8 @@ using RulesEngineEditor.Services; using RulesEngineEditor.Data; using Microsoft.EntityFrameworkCore; +using Microsoft.AspNetCore.Localization; +using System.Globalization; namespace RulesEngineEditorServer { @@ -34,6 +36,7 @@ public void ConfigureServices(IServiceCollection services) { services.AddRazorPages(); services.AddServerSideBlazor(); + services.AddLocalization(options => options.ResourcesPath = "Resources"); services.AddSingleton(); //services.AddDbContext(options => options.UseSqlServer(Configuration.GetConnectionString("RulesEngineEditorDB"))); @@ -45,6 +48,14 @@ public void ConfigureServices(IServiceCollection services) // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { + var supportedCultures = new[] { new CultureInfo("en-US"), new CultureInfo("zh-CN") }; + var localizationOptions = new RequestLocalizationOptions + { + DefaultRequestCulture = new RequestCulture("en-US"), + SupportedCultures = supportedCultures, + SupportedUICultures = supportedCultures + }; + app.UseRequestLocalization(localizationOptions); if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); diff --git a/demo/RulesEngineEditorServer/wwwroot/culture.js b/demo/RulesEngineEditorServer/wwwroot/culture.js new file mode 100644 index 00000000..16d85b6d --- /dev/null +++ b/demo/RulesEngineEditorServer/wwwroot/culture.js @@ -0,0 +1,14 @@ +window.blazorCulture = { + get: function () { + return window.localStorage['BlazorCulture']; + }, + set: function (value) { + window.localStorage['BlazorCulture'] = value; + } +}; + +window.setCultureCookie = function (culture) { + var cookieValue = 'c=' + culture + '|uic=' + culture; + var secure = (location.protocol === 'https:') ? '; secure' : ''; + document.cookie = '.AspNetCore.Culture=' + cookieValue + '; path=/; samesite=lax' + secure; +}; \ No newline at end of file diff --git a/demo/RulesEngineEditorWebAssembly/Program.cs b/demo/RulesEngineEditorWebAssembly/Program.cs index 0a319520..0cfbb08a 100644 --- a/demo/RulesEngineEditorWebAssembly/Program.cs +++ b/demo/RulesEngineEditorWebAssembly/Program.cs @@ -13,6 +13,8 @@ using RulesEngineEditor.Services; using System.Text.Json; using RulesEngineEditor.Shared; +using Microsoft.JSInterop; +using System.Globalization; namespace RulesEngineEditorWebAssembly { @@ -27,13 +29,23 @@ public static async Task Main(string[] args) builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); builder.Services.AddRulesEngineEditor(); + builder.Services.AddLocalization(); builder.Services.AddScoped(sp => { return RulesEngineEditor.Shared.RulesEngineJsonSourceContext.Default.Options; }); - await builder.Build().RunAsync(); + var host = builder.Build(); + var js = host.Services.GetRequiredService(); + var cultureName = await js.InvokeAsync("blazorCulture.get"); + if (!string.IsNullOrWhiteSpace(cultureName)) + { + var culture = new CultureInfo(cultureName); + CultureInfo.DefaultThreadCurrentCulture = culture; + CultureInfo.DefaultThreadCurrentUICulture = culture; + } + await host.RunAsync(); } } } diff --git a/demo/RulesEngineEditorWebAssembly/Shared/MainLayout.razor b/demo/RulesEngineEditorWebAssembly/Shared/MainLayout.razor index 1bee1699..128be7d4 100644 --- a/demo/RulesEngineEditorWebAssembly/Shared/MainLayout.razor +++ b/demo/RulesEngineEditorWebAssembly/Shared/MainLayout.razor @@ -1,8 +1,9 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @inherits LayoutComponentBase +@using RulesEngineEditor.Resources @@ -37,4 +40,4 @@ { collapseNavMenu = !collapseNavMenu; } -} \ No newline at end of file +} diff --git a/demo/RulesEngineEditorWebAssembly/Shared/NavMenu.razor b/demo/RulesEngineEditorWebAssembly/Shared/NavMenu.razor index 4164867d..23fe98d6 100644 --- a/demo/RulesEngineEditorWebAssembly/Shared/NavMenu.razor +++ b/demo/RulesEngineEditorWebAssembly/Shared/NavMenu.razor @@ -1,29 +1,29 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ +@using RulesEngineEditor.Resources
- diff --git a/demo/RulesEngineEditorWebAssembly/wwwroot/culture.js b/demo/RulesEngineEditorWebAssembly/wwwroot/culture.js new file mode 100644 index 00000000..16d85b6d --- /dev/null +++ b/demo/RulesEngineEditorWebAssembly/wwwroot/culture.js @@ -0,0 +1,14 @@ +window.blazorCulture = { + get: function () { + return window.localStorage['BlazorCulture']; + }, + set: function (value) { + window.localStorage['BlazorCulture'] = value; + } +}; + +window.setCultureCookie = function (culture) { + var cookieValue = 'c=' + culture + '|uic=' + culture; + var secure = (location.protocol === 'https:') ? '; secure' : ''; + document.cookie = '.AspNetCore.Culture=' + cookieValue + '; path=/; samesite=lax' + secure; +}; \ No newline at end of file diff --git a/demo/RulesEngineEditorWebAssembly/wwwroot/index.html b/demo/RulesEngineEditorWebAssembly/wwwroot/index.html index 8aa1d016..f451efc6 100644 --- a/demo/RulesEngineEditorWebAssembly/wwwroot/index.html +++ b/demo/RulesEngineEditorWebAssembly/wwwroot/index.html @@ -45,6 +45,7 @@ 🗙
+ diff --git a/src/RulesEngineEditor/Components/CultureSwitcher.razor b/src/RulesEngineEditor/Components/CultureSwitcher.razor new file mode 100644 index 00000000..4bcfb103 --- /dev/null +++ b/src/RulesEngineEditor/Components/CultureSwitcher.razor @@ -0,0 +1,18 @@ +@using Microsoft.JSInterop +@inject IJSRuntime JS +@inject NavigationManager Nav +@code { + private string selectedCulture = System.Globalization.CultureInfo.CurrentUICulture.Name; + private async Task OnChange(ChangeEventArgs e) + { + selectedCulture = e.Value?.ToString() ?? "en-US"; + await JS.InvokeVoidAsync("blazorCulture.set", selectedCulture); + await JS.InvokeVoidAsync("setCultureCookie", selectedCulture); + Nav.NavigateTo(Nav.Uri, forceLoad: true); + } +} + \ No newline at end of file diff --git a/src/RulesEngineEditor/Components/InputEditor.razor b/src/RulesEngineEditor/Components/InputEditor.razor index 2fc0ac5f..c5693f12 100644 --- a/src/RulesEngineEditor/Components/InputEditor.razor +++ b/src/RulesEngineEditor/Components/InputEditor.razor @@ -1,34 +1,35 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @using RulesEngineEditor.Models @inject RulesEngineEditor.Services.WorkflowService WorkflowService +@using RulesEngineEditor.Resources @if (Input != null) { -
Input Name
+
@RulesEngineEditor.Resources.SharedResources.InputName
- +
-
-
Parameters
- - +
@RulesEngineEditor.Resources.SharedResources.Parameters
+ + -
Input Param Name
-
Value
+
@RulesEngineEditor.Resources.SharedResources.InputParamName
+
@RulesEngineEditor.Resources.SharedResources.Value
@if (sort) diff --git a/src/RulesEngineEditor/Components/InputParamEditor.razor b/src/RulesEngineEditor/Components/InputParamEditor.razor index a071097a..6c34cc19 100644 --- a/src/RulesEngineEditor/Components/InputParamEditor.razor +++ b/src/RulesEngineEditor/Components/InputParamEditor.razor @@ -1,19 +1,20 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @using RulesEngineEditor.Models @inject RulesEngineEditor.Services.WorkflowService WorkflowService +@using RulesEngineEditor.Resources
- +
- +
- - - - + + + +
@@ -56,19 +57,20 @@
-
-
Local Params
+
@RulesEngineEditor.Resources.SharedResources.LocalParams
- +
-
Rules
+
@RulesEngineEditor.Resources.SharedResources.Rules
- +
@@ -135,7 +137,7 @@ rule.LocalParams = new List(); } rule.LocalParams.Insert(0, new ScopedParamData()); - StateHasChanged(); + InvokeAsync(StateHasChanged); } protected override void OnInitialized() @@ -154,6 +156,18 @@ } WorkflowService.WorkflowUpdate(); } + private string LocalizeMessage(string message) + { + if (string.IsNullOrEmpty(message)) return message; + if (message == "Rule was successful.") return RulesEngineEditor.Resources.SharedResources.RuleWasSuccessful; + if (message == "One or more adjust rules failed.") return RulesEngineEditor.Resources.SharedResources.OneOrMoreAdjustRulesFailed; + var m = message; + m = m.Replace("Validation failed:", RulesEngineEditor.Resources.SharedResources.ValidationFailed); + m = m.Replace("Severity: Error", RulesEngineEditor.Resources.SharedResources.SeverityError); + m = m.Replace("Atleast one of Rules or WorkflowsToInject must be not empty", RulesEngineEditor.Resources.SharedResources.RulesOrWorkflowsToInjectRequired); + m = m.Replace("Expression cannot be null or empty when RuleExpressionType is LambdaExpression", RulesEngineEditor.Resources.SharedResources.ExpressionCannotBeNullWhenLambda); + return m; + } private Task OnValueChanged(string value) { if (value == "null") diff --git a/src/RulesEngineEditor/Components/Rules.razor b/src/RulesEngineEditor/Components/Rules.razor index 90db5287..35224c14 100644 --- a/src/RulesEngineEditor/Components/Rules.razor +++ b/src/RulesEngineEditor/Components/Rules.razor @@ -1,13 +1,14 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @using RulesEngineEditor.Models @inject RulesEngineEditor.Services.WorkflowService WorkflowService +@using RulesEngineEditor.Resources @if (rules != null) { - +   @if (sort) { diff --git a/src/RulesEngineEditor/Components/ScopedParamEditor.razor b/src/RulesEngineEditor/Components/ScopedParamEditor.razor index 21256382..35441c5c 100644 --- a/src/RulesEngineEditor/Components/ScopedParamEditor.razor +++ b/src/RulesEngineEditor/Components/ScopedParamEditor.razor @@ -1,19 +1,20 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @using RulesEngineEditor.Models @inject RulesEngineEditor.Services.WorkflowService WorkflowService +@using RulesEngineEditor.Resources
- +
- +
+   -
Scoped Param Name
-
Expression
+
@RulesEngineEditor.Resources.SharedResources.ScopedParamName
+
@RulesEngineEditor.Resources.SharedResources.ScopedParamExpression
} @if (sort) diff --git a/src/RulesEngineEditor/Components/WorkflowEditor.razor b/src/RulesEngineEditor/Components/WorkflowEditor.razor index a3c92f13..f3b585bd 100644 --- a/src/RulesEngineEditor/Components/WorkflowEditor.razor +++ b/src/RulesEngineEditor/Components/WorkflowEditor.razor @@ -1,19 +1,20 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @using RulesEngineEditor.Models @inject RulesEngineEditor.Services.WorkflowService WorkflowService +@using RulesEngineEditor.Resources
- +
-
diff --git a/src/RulesEngineEditor/Pages/RulesEngineEditorPage.razor b/src/RulesEngineEditor/Pages/RulesEngineEditorPage.razor index 991c4f13..62e2257b 100644 --- a/src/RulesEngineEditor/Pages/RulesEngineEditorPage.razor +++ b/src/RulesEngineEditor/Pages/RulesEngineEditorPage.razor @@ -1,18 +1,19 @@ -@* +@* // Copyright (c) Alex Reich. // Licensed under the CC BY 4.0 License. *@ @using RulesEngineEditor.Models @using RulesEngineEditor.Components +@using RulesEngineEditor.Resources @inject NavigationManager NavigationManager @inject RulesEngineEditor.Services.WorkflowService WorkflowService @implements IDisposable
- +
- +

@@ -34,7 +35,7 @@ } @@ -86,13 +87,13 @@ w.WorkflowName == CurrentWorkflowName).ToList())" Class="reeditor_dragdrop">
-
Rules
- +
@RulesEngineEditor.Resources.SharedResources.Rules
+ -
Global Params
+
@RulesEngineEditor.Resources.SharedResources.GlobalParams
- +
@@ -104,13 +105,13 @@ {
-
Rules
- +
@RulesEngineEditor.Resources.SharedResources.Rules
+ -
Global Params
+
@RulesEngineEditor.Resources.SharedResources.GlobalParams
- +
@@ -125,27 +126,27 @@