Compare commits

1 Commits

12 changed files with 231 additions and 20 deletions

View File

@@ -3,23 +3,11 @@ root = true
# All files # All files
[*] [*]
indent_style = space indent_style = space
end_of_line = crlf end_of_line = lf
charset = utf-8 charset = utf-8
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = 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 files
[*.xml] [*.xml]
indent_size = 2 indent_size = 2

47
Settings.XamlStyler Normal file
View File

@@ -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
}

6
global.json Normal file
View File

@@ -0,0 +1,6 @@
{
"sdk": {
"version": "9.0.0",
"rollForward": "major"
}
}

View File

@@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<NoWarn>IDE0130</NoWarn>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,15 @@
using System.Globalization;
namespace Aurora.I18N;
/// <summary>
/// 文化变更事件参数
/// </summary>
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));
}

View File

@@ -0,0 +1,24 @@
using System.Globalization;
namespace Aurora.I18N;
public interface ICultureProvider
{
/// <summary>
/// 当前用于数值、日期等格式化的文化
/// 通常对应 <see cref="CultureInfo.CurrentCulture"/>
/// </summary>
CultureInfo CurrentCulture { get; }
/// <summary>
/// 当前用于 UI 文本的文化
/// 通常对应 <see cref="CultureInfo.CurrentUICulture"/>
/// </summary>
CultureInfo CurrentUICulture { get; }
/// <summary>
/// 当当前文化发生变化时触发,用于通知 UI 或其它监听方刷新
/// </summary>
event EventHandler<CultureChangedEventArgs>? CultureChanged;
}

View File

@@ -0,0 +1,6 @@
namespace Aurora.I18N;
/// <summary>
/// 关于
/// </summary>
public interface IPluralizer;

View File

@@ -0,0 +1,25 @@
using System.Globalization;
namespace Aurora.I18N;
/// <summary>
/// 按 key 和文化提供本地化字符串的读取接口
/// </summary>
public interface IResourceProvider
{
/// <summary>
/// 按键名和文化获取本地化字符串,缺失时返回 null
/// </summary>
/// <param name="key">资源键名</param>
/// <param name="culture">目标文化信息</param>
string? GetString(string key, CultureInfo culture);
/// <summary>
/// 获取指定文化下的全部键值对,可选包含父文化
/// </summary>
/// <param name="culture">目标文化信息</param>
/// <param name="includeParentCultures">是否同时包含父文化的资源</param>
IEnumerable<KeyValuePair<string, string>> GetAllStrings(
CultureInfo culture,
bool includeParentCultures);
}

View File

@@ -0,0 +1,46 @@
namespace Aurora.I18N;
/// <summary>
/// 泛型本地化接口,返回类型化结果并兼容基础本地化访问
/// </summary>
/// <typeparam name="T">本地化结果的泛型类型</typeparam>
public interface ITextLocalizer<out T> : ITextLocalizer { }
/// <summary>
/// 定义文本本地化的统一访问接口,支持通过键名获取格式化后的字符串
/// </summary>
public interface ITextLocalizer
{
/// <summary>
/// 根据键名获取本地化字符串,未找到时通常返回键名自身
/// </summary>
/// <param name="key">资源键名</param>
string this[string key] { get; }
/// <summary>
/// 根据键名获取可格式化的本地化字符串,并应用提供的格式参数
/// </summary>
/// <param name="key">资源键名</param>
/// <param name="arguments">格式化占位符对应的参数</param>
string this[string key, params object[] arguments] { get; }
/// <summary>
/// 返回包含查找状态信息的本地化结果
/// </summary>
/// <param name="key">资源键名</param>
LocalizedString Get(string key);
/// <summary>
/// 返回格式化后的本地化结果,并附带查找状态信息
/// </summary>
/// <param name="key">资源键名</param>
/// <param name="arguments">格式化占位符对应的参数</param>
LocalizedString Get(string key, params object[] arguments);
/// <summary>
/// 获取当前文化(可选包含父文化)下的全部本地化字符串
/// </summary>
/// <param name="includeParentCultures">是否同时包含父文化的资源</param>
IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures);
}

View File

@@ -0,0 +1,40 @@
namespace Aurora.I18N;
/// <summary>
/// 表示一个本地化文本项,包含键名、值以及查找状态等信息。
/// </summary>
/// <param name="name">资源键名,通常用于回退显示或继续查询</param>
/// <param name="value">本地化后的字符串,若查找失败则可能为 null</param>
/// <param name="resourceNotFound">指示是否未找到对应资源</param>
/// <param name="searchedLocation">记录查找资源时检索过的位置,便于调试</param>
public readonly struct LocalizedString(
string name,
string? value,
bool resourceNotFound,
string? searchedLocation = null)
{
/// <summary>
/// 本地化资源的键名
/// </summary>
public string Name { get; } = name;
/// <summary>
/// 匹配到的本地化文本,若未找到则保持为空
/// </summary>
public string? Value { get; } = value;
/// <summary>
/// 标记是否未找到对应资源,调用方可据此决定是否回退或记录日志
/// </summary>
public bool ResourceNotFound { get; } = resourceNotFound;
/// <summary>
/// 描述资源查找的来源或搜索路径,便于排查缺失问题
/// </summary>
public string? SearchedLocation { get; } = searchedLocation;
/// <summary>
/// 返回本地化值,如果缺失则回退到键名,保证调用方总能得到可显示内容
/// </summary>
public override string ToString() => Value ?? Name;
}

3
i18n/i18n.slnx Normal file
View File

@@ -0,0 +1,3 @@
<Solution>
<Project Path="Aurora.I18N.Abstractions/Aurora.I18N.Abstractions.csproj" Id="fef1ac5d-fbd2-456b-a529-ec3996f856c7" />
</Solution>

View File

@@ -2,7 +2,8 @@
<configuration> <configuration>
<packageSources> <packageSources>
<clear /> <clear />
<add key="nuget-cdn" value="https://nuget.cdn.azure.cn/v3/index.json" /> <!--<add key="nuget-cdn" value="https://nuget.cdn.azure.cn/v3/index.json" allowInsecureConnections="True" />-->
<add key="nuget-src" value="https://api.nuget.org/v3/index.json" allowInsecureConnections="True" />
</packageSources> </packageSources>
<disabledPackageSources> <disabledPackageSources>
<clear /> <clear />