From 3fbe229995212a224e42bfbae21bc85803666a52 Mon Sep 17 00:00:00 2001 From: chuan Date: Sun, 7 Dec 2025 01:21:46 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=9B=BD=E9=99=85?= =?UTF-8?q?=E5=8C=96=E6=94=AF=E6=8C=81=EF=BC=8C=E5=8C=85=E5=90=AB=E6=96=87?= =?UTF-8?q?=E5=8C=96=E5=8F=98=E6=9B=B4=E4=BA=8B=E4=BB=B6=E3=80=81=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E6=8F=90=E4=BE=9B=E8=80=85=E5=92=8C=E6=9C=AC=E5=9C=B0?= =?UTF-8?q?=E5=8C=96=E5=AD=97=E7=AC=A6=E4=B8=B2=E7=BB=93=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .editorconfig | 14 +----- Settings.XamlStyler | 47 +++++++++++++++++++ global.json | 6 +++ .../Aurora.I18N.Abstractions.csproj | 10 ++++ .../CultureChangedEventArgs.cs | 15 ++++++ .../ICultureProvider.cs | 24 ++++++++++ i18n/Aurora.I18N.Abstractions/IPluralizer.cs | 6 +++ .../IResourceProvider.cs | 25 ++++++++++ .../ITextLocalizer.cs | 46 ++++++++++++++++++ .../LocalizedString.cs | 40 ++++++++++++++++ i18n/i18n.slnx | 3 ++ nuget.config | 15 +++--- 12 files changed, 231 insertions(+), 20 deletions(-) create mode 100644 Settings.XamlStyler create mode 100644 global.json create mode 100644 i18n/Aurora.I18N.Abstractions/Aurora.I18N.Abstractions.csproj create mode 100644 i18n/Aurora.I18N.Abstractions/CultureChangedEventArgs.cs create mode 100644 i18n/Aurora.I18N.Abstractions/ICultureProvider.cs create mode 100644 i18n/Aurora.I18N.Abstractions/IPluralizer.cs create mode 100644 i18n/Aurora.I18N.Abstractions/IResourceProvider.cs create mode 100644 i18n/Aurora.I18N.Abstractions/ITextLocalizer.cs create mode 100644 i18n/Aurora.I18N.Abstractions/LocalizedString.cs create mode 100644 i18n/i18n.slnx diff --git a/.editorconfig b/.editorconfig index 928b3ce..ef55d07 100644 --- a/.editorconfig +++ b/.editorconfig @@ -3,23 +3,11 @@ root = true # All files [*] indent_style = space -end_of_line = crlf +end_of_line = lf charset = utf-8 trim_trailing_whitespace = true insert_final_newline = true -# C# files -[*.cs] -indent_size = 4 -csharp_new_line_before_open_brace = all -csharp_prefer_braces = true:warning -csharp_style_var_for_built_in_types = true:suggestion -csharp_style_var_when_type_is_apparent = true:suggestion - -# AXAML files -[*.axaml] -indent_size = 2 - # Xml files [*.xml] indent_size = 2 diff --git a/Settings.XamlStyler b/Settings.XamlStyler new file mode 100644 index 0000000..8dcd894 --- /dev/null +++ b/Settings.XamlStyler @@ -0,0 +1,47 @@ +{ + "IndentSize": 4, + "IndentWithTabs": null, + "AttributesTolerance": 5, + "KeepFirstAttributeOnSameLine": false, + "MaxAttributeCharactersPerLine": 80, + "MaxAttributesPerLine": 0, + "NewlineExemptionElements": "RadialGradientBrush, GradientStop, LinearGradientBrush, ScaleTransform, SkewTransform, RotateTransform, TranslateTransform, Trigger, Condition, Setter", + "SeparateByGroups": true, + "AttributeIndentation": 0, + "AttributeIndentationStyle": "Spaces", + "RemoveDesignTimeReferences": false, + "EnableAttributeReordering": true, + "AttributeOrderingRuleGroups": [ + "x:Class", + "xmlns, xmlns:x", + "xmlns:*", + "x:Key, Key, x:Name, Name, x:Uid, Uid, Title", + "Grid.Row, Grid.RowSpan, Grid.Column, Grid.ColumnSpan, Canvas.Left, Canvas.Top, Canvas.Right, Canvas.Bottom", + "Width, Height, MinWidth, MinHeight, MaxWidth, MaxHeight", + "Classes, Theme, Styles", + "Margin, Padding, HorizontalAlignment, VerticalAlignment, HorizontalContentAlignment, VerticalContentAlignment, Panel.ZIndex", + "*:*, *", + "PageSource, PageIndex, Offset, Color, TargetName, Property, Value, StartPoint, EndPoint", + "mc:Ignorable, d:IsDataSource, d:LayoutOverrides, d:IsStaticText", + "Storyboard.*, From, To, Duration" + ], + "FirstLineAttributes": "", + "OrderAttributesByName": true, + "IgnoreDesignTimeReferencePrefix": false, + "PutEndingBracketOnNewLine": false, + "RemoveEndingTagOfEmptyElement": true, + "SpaceBeforeClosingSlash": false, + "RootElementLineBreakRule": "Default", + "ReorderVSM": "Last", + "ReorderGridChildren": false, + "ReorderCanvasChildren": false, + "ReorderSetters": "None", + "FormatMarkupExtension": false, + "NoNewLineMarkupExtensions": "x:Bind, Binding", + "ThicknessSeparator": "Comma", + "ThicknessAttributes": "Margin, Padding, BorderThickness, ThumbnailClipMargin", + "FormatOnSave": true, + "SaveAndCloseOnFormat": true, + "CommentPadding": 2, + "SuppressProcessing": false +} diff --git a/global.json b/global.json new file mode 100644 index 0000000..3502a98 --- /dev/null +++ b/global.json @@ -0,0 +1,6 @@ +{ + "sdk": { + "version": "9.0.0", + "rollForward": "major" + } +} diff --git a/i18n/Aurora.I18N.Abstractions/Aurora.I18N.Abstractions.csproj b/i18n/Aurora.I18N.Abstractions/Aurora.I18N.Abstractions.csproj new file mode 100644 index 0000000..20b2831 --- /dev/null +++ b/i18n/Aurora.I18N.Abstractions/Aurora.I18N.Abstractions.csproj @@ -0,0 +1,10 @@ + + + + net9.0 + enable + enable + IDE0130 + + + diff --git a/i18n/Aurora.I18N.Abstractions/CultureChangedEventArgs.cs b/i18n/Aurora.I18N.Abstractions/CultureChangedEventArgs.cs new file mode 100644 index 0000000..62b3b22 --- /dev/null +++ b/i18n/Aurora.I18N.Abstractions/CultureChangedEventArgs.cs @@ -0,0 +1,15 @@ +using System.Globalization; + +namespace Aurora.I18N; + +/// +/// 文化变更事件参数 +/// +public sealed class CultureChangedEventArgs(CultureInfo oldCulture, CultureInfo newCulture) : EventArgs +{ + public CultureInfo OldCulture { get; } + = oldCulture ?? throw new ArgumentNullException(nameof(oldCulture)); + + public CultureInfo NewCulture { get; } + = newCulture ?? throw new ArgumentNullException(nameof(newCulture)); +} diff --git a/i18n/Aurora.I18N.Abstractions/ICultureProvider.cs b/i18n/Aurora.I18N.Abstractions/ICultureProvider.cs new file mode 100644 index 0000000..807b39f --- /dev/null +++ b/i18n/Aurora.I18N.Abstractions/ICultureProvider.cs @@ -0,0 +1,24 @@ +using System.Globalization; + +namespace Aurora.I18N; + +public interface ICultureProvider +{ + /// + /// 当前用于数值、日期等格式化的文化 + /// 通常对应 + /// + CultureInfo CurrentCulture { get; } + + /// + /// 当前用于 UI 文本的文化 + /// 通常对应 + /// + CultureInfo CurrentUICulture { get; } + + /// + /// 当当前文化发生变化时触发,用于通知 UI 或其它监听方刷新 + /// + event EventHandler? CultureChanged; +} + diff --git a/i18n/Aurora.I18N.Abstractions/IPluralizer.cs b/i18n/Aurora.I18N.Abstractions/IPluralizer.cs new file mode 100644 index 0000000..87131c4 --- /dev/null +++ b/i18n/Aurora.I18N.Abstractions/IPluralizer.cs @@ -0,0 +1,6 @@ +namespace Aurora.I18N; + +/// +/// 关于 +/// +public interface IPluralizer; diff --git a/i18n/Aurora.I18N.Abstractions/IResourceProvider.cs b/i18n/Aurora.I18N.Abstractions/IResourceProvider.cs new file mode 100644 index 0000000..7e627d1 --- /dev/null +++ b/i18n/Aurora.I18N.Abstractions/IResourceProvider.cs @@ -0,0 +1,25 @@ +using System.Globalization; + +namespace Aurora.I18N; + +/// +/// 按 key 和文化提供本地化字符串的读取接口 +/// +public interface IResourceProvider +{ + /// + /// 按键名和文化获取本地化字符串,缺失时返回 null + /// + /// 资源键名 + /// 目标文化信息 + string? GetString(string key, CultureInfo culture); + + /// + /// 获取指定文化下的全部键值对,可选包含父文化 + /// + /// 目标文化信息 + /// 是否同时包含父文化的资源 + IEnumerable> GetAllStrings( + CultureInfo culture, + bool includeParentCultures); +} diff --git a/i18n/Aurora.I18N.Abstractions/ITextLocalizer.cs b/i18n/Aurora.I18N.Abstractions/ITextLocalizer.cs new file mode 100644 index 0000000..6f95fcd --- /dev/null +++ b/i18n/Aurora.I18N.Abstractions/ITextLocalizer.cs @@ -0,0 +1,46 @@ +namespace Aurora.I18N; + +/// +/// 泛型本地化接口,返回类型化结果并兼容基础本地化访问 +/// +/// 本地化结果的泛型类型 +public interface ITextLocalizer : ITextLocalizer { } + + +/// +/// 定义文本本地化的统一访问接口,支持通过键名获取格式化后的字符串 +/// +public interface ITextLocalizer +{ + /// + /// 根据键名获取本地化字符串,未找到时通常返回键名自身 + /// + /// 资源键名 + string this[string key] { get; } + + /// + /// 根据键名获取可格式化的本地化字符串,并应用提供的格式参数 + /// + /// 资源键名 + /// 格式化占位符对应的参数 + string this[string key, params object[] arguments] { get; } + + /// + /// 返回包含查找状态信息的本地化结果 + /// + /// 资源键名 + LocalizedString Get(string key); + + /// + /// 返回格式化后的本地化结果,并附带查找状态信息 + /// + /// 资源键名 + /// 格式化占位符对应的参数 + LocalizedString Get(string key, params object[] arguments); + + /// + /// 获取当前文化(可选包含父文化)下的全部本地化字符串 + /// + /// 是否同时包含父文化的资源 + IEnumerable GetAllStrings(bool includeParentCultures); +} diff --git a/i18n/Aurora.I18N.Abstractions/LocalizedString.cs b/i18n/Aurora.I18N.Abstractions/LocalizedString.cs new file mode 100644 index 0000000..eecd691 --- /dev/null +++ b/i18n/Aurora.I18N.Abstractions/LocalizedString.cs @@ -0,0 +1,40 @@ +namespace Aurora.I18N; + +/// +/// 表示一个本地化文本项,包含键名、值以及查找状态等信息。 +/// +/// 资源键名,通常用于回退显示或继续查询 +/// 本地化后的字符串,若查找失败则可能为 null +/// 指示是否未找到对应资源 +/// 记录查找资源时检索过的位置,便于调试 +public readonly struct LocalizedString( + string name, + string? value, + bool resourceNotFound, + string? searchedLocation = null) +{ + /// + /// 本地化资源的键名 + /// + public string Name { get; } = name; + + /// + /// 匹配到的本地化文本,若未找到则保持为空 + /// + public string? Value { get; } = value; + + /// + /// 标记是否未找到对应资源,调用方可据此决定是否回退或记录日志 + /// + public bool ResourceNotFound { get; } = resourceNotFound; + + /// + /// 描述资源查找的来源或搜索路径,便于排查缺失问题 + /// + public string? SearchedLocation { get; } = searchedLocation; + + /// + /// 返回本地化值,如果缺失则回退到键名,保证调用方总能得到可显示内容 + /// + public override string ToString() => Value ?? Name; +} diff --git a/i18n/i18n.slnx b/i18n/i18n.slnx new file mode 100644 index 0000000..1c16724 --- /dev/null +++ b/i18n/i18n.slnx @@ -0,0 +1,3 @@ + + + diff --git a/nuget.config b/nuget.config index bc6e268..67a00ba 100644 --- a/nuget.config +++ b/nuget.config @@ -1,11 +1,12 @@ - - - - - - - + + + + + + + +