mirror of
https://github.com/dotnetcore/BootstrapBlazor.git
synced 2025-12-20 02:16:40 +08:00
!619 feat(#I22PTA): wasm 支持本地化功能
* refactor: 更新 StringLocalizer 类 * refactor: 删除 PathHelper 文件 * refactor: 根据新的资源文件方式重写解析程序 * refactor: 更改资源文件路径为 Locales * doc: 增加资源文件 * refactor: 删除带命名空间的资源文件 * refactor: 更新 Resources 文件夹名称 * release: 发布新版本 3.1.27-beta02 * feat: 增加 ICultureStorage 接口适配 wasm 模式 * refactor: 更改方法名为 GetCultureAsync * refactor: 精简服务 * refactor: 移动 localStorage 存储文化信息代码 * style: 增加语言选择下拉框宽度 * refactor: 更新配置文件仅需配置文化名称即可 * feat: wasm 模式增加本地化支持 * feat: wasm 模式增加文化持久化 * refactor: 移除 useWebAssemblyDebugging 配置项 * feat: 更新本地化服务设置默认使用本机文化信息 * refactor: 更新资源文件打包方式使用卫星文件 * feat: 重构 JsonLocalization 支持 wasm 模式 * refactor: 依赖组件升级到最新版
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
internal static class CultureStorageExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// 添加本地化持久化策略服务
|
||||
/// </summary>
|
||||
/// <param name="services"></param>
|
||||
public static IServiceCollection AddCultureStorage(this IServiceCollection services)
|
||||
{
|
||||
services.AddSingleton<ICultureStorage, DefaultCultureStorage>();
|
||||
return services;
|
||||
}
|
||||
|
||||
internal class DefaultCultureStorage : ICultureStorage
|
||||
{
|
||||
public CultureStorageMode Mode { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
@@ -52,6 +51,7 @@ namespace BootstrapBlazor.Server
|
||||
services.AddControllers();
|
||||
services.AddRazorPages();
|
||||
services.AddServerSideBlazor();
|
||||
services.AddCultureStorage();
|
||||
|
||||
services.AddBlazorBackgroundTask();
|
||||
|
||||
@@ -62,8 +62,8 @@ namespace BootstrapBlazor.Server
|
||||
services.AddJsonLocalization();
|
||||
services.Configure<RequestLocalizationOptions>(options =>
|
||||
{
|
||||
var supportedCultures = Configuration.GetSupportCultures().Select(kv => new CultureInfo(kv.Value)).ToList();
|
||||
options.DefaultRequestCulture = new RequestCulture("zh-CN");
|
||||
var supportedCultures = Configuration.GetSupportCultures().ToList();
|
||||
options.DefaultRequestCulture = new RequestCulture(CultureInfo.CurrentCulture);
|
||||
options.SupportedCultures = supportedCultures;
|
||||
options.SupportedUICultures = supportedCultures;
|
||||
});
|
||||
@@ -77,6 +77,7 @@ namespace BootstrapBlazor.Server
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
// 启用本地化
|
||||
app.UseRequestLocalization(app.ApplicationServices.GetService<IOptions<RequestLocalizationOptions>>().Value);
|
||||
|
||||
app.UseForwardedHeaders(new ForwardedHeadersOptions() { ForwardedHeaders = ForwardedHeaders.All });
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
}
|
||||
},
|
||||
"AllowedHosts": "*",
|
||||
"SupportCultures": {
|
||||
"English": "en-US",
|
||||
"简体中文": "zh-CN"
|
||||
}
|
||||
"SupportCultures": [
|
||||
"en-US",
|
||||
"zh-CN"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Net.Http.Json" Version="3.2.0" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
|
||||
namespace Microsoft.Extensions.Configuration
|
||||
namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
/// <summary>
|
||||
/// Culture 扩展操作类
|
||||
@@ -13,10 +15,48 @@ namespace Microsoft.Extensions.Configuration
|
||||
/// </summary>
|
||||
/// <param name="configuration"></param>
|
||||
/// <returns></returns>
|
||||
public static IEnumerable<KeyValuePair<string, string>> GetSupportCultures(this IConfiguration configuration) => configuration.GetSection("SupportCultures").GetChildren()
|
||||
.SelectMany(c => new KeyValuePair<string, string>[]
|
||||
public static IEnumerable<CultureInfo> GetSupportCultures(this IConfiguration configuration)
|
||||
{
|
||||
var ret = configuration.GetSection("SupportCultures").GetChildren()
|
||||
.Select(c => c.Value);
|
||||
|
||||
if (!ret.Any())
|
||||
{
|
||||
new KeyValuePair<string, string>(c.Key, c.Value)
|
||||
});
|
||||
ret = new List<string>()
|
||||
{
|
||||
"en-US",
|
||||
"zh-CN"
|
||||
};
|
||||
}
|
||||
|
||||
return ret.Select(c => new CultureInfo(c));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ICulture
|
||||
/// </summary>
|
||||
public interface ICultureStorage
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public CultureStorageMode Mode { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
public enum CultureStorageMode
|
||||
{
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
Webapi,
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
LocalStorage
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
@using Microsoft.Extensions.Configuration
|
||||
@using Microsoft.Extensions.DependencyInjection
|
||||
@using Microsoft.Extensions.Configuration
|
||||
@using System.Globalization
|
||||
@inherits BootstrapComponentBase
|
||||
@inject IConfiguration Configuration
|
||||
@inject NavigationManager NavigationManager
|
||||
@inject ICultureStorage CultureStorage
|
||||
|
||||
<div @attributes="@AdditionalAttributes" class="@ClassString">
|
||||
<label>请选择语言:</label>
|
||||
@@ -10,7 +12,7 @@
|
||||
<Options>
|
||||
@foreach (var kv in Configuration.GetSupportCultures())
|
||||
{
|
||||
<SelectOption Text="@kv.Key" Value="@kv.Value" />
|
||||
<SelectOption Text="@kv.NativeName" Value="@kv.Name" />
|
||||
}
|
||||
</Options>
|
||||
</Select>
|
||||
@@ -23,17 +25,33 @@
|
||||
|
||||
private string SelectedCulture { get; set; } = CultureInfo.CurrentUICulture.Name;
|
||||
|
||||
private Task SetCulture(SelectedItem item)
|
||||
private async Task SetCulture(SelectedItem item)
|
||||
{
|
||||
if (SelectedCulture != item.Value)
|
||||
if (CultureStorage.Mode == CultureStorageMode.Webapi)
|
||||
{
|
||||
var culture = item.Value;
|
||||
var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
|
||||
var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";
|
||||
// 使用 api 方式 适用于 Server-Side 模式
|
||||
if (SelectedCulture != item.Value)
|
||||
{
|
||||
var culture = item.Value;
|
||||
var uri = new Uri(NavigationManager.Uri).GetComponents(UriComponents.PathAndQuery, UriFormat.Unescaped);
|
||||
var query = $"?culture={Uri.EscapeDataString(culture)}&redirectUri={Uri.EscapeDataString(uri)}";
|
||||
|
||||
// use a path that matches your culture redirect controller from the previous steps
|
||||
NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
|
||||
// use a path that matches your culture redirect controller from the previous steps
|
||||
NavigationManager.NavigateTo("/Culture/SetCulture" + query, forceLoad: true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var cultureName = item.Value;
|
||||
if (cultureName != CultureInfo.CurrentCulture.Name)
|
||||
{
|
||||
await JSRuntime.InvokeAsync<string>("$.blazorCulture.set", cultureName);
|
||||
var culture = new CultureInfo(cultureName);
|
||||
CultureInfo.CurrentCulture = culture;
|
||||
CultureInfo.CurrentUICulture = culture;
|
||||
|
||||
NavigationManager.NavigateTo(NavigationManager.Uri, forceLoad: true);
|
||||
}
|
||||
}
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
@@ -1141,5 +1141,5 @@ section {
|
||||
}
|
||||
|
||||
.culture-selector .form-select {
|
||||
width: 120px;
|
||||
width: 210px;
|
||||
}
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.0" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.0" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="3.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="3.2.1" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Build" Version="3.2.1" PrivateAssets="all" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="3.2.1" PrivateAssets="all" />
|
||||
<PackageReference Include="System.Net.Http.Json" Version="3.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
using BootstrapBlazor.Shared.Data;
|
||||
using Microsoft.AspNetCore.Components.WebAssembly.Hosting;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.JSInterop;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@@ -37,7 +39,28 @@ namespace BootstrapBlazor.WebAssembly.ClientHost
|
||||
|
||||
builder.Services.AddSingleton<WeatherForecastService>();
|
||||
|
||||
await builder.Build().RunAsync();
|
||||
builder.Services.AddSingleton<ICultureStorage, DefaultCultureStorage>();
|
||||
|
||||
var host = builder.Build();
|
||||
|
||||
await GetCultureAsync(host);
|
||||
|
||||
await host.RunAsync();
|
||||
}
|
||||
|
||||
// based on https://github.com/pranavkm/LocSample
|
||||
private static async Task GetCultureAsync(WebAssemblyHost host)
|
||||
{
|
||||
var jsRuntime = host.Services.GetRequiredService<IJSRuntime>();
|
||||
var cultureName = await jsRuntime.InvokeAsync<string>("$.blazorCulture.get") ?? "zh-CN";
|
||||
var culture = new CultureInfo(cultureName);
|
||||
CultureInfo.DefaultThreadCurrentCulture = culture;
|
||||
CultureInfo.DefaultThreadCurrentUICulture = culture;
|
||||
}
|
||||
|
||||
internal class DefaultCultureStorage : ICultureStorage
|
||||
{
|
||||
public CultureStorageMode Mode { get; set; } = CultureStorageMode.LocalStorage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
{
|
||||
"useWebAssemblyDebugging": true,
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="3.2.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -34,7 +34,6 @@ namespace BootstrapBlazor.WebAssembly.ServerHost
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddBootstrapBlazor();
|
||||
services.AddRazorPages();
|
||||
}
|
||||
|
||||
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
|
||||
@@ -62,7 +61,6 @@ namespace BootstrapBlazor.WebAssembly.ServerHost
|
||||
|
||||
app.UseEndpoints(endpoints =>
|
||||
{
|
||||
endpoints.MapRazorPages();
|
||||
endpoints.MapFallbackToFile("index.html");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -6,10 +6,15 @@
|
||||
<RazorLangVersion>3.0</RazorLangVersion>
|
||||
<IsPackable>true</IsPackable>
|
||||
<PackageIcon>logo.png</PackageIcon>
|
||||
<Version>3.1.27-beta01</Version>
|
||||
<Version>3.1.27-beta02</Version>
|
||||
<PackageReleaseNotes>更新日志:https://gitee.com/LongbowEnterprise/BootstrapBlazor/wikis</PackageReleaseNotes>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Content Remove="Locales\*.json" />
|
||||
<EmbeddedResource Include="Locales\*.json" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="EPPlus" Version="4.5.3.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="3.1.9" />
|
||||
|
||||
192
src/BootstrapBlazor/Locales/en-US.json
Normal file
192
src/BootstrapBlazor/Locales/en-US.json
Normal file
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"Components.AutoComplete": {
|
||||
"NoDataTip": "No Data",
|
||||
"PlaceHolder": "Please Input"
|
||||
},
|
||||
"Components.Captcha": {
|
||||
"HeaderText": "Captcha",
|
||||
"BarText": "Slide right to fill puzzle",
|
||||
"FailedText": "Load failed",
|
||||
"LoadText": "Loading ...",
|
||||
"TryText": "Try again"
|
||||
},
|
||||
"Components.Console": {
|
||||
"HeaderText": "Monitor",
|
||||
"LightTitle": "Light",
|
||||
"ClearButtonText": "Clear",
|
||||
"AutoScrollText": "AutoScroll"
|
||||
},
|
||||
"Components.DateTimePicker": {
|
||||
"DatePlaceHolder": "Date",
|
||||
"TimePlaceHolder": "Time",
|
||||
"DateTimePlaceHolderText": "Please select ...",
|
||||
"DatePlaceHolderText": "Please select ...",
|
||||
"TimeFormat": "hh\\:mm\\:ss",
|
||||
"DateFormat": "M/d/yyyy",
|
||||
"DateTimeFormat": "M/d/yyyy hh\\:mm\\:ss",
|
||||
"AiraPrevYearLabel": "Prev Year",
|
||||
"AiraNextYearLabel": "Next Year",
|
||||
"AiraPrevMonthLabel": "Prev Month",
|
||||
"AiraNextMonthLabel": "Next Month",
|
||||
"ClearButtonText": "Clear",
|
||||
"NowButtonText": "Now",
|
||||
"ConfirmButtonText": "Ok",
|
||||
"CancelButtonText": "Cancel",
|
||||
"YearText": "{0}",
|
||||
"MonthText": "{0}",
|
||||
"YearPeriodText": "{0} - {1}",
|
||||
"Months": "January,February,March,April,May,June,July,August,September,October,November,December",
|
||||
"MonthLists": "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
|
||||
"WeekLists": "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
|
||||
"GenericTypeErroMessage": "DateTimePicker only support DateTime or Nullable<DateTime>"
|
||||
},
|
||||
"Components.DropdownList": {
|
||||
"PlaceHolder": "Please select ..."
|
||||
},
|
||||
"Components.Editor": {
|
||||
"PlaceHolder": "Click to edit"
|
||||
},
|
||||
"Components.EditorForm": {
|
||||
"ModelInvalidOperationExceptionMessage": "ValidateForm MODEL not match {0} MODEL",
|
||||
"PlaceHolderText": "Please input ..."
|
||||
},
|
||||
"Components.EqualToValidator": {
|
||||
"ErrorMessage": "Please enter the same value again"
|
||||
},
|
||||
"Components.GoTop": {
|
||||
"TooltipText": "Go top"
|
||||
},
|
||||
"Components.Layout": {
|
||||
"TooltipText": "Click to Expand/Collapse sidebar"
|
||||
},
|
||||
"Components.MultiSelect": {
|
||||
"PlaceHolder": "Click for select ...",
|
||||
"SelectAllText": "All",
|
||||
"ReverseSelectText": "Reverse",
|
||||
"ClearText": "Clear"
|
||||
},
|
||||
"Components.Pagination": {
|
||||
"AiraPageLabel": "Pagination",
|
||||
"AiraPrevPageText": "Prev",
|
||||
"AiraFirstPageText": "First",
|
||||
"AiraNextPageText": "Next",
|
||||
"PageInfoText": "{0}-{1}",
|
||||
"TotalInfoText": ", Total {0}",
|
||||
"PrePageInfoText": "",
|
||||
"RowInfoText": "",
|
||||
"LabelString": "page {0}",
|
||||
"SelectItemsText": "{0} /page"
|
||||
},
|
||||
"Components.PopConfirmButton": {
|
||||
"CloseButtonText": "Cancel",
|
||||
"ConfirmButtonText": "Ok",
|
||||
"Content": "Are you sure DELETE?"
|
||||
},
|
||||
"Components.QRCode": {
|
||||
"PlaceHolder": "Please input ...",
|
||||
"ClearButtonText": "Clear",
|
||||
"GenerateButtonText": "Generate"
|
||||
},
|
||||
"Components.RequiredValidator": {
|
||||
"ErrorMessage": "This field is required"
|
||||
},
|
||||
"Components.Search": {
|
||||
"SearchButtonText": "Search"
|
||||
},
|
||||
"Components.Select": {
|
||||
"PlaceHolder": "Click for select ..."
|
||||
},
|
||||
"Components.StringLengthValidator": {
|
||||
"ErrorMessage": "Please enter a value less than or equal to {{0}}"
|
||||
},
|
||||
"Components.SweetAlert": {
|
||||
"CloseButtonText": "Close",
|
||||
"CancelButtonText": "Cancel",
|
||||
"ConfirmButtonText": "Confirm"
|
||||
},
|
||||
"Components.Switch": {
|
||||
"OnInnerText": "On",
|
||||
"OffInnerText": "Off"
|
||||
},
|
||||
"Components.Table": {
|
||||
"AddButtonText": "Add",
|
||||
"EditButtonText": "Edit",
|
||||
"DeleteButtonText": "Delete",
|
||||
"CancelDeleteButtonText": "Cancel",
|
||||
"ConfirmDeleteButtonText": "Delete",
|
||||
"ConfirmDeleteContentText": "Are you sure to DELETE all selected rows?",
|
||||
"RefreshButtonText": "Refresh",
|
||||
"ColumnButtonTitleText": "Show/Hide Columns",
|
||||
"ColumnButtonText": "Columns",
|
||||
"ExportButtonText": "Export",
|
||||
"SearchPlaceholderText": "Search",
|
||||
"SearchButtonText": "Search",
|
||||
"ResetButtonText": "Reset",
|
||||
"AdvanceButtonText": "Advance Search",
|
||||
"CheckboxDisplayText": "All",
|
||||
"EditModalTitle": "Edit Data",
|
||||
"AddModalTitle": "New Data",
|
||||
"ColumnButtonTemplateHeaderText": "",
|
||||
"SearchTooltip": "<div class='search-input-tooltip'>Please input ...</br><kbd>Enter</kbd> Search <kbd>ESC</kbd> Clear</div>",
|
||||
"SearchModalTitle": "Searching",
|
||||
"AddButtonToastTitle": "Add Data",
|
||||
"AddButtonToastContent": "Save data failed. Please provider SAVE method",
|
||||
"EditButtonToastTitle": "Add Data",
|
||||
"EditButtonToastNotSelectContent": "Save data failed. Please provider SAVE method",
|
||||
"EditButtonToastMoreSelectContent": "Only one row can be EDIT",
|
||||
"EditButtonToastNoSaveMethodContent": "Can not EDIT data. Please provider SAVE method",
|
||||
"SaveButtonToastTitle": "Save Data",
|
||||
"SaveButtonToastContent": "Save data failed. Please provider SAVE method",
|
||||
"SaveButtonToastResultContent": "Save data {0}, auto close after {1}s",
|
||||
"SuccessText": "Successful",
|
||||
"FailText": "Failed",
|
||||
"DeleteButtonToastTitle": "Delete Data",
|
||||
"DeleteButtonToastContent": "Please select DELETE rows, auto claose after {1}s",
|
||||
"DeleteButtonToastResultContent": "Delete data {0}, auto claose after {1}s"
|
||||
},
|
||||
"Components.TableEditorDialog": {
|
||||
"CloseButtonText": "Close",
|
||||
"SaveButtonText": "Save"
|
||||
},
|
||||
"Components.TableFilter": {
|
||||
"Title": "Filter",
|
||||
"ClearButtonText": "Clear",
|
||||
"FilterButtonText": "Filter",
|
||||
"BoolFilter.AllText": "All",
|
||||
"BoolFilter.TrueText": "True",
|
||||
"BoolFilter.FalseText": "False",
|
||||
"GreaterThanOrEqual": "GreaterThanOrEqual",
|
||||
"LessThanOrEqual": "LessThanOrEqual",
|
||||
"GreaterThan": "GreaterThan",
|
||||
"LessThan": "LessThan",
|
||||
"Equal": "Equal",
|
||||
"NotEqual": "NotEqual",
|
||||
"Contains": "Contains",
|
||||
"NotContains": "NotContains",
|
||||
"EnumFilter.AllText": "All"
|
||||
},
|
||||
"Components.TableSearchDialog": {
|
||||
"ResetButtonText": "Reset",
|
||||
"QueryButtonText": "Query"
|
||||
},
|
||||
"Components.Timer": {
|
||||
"PauseText": "Pause",
|
||||
"ResumeText": "Resume",
|
||||
"CancelText": "Cancel",
|
||||
"StarText": "Star"
|
||||
},
|
||||
"Components.Toggle": {
|
||||
"OnText": "Expand",
|
||||
"OffText": "Collapse"
|
||||
},
|
||||
"Components.Transfer": {
|
||||
"LeftPanelText": "List 1",
|
||||
"RightPanelText": "List 2"
|
||||
},
|
||||
"Components.Upload": {
|
||||
"Text": "Upload",
|
||||
"ResetText": "Reset",
|
||||
"AllowFileTypeErrorMessage": "Only allow Images type file",
|
||||
"FileTooLargeText": "File to large"
|
||||
}
|
||||
}
|
||||
192
src/BootstrapBlazor/Locales/zh-CN.json
Normal file
192
src/BootstrapBlazor/Locales/zh-CN.json
Normal file
@@ -0,0 +1,192 @@
|
||||
{
|
||||
"Components.AutoComplete": {
|
||||
"NoDataTip": "无匹配数据",
|
||||
"PlaceHolder": "请输入"
|
||||
},
|
||||
"Components.Captcha": {
|
||||
"HeaderText": "请完成安全验证",
|
||||
"BarText": "向右滑动填充拼图",
|
||||
"FailedText": "加载失败",
|
||||
"LoadText": "正在加载 ...",
|
||||
"TryText": "再试一次"
|
||||
},
|
||||
"Components.Console": {
|
||||
"HeaderText": "系统监控",
|
||||
"LightTitle": "通讯指示灯",
|
||||
"ClearButtonText": "清屏",
|
||||
"AutoScrollText": "自动滚屏"
|
||||
},
|
||||
"Components.DateTimePicker": {
|
||||
"DatePlaceHolder": "选择日期",
|
||||
"TimePlaceHolder": "选择时间",
|
||||
"DateTimePlaceHolderText": "请选择日期时间",
|
||||
"DatePlaceHolderText": "请选择日期",
|
||||
"TimeFormat": "hh\\:mm\\:ss",
|
||||
"DateFormat": "yyyy-MM-dd",
|
||||
"DateTimeFormat": "yyyy-MM-dd hh\\:mm\\:ss",
|
||||
"AiraPrevYearLabel": "前一年",
|
||||
"AiraNextYearLabel": "后一年",
|
||||
"AiraPrevMonthLabel": "上一月",
|
||||
"AiraNextMonthLabel": "下一月",
|
||||
"ClearButtonText": "清空",
|
||||
"NowButtonText": "此刻",
|
||||
"ConfirmButtonText": "确定",
|
||||
"CancelButtonText": "取消",
|
||||
"YearText": "{0} 年",
|
||||
"MonthText": "{0} 月",
|
||||
"YearPeriodText": "{0} 年 - {1} 年",
|
||||
"Months": "1,2,3,4,5,6,7,8,9,10,11,12",
|
||||
"MonthLists": "一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月",
|
||||
"WeekLists": "日,一,二,三,四,五,六",
|
||||
"GenericTypeErroMessage": "DateTimePicker 组件仅支持绑定泛型为 DateTime 或者 DateTime?"
|
||||
},
|
||||
"Components.DropdownList": {
|
||||
"PlaceHolder": "请选择 ..."
|
||||
},
|
||||
"Components.Editor": {
|
||||
"PlaceHolder": "点击后编辑"
|
||||
},
|
||||
"Components.EditorForm": {
|
||||
"ModelInvalidOperationExceptionMessage": "验证表单与 {0} 绑定模型不一致",
|
||||
"PlaceHolderText": "请输入 ..."
|
||||
},
|
||||
"Components.EqualToValidator": {
|
||||
"ErrorMessage": "你的输入不相同"
|
||||
},
|
||||
"Components.GoTop": {
|
||||
"TooltipText": "返回顶端"
|
||||
},
|
||||
"Components.Layout": {
|
||||
"TooltipText": "点击展开收缩左侧菜单"
|
||||
},
|
||||
"Components.MultiSelect": {
|
||||
"PlaceHolder": "点击进行多选 ...",
|
||||
"SelectAllText": "全选",
|
||||
"ReverseSelectText": "反选",
|
||||
"ClearText": "清除"
|
||||
},
|
||||
"Components.Pagination": {
|
||||
"AiraPageLabel": "分页组件",
|
||||
"AiraPrevPageText": "上一页",
|
||||
"AiraFirstPageText": "第一页",
|
||||
"AiraNextPageText": "下一页",
|
||||
"PageInfoText": "显示第 {0} 到第 {1} 条记录",
|
||||
"TotalInfoText": ",总共 {0} 条记录",
|
||||
"PrePageInfoText": "每页显示",
|
||||
"RowInfoText": "条记录",
|
||||
"LabelString": "第 {0} 页",
|
||||
"SelectItemsText": "{0} 条/页"
|
||||
},
|
||||
"Components.PopConfirmButton": {
|
||||
"CloseButtonText": "关闭",
|
||||
"ConfirmButtonText": "确定",
|
||||
"Content": "确认删除吗?"
|
||||
},
|
||||
"Components.QRCode": {
|
||||
"PlaceHolder": "请输入内容",
|
||||
"ClearButtonText": "清除",
|
||||
"GenerateButtonText": "生成"
|
||||
},
|
||||
"Components.RequiredValidator": {
|
||||
"ErrorMessage": "这是必填字段"
|
||||
},
|
||||
"Components.Search": {
|
||||
"SearchButtonText": "搜索"
|
||||
},
|
||||
"Components.Select": {
|
||||
"PlaceHolder": "请选择 ..."
|
||||
},
|
||||
"Components.StringLengthValidator": {
|
||||
"ErrorMessage": "最多可以输入 {{0}} 个字符"
|
||||
},
|
||||
"Components.SweetAlert": {
|
||||
"CloseButtonText": "关闭",
|
||||
"CancelButtonText": "取消",
|
||||
"ConfirmButtonText": "确认"
|
||||
},
|
||||
"Components.Switch": {
|
||||
"OnInnerText": "开",
|
||||
"OffInnerText": "关"
|
||||
},
|
||||
"Components.Table": {
|
||||
"AddButtonText": "新建",
|
||||
"EditButtonText": "编辑",
|
||||
"DeleteButtonText": "删除",
|
||||
"CancelDeleteButtonText": "取消",
|
||||
"ConfirmDeleteButtonText": "删除",
|
||||
"ConfirmDeleteContentText": "确认要删除选中的所有行吗?",
|
||||
"RefreshButtonText": "刷新",
|
||||
"ColumnButtonTitleText": "列显示隐藏控制",
|
||||
"ColumnButtonText": "列",
|
||||
"ExportButtonText": "导出数据",
|
||||
"SearchPlaceholderText": "搜索",
|
||||
"SearchButtonText": "搜索",
|
||||
"ResetButtonText": "清空过滤",
|
||||
"AdvanceButtonText": "高级搜索",
|
||||
"CheckboxDisplayText": "选择",
|
||||
"EditModalTitle": "编辑数据窗口",
|
||||
"AddModalTitle": "新建数据窗口",
|
||||
"ColumnButtonTemplateHeaderText": "操作",
|
||||
"SearchTooltip": "<div class='search-input-tooltip'>输入任意字符串全局搜索</br><kbd>Enter</kbd> 搜索 <kbd>ESC</kbd> 清除搜索</div>",
|
||||
"SearchModalTitle": "搜索条件",
|
||||
"AddButtonToastTitle": "新建数据",
|
||||
"AddButtonToastContent": "未提供保存数据方法,无法新建数据",
|
||||
"EditButtonToastTitle": "编辑数据",
|
||||
"EditButtonToastNotSelectContent": "请选择要编辑的数据",
|
||||
"EditButtonToastMoreSelectContent": "只能选择一项要编辑的数据",
|
||||
"EditButtonToastNoSaveMethodContent": "未提供保存数据方法,无法编辑数据",
|
||||
"SaveButtonToastTitle": "保存数据",
|
||||
"SaveButtonToastContent": "未提供保存数据方法,无法保存数据",
|
||||
"SaveButtonToastResultContent": "保存数据{0}, {1} 秒后自动关闭",
|
||||
"SuccessText": "成功",
|
||||
"FailText": "失败",
|
||||
"DeleteButtonToastTitle": "删除数据",
|
||||
"DeleteButtonToastContent": "请选择要删除的数据, {0} 秒后自动关闭",
|
||||
"DeleteButtonToastResultContent": "删除数据{0}, {1} 秒后自动关闭"
|
||||
},
|
||||
"Components.TableEditorDialog": {
|
||||
"CloseButtonText": "关闭",
|
||||
"SaveButtonText": "保存"
|
||||
},
|
||||
"Components.TableFilter": {
|
||||
"Title": "过滤",
|
||||
"ClearButtonText": "重置",
|
||||
"FilterButtonText": "确认",
|
||||
"BoolFilter.AllText": "全部",
|
||||
"BoolFilter.TrueText": "选中",
|
||||
"BoolFilter.FalseText": "未选中",
|
||||
"GreaterThanOrEqual": "大于等于",
|
||||
"LessThanOrEqual": "小于等于",
|
||||
"GreaterThan": "大于",
|
||||
"LessThan": "小于",
|
||||
"Equal": "等于",
|
||||
"NotEqual": "不等于",
|
||||
"Contains": "包含",
|
||||
"NotContains": "不包含",
|
||||
"EnumFilter.AllText": "全选"
|
||||
},
|
||||
"Components.TableSearchDialog": {
|
||||
"ResetButtonText": "重置",
|
||||
"QueryButtonText": "查询"
|
||||
},
|
||||
"Components.Timer": {
|
||||
"PauseText": "暂停",
|
||||
"ResumeText": "继续",
|
||||
"CancelText": "取消",
|
||||
"StarText": "开始计时"
|
||||
},
|
||||
"Components.Toggle": {
|
||||
"OnText": "展开",
|
||||
"OffText": "收缩"
|
||||
},
|
||||
"Components.Transfer": {
|
||||
"LeftPanelText": "列表 1",
|
||||
"RightPanelText": "列表 2"
|
||||
},
|
||||
"Components.Upload": {
|
||||
"Text": "点击上传",
|
||||
"ResetText": "重置",
|
||||
"AllowFileTypeErrorMessage": "只允许选择图片类型文件",
|
||||
"FileTooLargeText": "文件太大"
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BootstrapBlazor.Localization.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// 路径操作类
|
||||
/// </summary>
|
||||
internal static class PathHelpers
|
||||
{
|
||||
/// <summary>
|
||||
/// 获取当前应用程序所在路径
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetApplicationRoot()
|
||||
=> Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@ namespace BootstrapBlazor.Localization.Json
|
||||
|
||||
public StringLocalizer(IStringLocalizerFactory factory)
|
||||
{
|
||||
_localizer = factory.Create(string.Empty, PathHelpers.GetApplicationRoot());
|
||||
_localizer = factory.Create(string.Empty, string.Empty);
|
||||
}
|
||||
|
||||
public LocalizedString this[string name] => _localizer[name];
|
||||
|
||||
@@ -12,12 +12,7 @@ namespace BootstrapBlazor.Localization.Json
|
||||
/// </summary>
|
||||
public JsonLocalizationOptions()
|
||||
{
|
||||
ResourcesPath = "Resources";
|
||||
ResourcesPath = "Locales";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获得/设置 资源定位方式 默认为 TypeBased 基于类型定位 TypeFullName.CultureName.json 格式
|
||||
/// </summary>
|
||||
public ResourcesType ResourcesType { get; set; } = ResourcesType.TypeBased;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace Microsoft.Extensions.DependencyInjection
|
||||
{
|
||||
//services.AddSingleton<IHtmlLocalizerFactory, JsonHtmlLocalizerFactory>();
|
||||
services.TryAddSingleton<IStringLocalizerFactory, JsonStringLocalizerFactory>();
|
||||
services.TryAddTransient(typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
|
||||
services.TryAddTransient(typeof(IStringLocalizer), typeof(StringLocalizer));
|
||||
services.TryAddScoped(typeof(IStringLocalizer<>), typeof(StringLocalizer<>));
|
||||
services.TryAddScoped(typeof(IStringLocalizer), typeof(StringLocalizer));
|
||||
|
||||
if (setupAction != null) services.Configure(setupAction);
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BootstrapBlazor.Localization.Json
|
||||
{
|
||||
@@ -17,8 +17,9 @@ namespace BootstrapBlazor.Localization.Json
|
||||
{
|
||||
private readonly ConcurrentDictionary<string, IEnumerable<KeyValuePair<string, string>>> _resourcesCache = new ConcurrentDictionary<string, IEnumerable<KeyValuePair<string, string>>>();
|
||||
|
||||
private readonly string _resourcesPath;
|
||||
private readonly Assembly _assembly;
|
||||
private readonly string? _resourceName;
|
||||
private readonly string _typeName;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private string _searchedLocation = "";
|
||||
@@ -26,12 +27,14 @@ namespace BootstrapBlazor.Localization.Json
|
||||
/// <summary>
|
||||
/// 构造函数
|
||||
/// </summary>
|
||||
/// <param name="resourcesPath"></param>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="resourceName"></param>
|
||||
/// <param name="typeName"></param>
|
||||
/// <param name="logger"></param>
|
||||
public JsonStringLocalizer(string resourcesPath, string? resourceName, ILogger logger)
|
||||
public JsonStringLocalizer(Assembly assembly, string? resourceName, string typeName, ILogger logger)
|
||||
{
|
||||
_resourcesPath = resourcesPath;
|
||||
_assembly = assembly;
|
||||
_typeName = typeName;
|
||||
_resourceName = resourceName;
|
||||
_logger = logger;
|
||||
}
|
||||
@@ -115,7 +118,7 @@ namespace BootstrapBlazor.Localization.Json
|
||||
|
||||
while (culture != culture.Parent)
|
||||
{
|
||||
BuildResourcesCache(culture.Name);
|
||||
BuildResourcesCache(culture);
|
||||
|
||||
if (_resourcesCache.TryGetValue(culture.Name, out var resources))
|
||||
{
|
||||
@@ -158,7 +161,7 @@ namespace BootstrapBlazor.Localization.Json
|
||||
|
||||
private IEnumerable<string> GetAllResourceStrings(CultureInfo culture)
|
||||
{
|
||||
BuildResourcesCache(culture.Name);
|
||||
BuildResourcesCache(culture);
|
||||
|
||||
var ret = Enumerable.Empty<string>();
|
||||
if (_resourcesCache.TryGetValue(culture.Name, out var resources))
|
||||
@@ -168,39 +171,23 @@ namespace BootstrapBlazor.Localization.Json
|
||||
return ret;
|
||||
}
|
||||
|
||||
private void BuildResourcesCache(string culture)
|
||||
private void BuildResourcesCache(CultureInfo culture)
|
||||
{
|
||||
_resourcesCache.GetOrAdd(culture, _ =>
|
||||
_resourcesCache.GetOrAdd(culture.Name, key =>
|
||||
{
|
||||
var resourceFile = string.IsNullOrEmpty(_resourceName)
|
||||
? $"{culture}.json"
|
||||
: $"{_resourceName}.{culture}.json";
|
||||
|
||||
_searchedLocation = Path.Combine(_resourcesPath, resourceFile);
|
||||
|
||||
if (!File.Exists(_searchedLocation))
|
||||
{
|
||||
if (resourceFile.Any(r => r == '.'))
|
||||
{
|
||||
var resourceFileWithoutExtension = Path.GetFileNameWithoutExtension(resourceFile);
|
||||
var resourceFileWithoutCulture = resourceFileWithoutExtension.Substring(0, resourceFileWithoutExtension.LastIndexOf('.'));
|
||||
resourceFile = $"{resourceFileWithoutCulture.Replace('.', Path.DirectorySeparatorChar)}.{culture}.json";
|
||||
_searchedLocation = Path.Combine(_resourcesPath, resourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
var value = Enumerable.Empty<KeyValuePair<string, string>>();
|
||||
|
||||
if (File.Exists(_searchedLocation))
|
||||
_searchedLocation = $"{_resourceName}.{key}.json";
|
||||
|
||||
using var res = _assembly.GetManifestResourceStream(_searchedLocation);
|
||||
|
||||
if (res != null)
|
||||
{
|
||||
var builder = new ConfigurationBuilder()
|
||||
.SetBasePath(_resourcesPath)
|
||||
.AddJsonFile(resourceFile, optional: false, reloadOnChange: false);
|
||||
|
||||
var config = builder.Build();
|
||||
value = config.AsEnumerable();
|
||||
var config = new ConfigurationBuilder()
|
||||
.AddJsonStream(res)
|
||||
.Build();
|
||||
value = config.GetSection(_typeName).GetChildren().SelectMany(c => new KeyValuePair<string, string>[] { new KeyValuePair<string, string>(c.Key, c.Value) });
|
||||
}
|
||||
|
||||
return value;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
|
||||
namespace BootstrapBlazor.Localization.Json
|
||||
@@ -13,7 +12,6 @@ namespace BootstrapBlazor.Localization.Json
|
||||
internal class JsonStringLocalizerFactory : IStringLocalizerFactory
|
||||
{
|
||||
private readonly string _resourcesRelativePath;
|
||||
private readonly ResourcesType _resourcesType = ResourcesType.TypeBased;
|
||||
private readonly ILoggerFactory _loggerFactory;
|
||||
|
||||
/// <summary>
|
||||
@@ -24,7 +22,6 @@ namespace BootstrapBlazor.Localization.Json
|
||||
public JsonStringLocalizerFactory(IOptions<JsonLocalizationOptions> localizationOptions, ILoggerFactory loggerFactory)
|
||||
{
|
||||
_resourcesRelativePath = localizationOptions.Value.ResourcesPath;
|
||||
_resourcesType = localizationOptions.Value.ResourcesType;
|
||||
_loggerFactory = loggerFactory;
|
||||
}
|
||||
|
||||
@@ -35,15 +32,8 @@ namespace BootstrapBlazor.Localization.Json
|
||||
/// <returns></returns>
|
||||
public IStringLocalizer Create(Type resourceSource)
|
||||
{
|
||||
if (resourceSource.Name == "Controller")
|
||||
{
|
||||
return CreateJsonStringLocalizer(Path.Combine(PathHelpers.GetApplicationRoot(), GetResourcePath(resourceSource.Assembly)), TryFixInnerClassPath("Controller"));
|
||||
}
|
||||
|
||||
var typeInfo = resourceSource.GetTypeInfo();
|
||||
var assembly = typeInfo.Assembly;
|
||||
var assemblyName = resourceSource.Assembly.GetName().Name;
|
||||
var resourcesPath = Path.Combine(PathHelpers.GetApplicationRoot(), GetResourcePath(assembly));
|
||||
var typeName = $"{assemblyName}.{typeInfo.Name}" == typeInfo.FullName
|
||||
? typeInfo.Name
|
||||
: typeInfo.FullName.Substring(assemblyName.Length + 1);
|
||||
@@ -56,7 +46,7 @@ namespace BootstrapBlazor.Localization.Json
|
||||
|
||||
typeName = TryFixInnerClassPath(typeName);
|
||||
|
||||
return CreateJsonStringLocalizer(resourcesPath, typeName);
|
||||
return CreateJsonStringLocalizer(typeInfo.Assembly, typeName, $"{assemblyName}.{_resourcesRelativePath}");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -71,50 +61,23 @@ namespace BootstrapBlazor.Localization.Json
|
||||
|
||||
var assemblyName = new AssemblyName(location);
|
||||
var assembly = Assembly.Load(assemblyName);
|
||||
var resourcesPath = Path.Combine(PathHelpers.GetApplicationRoot(), GetResourcePath(assembly));
|
||||
string? resourceName = null;
|
||||
|
||||
if (_resourcesType == ResourcesType.TypeBased)
|
||||
{
|
||||
resourceName = TrimPrefix(baseName, location + ".");
|
||||
}
|
||||
|
||||
return CreateJsonStringLocalizer(resourcesPath, resourceName);
|
||||
return CreateJsonStringLocalizer(assembly, string.Empty, resourceName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 创建 IStringLocalizer 实例方法
|
||||
/// </summary>
|
||||
/// <param name="resourcesPath"></param>
|
||||
/// <param name="resourcename"></param>
|
||||
/// <param name="assembly"></param>
|
||||
/// <param name="typeName"></param>
|
||||
/// <param name="resourceName"></param>
|
||||
/// <returns></returns>
|
||||
protected virtual IStringLocalizer CreateJsonStringLocalizer(string resourcesPath, string? resourcename)
|
||||
protected virtual IStringLocalizer CreateJsonStringLocalizer(Assembly assembly, string typeName, string? resourceName)
|
||||
{
|
||||
var logger = _loggerFactory.CreateLogger<JsonStringLocalizer>();
|
||||
|
||||
return new JsonStringLocalizer(
|
||||
resourcesPath,
|
||||
_resourcesType == ResourcesType.TypeBased ? resourcename : null,
|
||||
logger);
|
||||
}
|
||||
|
||||
private string GetResourcePath(Assembly assembly)
|
||||
{
|
||||
var resourceLocationAttribute = assembly.GetCustomAttribute<ResourceLocationAttribute>();
|
||||
|
||||
return resourceLocationAttribute == null
|
||||
? _resourcesRelativePath
|
||||
: resourceLocationAttribute.ResourceLocation;
|
||||
}
|
||||
|
||||
private static string TrimPrefix(string name, string prefix)
|
||||
{
|
||||
if (name.StartsWith(prefix, StringComparison.Ordinal))
|
||||
{
|
||||
return name.Substring(prefix.Length);
|
||||
}
|
||||
|
||||
return name;
|
||||
return new JsonStringLocalizer(assembly, resourceName, typeName, logger);
|
||||
}
|
||||
|
||||
private string TryFixInnerClassPath(string path)
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
namespace BootstrapBlazor.Localization.Json
|
||||
{
|
||||
/// <summary>
|
||||
/// 资源类型枚举
|
||||
/// </summary>
|
||||
public enum ResourcesType
|
||||
{
|
||||
/// <summary>
|
||||
/// 基于语言文化
|
||||
/// </summary>
|
||||
CultureBased,
|
||||
|
||||
/// <summary>
|
||||
/// 基于类型
|
||||
/// </summary>
|
||||
TypeBased
|
||||
}
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"NoDataTip": "No Data",
|
||||
"PlaceHolder": "Please Input"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"NoDataTip": "无匹配数据",
|
||||
"PlaceHolder": "请输入"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"HeaderText": "Captcha",
|
||||
"BarText": "Slide right to fill puzzle",
|
||||
"FailedText": "Load failed",
|
||||
"LoadText": "Loading ...",
|
||||
"TryText": "Try again"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"HeaderText": "请完成安全验证",
|
||||
"BarText": "向右滑动填充拼图",
|
||||
"FailedText": "加载失败",
|
||||
"LoadText": "正在加载 ...",
|
||||
"TryText": "再试一次"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"HeaderText": "Monitor",
|
||||
"LightTitle": "Light",
|
||||
"ClearButtonText": "Clear",
|
||||
"AutoScrollText": "AutoScroll"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"HeaderText": "系统监控",
|
||||
"LightTitle": "通讯指示灯",
|
||||
"ClearButtonText": "清屏",
|
||||
"AutoScrollText": "自动滚屏"
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"DatePlaceHolder": "Date",
|
||||
"TimePlaceHolder": "Time",
|
||||
"DateTimePlaceHolderText": "Please select ...",
|
||||
"DatePlaceHolderText": "Please select ...",
|
||||
"TimeFormat": "hh\\:mm\\:ss",
|
||||
"DateFormat": "M/d/yyyy",
|
||||
"DateTimeFormat": "M/d/yyyy hh\\:mm\\:ss",
|
||||
"AiraPrevYearLabel": "Prev Year",
|
||||
"AiraNextYearLabel": "Next Year",
|
||||
"AiraPrevMonthLabel": "Prev Month",
|
||||
"AiraNextMonthLabel": "Next Month",
|
||||
"ClearButtonText": "Clear",
|
||||
"NowButtonText": "Now",
|
||||
"ConfirmButtonText": "Ok",
|
||||
"CancelButtonText": "Cancel",
|
||||
"YearText": "{0}",
|
||||
"MonthText": "{0}",
|
||||
"YearPeriodText": "{0} - {1}",
|
||||
"Months": "January,February,March,April,May,June,July,August,September,October,November,December",
|
||||
"MonthLists": "Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec",
|
||||
"WeekLists": "Sun,Mon,Tue,Wed,Thu,Fri,Sat",
|
||||
"GenericTypeErroMessage": "DateTimePicker only support DateTime or Nullable<DateTime>"
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
{
|
||||
"DatePlaceHolder": "选择日期",
|
||||
"TimePlaceHolder": "选择时间",
|
||||
"DateTimePlaceHolderText": "请选择日期时间",
|
||||
"DatePlaceHolderText": "请选择日期",
|
||||
"TimeFormat": "hh\\:mm\\:ss",
|
||||
"DateFormat": "yyyy-MM-dd",
|
||||
"DateTimeFormat": "yyyy-MM-dd hh\\:mm\\:ss",
|
||||
"AiraPrevYearLabel": "前一年",
|
||||
"AiraNextYearLabel": "后一年",
|
||||
"AiraPrevMonthLabel": "上一月",
|
||||
"AiraNextMonthLabel": "下一月",
|
||||
"ClearButtonText": "清空",
|
||||
"NowButtonText": "此刻",
|
||||
"ConfirmButtonText": "确定",
|
||||
"CancelButtonText": "取消",
|
||||
"YearText": "{0} 年",
|
||||
"MonthText": "{0} 月",
|
||||
"YearPeriodText": "{0} 年 - {1} 年",
|
||||
"Months": "1,2,3,4,5,6,7,8,9,10,11,12",
|
||||
"MonthLists": "一月,二月,三月,四月,五月,六月,七月,八月,九月,十月,十一月,十二月",
|
||||
"WeekLists": "日,一,二,三,四,五,六",
|
||||
"GenericTypeErroMessage": "DateTimePicker 组件仅支持绑定泛型为 DateTime 或者 DateTime?"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"PlaceHolder":"Please select ..."
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"PlaceHolder":"请选择 ..."
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"PlaceHolder":"Click to edit"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"PlaceHolder":"点击后编辑"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"ModelInvalidOperationExceptionMessage": "ValidateForm MODEL not match {0} MODEL",
|
||||
"PlaceHolderText":"Please input ..."
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"ModelInvalidOperationExceptionMessage": "验证表单与 {0} 绑定模型不一致",
|
||||
"PlaceHolderText":"请输入 ..."
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"ErrorMessage": "Please enter the same value again"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"ErrorMessage": "你的输入不相同"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"TooltipText": "Go top"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"TooltipText": "返回顶端"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"TooltipText": "Click to Expand/Collapse sidebar"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"TooltipText": "点击展开收缩左侧菜单"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"PlaceHolder": "Click for select ...",
|
||||
"SelectAllText": "All",
|
||||
"ReverseSelectText": "Reverse",
|
||||
"ClearText": "Clear"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"PlaceHolder": "点击进行多选 ...",
|
||||
"SelectAllText": "全选",
|
||||
"ReverseSelectText": "反选",
|
||||
"ClearText": "清除"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"AiraPageLabel": "Pagination",
|
||||
"AiraPrevPageText": "Prev",
|
||||
"AiraFirstPageText": "First",
|
||||
"AiraNextPageText": "Next",
|
||||
"PageInfoText": "{0}-{1}",
|
||||
"TotalInfoText": ", Total {0}",
|
||||
"PrePageInfoText": "",
|
||||
"RowInfoText": "",
|
||||
"LabelString": "page {0}",
|
||||
"SelectItemsText": "{0} /page"
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
{
|
||||
"AiraPageLabel": "分页组件",
|
||||
"AiraPrevPageText": "上一页",
|
||||
"AiraFirstPageText": "第一页",
|
||||
"AiraNextPageText": "下一页",
|
||||
"PageInfoText": "显示第 {0} 到第 {1} 条记录",
|
||||
"TotalInfoText": ",总共 {0} 条记录",
|
||||
"PrePageInfoText": "每页显示",
|
||||
"RowInfoText": "条记录",
|
||||
"LabelString": "第 {0} 页",
|
||||
"SelectItemsText": "{0} 条/页"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"CloseButtonText": "Cancel",
|
||||
"ConfirmButtonText": "Ok",
|
||||
"Content": "Are you sure DELETE?"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"CloseButtonText": "关闭",
|
||||
"ConfirmButtonText": "确定",
|
||||
"Content": "确认删除吗?"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"PlaceHolder": "Please input ...",
|
||||
"ClearButtonText": "Clear",
|
||||
"GenerateButtonText": "Generate"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"PlaceHolder": "请输入内容",
|
||||
"ClearButtonText": "清除",
|
||||
"GenerateButtonText": "生成"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"ErrorMessage": "This field is required"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"ErrorMessage": "这是必填字段"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"SearchButtonText": "Search"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"SearchButtonText": "搜索"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"PlaceHolder": "Click for select ..."
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"PlaceHolder": "请选择 ..."
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"ErrorMessage": "Please enter a value less than or equal to {{0}}"
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"ErrorMessage": "最多可以输入 {{0}} 个字符"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"CloseButtonText": "Close",
|
||||
"CancelButtonText": "Cancel",
|
||||
"ConfirmButtonText": "Confirm"
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"CloseButtonText": "关闭",
|
||||
"CancelButtonText": "取消",
|
||||
"ConfirmButtonText": "确认"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"OnInnerText": "On",
|
||||
"OffInnerText": "Off"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"OnInnerText": "开",
|
||||
"OffInnerText": "关"
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"AddButtonText": "Add",
|
||||
"EditButtonText": "Edit",
|
||||
"DeleteButtonText": "Delete",
|
||||
"CancelDeleteButtonText": "Cancel",
|
||||
"ConfirmDeleteButtonText": "Delete",
|
||||
"ConfirmDeleteContentText": "Are you sure to DELETE all selected rows?",
|
||||
"RefreshButtonText": "Refresh",
|
||||
"ColumnButtonTitleText": "Show/Hide Columns",
|
||||
"ColumnButtonText": "Columns",
|
||||
"ExportButtonText": "Export",
|
||||
"SearchPlaceholderText": "Search",
|
||||
"SearchButtonText": "Search",
|
||||
"ResetButtonText": "Reset",
|
||||
"AdvanceButtonText": "Advance Search",
|
||||
"CheckboxDisplayText": "All",
|
||||
"EditModalTitle": "Edit Data",
|
||||
"AddModalTitle": "New Data",
|
||||
"ColumnButtonTemplateHeaderText": "",
|
||||
"SearchTooltip": "<div class='search-input-tooltip'>Please input ...</br><kbd>Enter</kbd> Search <kbd>ESC</kbd> Clear</div>",
|
||||
"SearchModalTitle": "Searching",
|
||||
"AddButtonToastTitle": "Add Data",
|
||||
"AddButtonToastContent": "Save data failed. Please provider SAVE method",
|
||||
"EditButtonToastTitle": "Add Data",
|
||||
"EditButtonToastNotSelectContent": "Save data failed. Please provider SAVE method",
|
||||
"EditButtonToastMoreSelectContent": "Only one row can be EDIT",
|
||||
"EditButtonToastNoSaveMethodContent": "Can not EDIT data. Please provider SAVE method",
|
||||
"SaveButtonToastTitle": "Save Data",
|
||||
"SaveButtonToastContent": "Save data failed. Please provider SAVE method",
|
||||
"SaveButtonToastResultContent": "Save data {0}, auto close after {1}s",
|
||||
"SuccessText": "Successful",
|
||||
"FailText": "Failed",
|
||||
"DeleteButtonToastTitle": "Delete Data",
|
||||
"DeleteButtonToastContent": "Please select DELETE rows, auto claose after {1}s",
|
||||
"DeleteButtonToastResultContent": "Delete data {0}, auto claose after {1}s"
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
{
|
||||
"AddButtonText": "新建",
|
||||
"EditButtonText": "编辑",
|
||||
"DeleteButtonText": "删除",
|
||||
"CancelDeleteButtonText": "取消",
|
||||
"ConfirmDeleteButtonText": "删除",
|
||||
"ConfirmDeleteContentText": "确认要删除选中的所有行吗?",
|
||||
"RefreshButtonText": "刷新",
|
||||
"ColumnButtonTitleText": "列显示隐藏控制",
|
||||
"ColumnButtonText": "列",
|
||||
"ExportButtonText": "导出数据",
|
||||
"SearchPlaceholderText": "搜索",
|
||||
"SearchButtonText": "搜索",
|
||||
"ResetButtonText": "清空过滤",
|
||||
"AdvanceButtonText": "高级搜索",
|
||||
"CheckboxDisplayText": "选择",
|
||||
"EditModalTitle": "编辑数据窗口",
|
||||
"AddModalTitle": "新建数据窗口",
|
||||
"ColumnButtonTemplateHeaderText": "操作",
|
||||
"SearchTooltip": "<div class='search-input-tooltip'>输入任意字符串全局搜索</br><kbd>Enter</kbd> 搜索 <kbd>ESC</kbd> 清除搜索</div>",
|
||||
"SearchModalTitle": "搜索条件",
|
||||
"AddButtonToastTitle": "新建数据",
|
||||
"AddButtonToastContent": "未提供保存数据方法,无法新建数据",
|
||||
"EditButtonToastTitle": "编辑数据",
|
||||
"EditButtonToastNotSelectContent": "请选择要编辑的数据",
|
||||
"EditButtonToastMoreSelectContent": "只能选择一项要编辑的数据",
|
||||
"EditButtonToastNoSaveMethodContent": "未提供保存数据方法,无法编辑数据",
|
||||
"SaveButtonToastTitle": "保存数据",
|
||||
"SaveButtonToastContent": "未提供保存数据方法,无法保存数据",
|
||||
"SaveButtonToastResultContent": "保存数据{0}, {1} 秒后自动关闭",
|
||||
"SuccessText": "成功",
|
||||
"FailText": "失败",
|
||||
"DeleteButtonToastTitle": "删除数据",
|
||||
"DeleteButtonToastContent": "请选择要删除的数据, {0} 秒后自动关闭",
|
||||
"DeleteButtonToastResultContent": "删除数据{0}, {1} 秒后自动关闭"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"CloseButtonText": "Close",
|
||||
"SaveButtonText": "Save"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"CloseButtonText": "关闭",
|
||||
"SaveButtonText": "保存"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"Title": "Filter",
|
||||
"ClearButtonText": "Clear",
|
||||
"FilterButtonText": "Filter",
|
||||
"BoolFilter.AllText": "All",
|
||||
"BoolFilter.TrueText": "True",
|
||||
"BoolFilter.FalseText": "False",
|
||||
"GreaterThanOrEqual": "GreaterThanOrEqual",
|
||||
"LessThanOrEqual": "LessThanOrEqual",
|
||||
"GreaterThan": "GreaterThan",
|
||||
"LessThan": "LessThan",
|
||||
"Equal": "Equal",
|
||||
"NotEqual": "NotEqual",
|
||||
"Contains": "Contains",
|
||||
"NotContains": "NotContains",
|
||||
"EnumFilter.AllText": "All"
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
{
|
||||
"Title": "过滤",
|
||||
"ClearButtonText": "重置",
|
||||
"FilterButtonText": "确认",
|
||||
"BoolFilter.AllText": "全部",
|
||||
"BoolFilter.TrueText": "选中",
|
||||
"BoolFilter.FalseText": "未选中",
|
||||
"GreaterThanOrEqual": "大于等于",
|
||||
"LessThanOrEqual": "小于等于",
|
||||
"GreaterThan": "大于",
|
||||
"LessThan": "小于",
|
||||
"Equal": "等于",
|
||||
"NotEqual": "不等于",
|
||||
"Contains": "包含",
|
||||
"NotContains": "不包含",
|
||||
"EnumFilter.AllText": "全选"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"ResetButtonText": "Reset",
|
||||
"QueryButtonText": "Query"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"ResetButtonText": "重置",
|
||||
"QueryButtonText": "查询"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"PauseText": "Pause",
|
||||
"ResumeText": "Resume",
|
||||
"CancelText": "Cancel",
|
||||
"StarText": "Star"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"PauseText": "暂停",
|
||||
"ResumeText": "继续",
|
||||
"CancelText": "取消",
|
||||
"StarText": "开始计时"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"OnText": "Expand",
|
||||
"OffText": "Collapse"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"OnText": "展开",
|
||||
"OffText": "收缩"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"LeftPanelText": "List 1",
|
||||
"RightPanelText": "List 2"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"LeftPanelText": "列表 1",
|
||||
"RightPanelText": "列表 2"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"Text": "Upload",
|
||||
"ResetText": "Reset",
|
||||
"AllowFileTypeErrorMessage": "Only allow Images type file",
|
||||
"FileTooLargeText": "File to large"
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"Text": "点击上传",
|
||||
"ResetText": "重置",
|
||||
"AllowFileTypeErrorMessage": "只允许选择图片类型文件",
|
||||
"FileTooLargeText": "文件太大"
|
||||
}
|
||||
@@ -55,6 +55,15 @@
|
||||
language: (navigator.browserLanguage || navigator.language).toLowerCase()
|
||||
};
|
||||
|
||||
$.blazorCulture = {
|
||||
get: () => {
|
||||
return window.localStorage['BlazorCulture'];
|
||||
},
|
||||
set: (value) => {
|
||||
window.localStorage['BlazorCulture'] = value;
|
||||
}
|
||||
};
|
||||
|
||||
$.generatefile = (fileName, bytesBase64, contenttype) => {
|
||||
var link = document.createElement('a');
|
||||
link.download = fileName;
|
||||
|
||||
@@ -6,10 +6,16 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.0" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.0" />
|
||||
<PackageReference Include="coverlet.collector" Version="1.2.0" />
|
||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="coverlet.collector" Version="1.3.0">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
Reference in New Issue
Block a user