Skip to content

Commit aefcb1f

Browse files
authored
feat(i18n): Simplify fetching custom resources (#387)
* fix(i18n): Fix resource type case sensitive issue * chore: modify method name * feat(I18n): Simplify fetching custom resources * feat: Custom resources support getting content through attribute expressions * rename: Customer -> Custom
1 parent fb1eb16 commit aefcb1f

File tree

10 files changed

+189
-7
lines changed

10 files changed

+189
-7
lines changed

Masa.Framework.sln

+11
Original file line numberDiff line numberDiff line change
@@ -643,6 +643,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Utils.Extensions.Enums
643643
EndProject
644644
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.Utils.Extensions.Expressions.Tests", "src\Utils\Extensions\Tests\Masa.Utils.Extensions.Expressions.Tests\Masa.Utils.Extensions.Expressions.Tests.csproj", "{FCD6DF86-4E3B-4CDC-9849-28884B3B40D8}"
645645
EndProject
646+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Masa.BuildingBlocks.Globalization.I18n.Tests", "src\BuildingBlocks\Globalization\Masa.BuildingBlocks.Globalization.I18n.Tests\Masa.BuildingBlocks.Globalization.I18n.Tests.csproj", "{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}"
647+
EndProject
646648
Global
647649
GlobalSection(SolutionConfigurationPlatforms) = preSolution
648650
Debug|Any CPU = Debug|Any CPU
@@ -2291,6 +2293,14 @@ Global
22912293
{FCD6DF86-4E3B-4CDC-9849-28884B3B40D8}.Release|Any CPU.Build.0 = Release|Any CPU
22922294
{FCD6DF86-4E3B-4CDC-9849-28884B3B40D8}.Release|x64.ActiveCfg = Release|Any CPU
22932295
{FCD6DF86-4E3B-4CDC-9849-28884B3B40D8}.Release|x64.Build.0 = Release|Any CPU
2296+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
2297+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}.Debug|Any CPU.Build.0 = Debug|Any CPU
2298+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}.Debug|x64.ActiveCfg = Debug|Any CPU
2299+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}.Debug|x64.Build.0 = Debug|Any CPU
2300+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}.Release|Any CPU.ActiveCfg = Release|Any CPU
2301+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}.Release|Any CPU.Build.0 = Release|Any CPU
2302+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}.Release|x64.ActiveCfg = Release|Any CPU
2303+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE}.Release|x64.Build.0 = Release|Any CPU
22942304
EndGlobalSection
22952305
GlobalSection(SolutionProperties) = preSolution
22962306
HideSolutionNode = FALSE
@@ -2608,6 +2618,7 @@ Global
26082618
{351755B9-4C7F-4B51-B813-3203DC9A8284} = {9FEE5178-557E-4694-A088-F157267C989C}
26092619
{3AAD9D87-BC2D-446C-B56B-60F8A1492C30} = {C2FAC276-9D6E-498A-BBA2-F3F14ADF4D0D}
26102620
{FCD6DF86-4E3B-4CDC-9849-28884B3B40D8} = {C2FAC276-9D6E-498A-BBA2-F3F14ADF4D0D}
2621+
{8BF4E6EC-4BF7-43B6-B11B-9047759E4FAE} = {D10FC534-0091-42B4-809F-82C1E2164ED5}
26112622
EndGlobalSection
26122623
GlobalSection(ExtensibilityGlobals) = postSolution
26132624
SolutionGuid = {40383055-CC50-4600-AD9A-53C14F620D03}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright (c) MASA Stack All rights reserved.
2+
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
3+
4+
namespace Masa.BuildingBlocks.Ddd.Domain.Tests;
5+
6+
public class CustomResource
7+
{
8+
public string Name { get; set; }
9+
10+
public OrderResource Order { get; set; }
11+
12+
public class OrderResource
13+
{
14+
public string Name { get; set; }
15+
}
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Copyright (c) MASA Stack All rights reserved.
2+
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
3+
4+
namespace Masa.BuildingBlocks.Ddd.Domain.Tests;
5+
6+
[TestClass]
7+
public class ExpressionTest
8+
{
9+
[TestMethod]
10+
public void TestGetI18nName()
11+
{
12+
var name = ExpressionExtensions.GetI18nName<CustomResource>(c => c.Name);
13+
Assert.AreEqual("Name", name);
14+
15+
name = ExpressionExtensions.GetI18nName<CustomResource>(c => c.Order.Name);
16+
Assert.AreEqual("Order.Name", name);
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net6.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<IsPackable>false</IsPackable>
8+
<RootNamespace>Masa.BuildingBlocks.Ddd.Domain.Tests</RootNamespace>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<PackageReference Include="coverlet.collector" Version="$(CoverletPackageVersion)">
13+
<PrivateAssets>all</PrivateAssets>
14+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
15+
</PackageReference>
16+
<PackageReference Include="coverlet.msbuild" Version="$(CoverletPackageVersion)">
17+
<PrivateAssets>all</PrivateAssets>
18+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
19+
</PackageReference>
20+
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="$(MicrosoftTeskSdkPackageVersion)" />
21+
<PackageReference Include="MSTest.TestAdapter" Version="$(MSTestPackageVersion)" />
22+
<PackageReference Include="MSTest.TestFramework" Version="$(MSTestPackageVersion)" />
23+
<PackageReference Include="Moq" Version="$(MoqPackageVersion)" />
24+
</ItemGroup>
25+
26+
<ItemGroup>
27+
<ProjectReference Include="..\Masa.BuildingBlocks.Globalization.I18n\Masa.BuildingBlocks.Globalization.I18n.csproj" />
28+
</ItemGroup>
29+
30+
</Project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
// Copyright (c) MASA Stack All rights reserved.
2+
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
3+
4+
global using Masa.BuildingBlocks.Globalization.I18n;
5+
global using Microsoft.VisualStudio.TestTools.UnitTesting;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// Copyright (c) MASA Stack All rights reserved.
2+
// Licensed under the MIT License. See LICENSE.txt in the project root for license information.
3+
4+
namespace Masa.BuildingBlocks.Globalization.I18n;
5+
6+
public static class ExpressionExtensions
7+
{
8+
public static string GetI18nName<TResource>(Expression<Func<TResource, string>> propertyExpression)
9+
=> GetI18nName(propertyExpression.Body);
10+
11+
private static string GetI18nName(Expression expression)
12+
{
13+
string name = string.Empty;
14+
if (expression is MemberExpression memberExpression)
15+
{
16+
name = memberExpression.Member.Name;
17+
18+
if (memberExpression.Expression is { NodeType: ExpressionType.Parameter })
19+
return name;
20+
21+
return $"{GetI18nName(memberExpression.Expression!)}.{name}";
22+
}
23+
24+
return name;
25+
}
26+
}

src/BuildingBlocks/Globalization/Masa.BuildingBlocks.Globalization.I18n/I18n.cs

+76
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,82 @@ public static class I18n
4343
/// <param name="arguments">The values to format the string with.</param>
4444
public static string? T(string name, bool returnKey, params object[] arguments) => _i18n.T(name, returnKey, arguments);
4545

46+
/// <summary>
47+
/// Gets the string resource with the given name.
48+
/// </summary>
49+
/// <param name="name">The name of the string resource.</param>
50+
/// <typeparam name="TResource">Customer Resource Type</typeparam>
51+
/// <returns></returns>
52+
public static string T<TResource>(string name)
53+
=> _serviceProvider.GetRequiredService<II18n<TResource>>().T(name);
54+
55+
/// <summary>
56+
/// Gets the string resource with the given name.
57+
/// </summary>
58+
/// <param name="propertyExpression">attribute expression.</param>
59+
/// <typeparam name="TResource">Customer Resource Type</typeparam>
60+
/// <returns></returns>
61+
public static string T<TResource>(Expression<Func<TResource, string>> propertyExpression)
62+
=> T<TResource>(ExpressionExtensions.GetI18nName(propertyExpression));
63+
64+
/// <summary>
65+
/// Gets the string resource with the given name.
66+
/// </summary>
67+
/// <param name="name">The name of the string resource.</param>
68+
/// <param name="returnKey">Return Key when key does not exist, default: true</param>
69+
/// <typeparam name="TResource">Customer Resource Type</typeparam>
70+
/// <returns></returns>
71+
public static string? T<TResource>(string name, bool returnKey)
72+
=> _serviceProvider.GetRequiredService<II18n<TResource>>().T(name, returnKey);
73+
74+
/// <summary>
75+
/// Gets the string resource with the given name.
76+
/// </summary>
77+
/// <param name="propertyExpression">attribute expression.</param>
78+
/// <param name="returnKey">Return Key when key does not exist, default: true</param>
79+
/// <typeparam name="TResource">Customer Resource Type</typeparam>
80+
/// <returns></returns>
81+
public static string? T<TResource>(Expression<Func<TResource, string>> propertyExpression, bool returnKey)
82+
=> T<TResource>(ExpressionExtensions.GetI18nName(propertyExpression), returnKey);
83+
84+
/// <summary>
85+
/// Gets the string resource with the given name and formatted with the supplied arguments.
86+
/// </summary>
87+
/// <param name="name">The name of the string resource.</param>
88+
/// <param name="arguments">The values to format the string with.</param>
89+
/// <typeparam name="TResource">Customer Resource Type</typeparam>
90+
public static string T<TResource>(string name, params object[] arguments)
91+
=> _serviceProvider.GetRequiredService<II18n<TResource>>().T(name, arguments);
92+
93+
/// <summary>
94+
/// Gets the string resource with the given name and formatted with the supplied arguments.
95+
/// </summary>>
96+
/// <param name="propertyExpression">attribute expression.</param>
97+
/// <param name="arguments">The values to format the string with.</param>
98+
/// <typeparam name="TResource">Customer Resource Type</typeparam>
99+
public static string T<TResource>(Expression<Func<TResource, string>> propertyExpression, params object[] arguments)
100+
=> T<TResource>(ExpressionExtensions.GetI18nName(propertyExpression), arguments);
101+
102+
/// <summary>
103+
/// Gets the string resource with the given name and formatted with the supplied arguments.
104+
/// </summary>
105+
/// <param name="name">The name of the string resource.</param>
106+
/// <param name="returnKey">Return Key when key does not exist, default: true</param>
107+
/// <param name="arguments">The values to format the string with.</param>
108+
/// <typeparam name="TResource">Customer Resource Type</typeparam>
109+
public static string? T<TResource>(string name, bool returnKey, params object[] arguments)
110+
=> _serviceProvider.GetRequiredService<II18n<TResource>>().T(name, returnKey, arguments);
111+
112+
/// <summary>
113+
/// Gets the string resource with the given name and formatted with the supplied arguments.
114+
/// </summary>
115+
/// <param name="propertyExpression">attribute expression.</param>
116+
/// <param name="returnKey">Return Key when key does not exist, default: true</param>
117+
/// <param name="arguments">The values to format the string with.</param>
118+
/// <typeparam name="TResource">Customer Resource Type</typeparam>
119+
public static string? T<TResource>(Expression<Func<TResource, string>> propertyExpression, bool returnKey, params object[] arguments)
120+
=> T<TResource>(ExpressionExtensions.GetI18nName(propertyExpression), returnKey, arguments);
121+
46122
public static CultureInfo GetCultureInfo() => _i18n.GetCultureInfo();
47123

48124
/// <summary>

src/BuildingBlocks/Globalization/Masa.BuildingBlocks.Globalization.I18n/_Imports.cs

+1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,6 @@
55
global using Microsoft.Extensions.DependencyInjection;
66
global using Microsoft.Extensions.Options;
77
global using System.Globalization;
8+
global using System.Linq.Expressions;
89
global using System.Reflection;
910
global using System.Runtime.Serialization;
+4-5
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,12 @@
33

44
namespace Masa.Contrib.Dispatcher.IntegrationEvents.Tests;
55

6-
public class CustomerSendByDataProcessor : SendByDataProcessor
6+
public class CustomSendByDataProcessor : SendByDataProcessor
77
{
8-
public CustomerSendByDataProcessor(IServiceProvider serviceProvider,
8+
public CustomSendByDataProcessor(IServiceProvider serviceProvider,
99
IOptions<DispatcherOptions> options,
10-
IOptionsMonitor<MasaAppConfigureOptions>? masaAppConfigureOptions = null,
11-
ILogger<SendByDataProcessor>? logger = null)
12-
: base(serviceProvider, options, masaAppConfigureOptions, logger)
10+
IOptionsMonitor<MasaAppConfigureOptions>? masaAppConfigureOptions = null)
11+
: base(serviceProvider, options, masaAppConfigureOptions)
1312
{
1413
}
1514

src/Contrib/Dispatcher/IntegrationEvents/Tests/Masa.Contrib.Dispatcher.IntegrationEvents.Tests/SendByDataProcessorTest.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,14 @@ namespace Masa.Contrib.Dispatcher.IntegrationEvents.Tests;
77
public class SendByDataProcessorTest
88
{
99
private readonly IServiceCollection _services;
10-
private readonly CustomerSendByDataProcessor _processor;
10+
private readonly CustomSendByDataProcessor _processor;
1111

1212
public SendByDataProcessorTest()
1313
{
1414
_services = new ServiceCollection();
1515
IOptions<DispatcherOptions> dispatcherOptions =
1616
Microsoft.Extensions.Options.Options.Create(new DispatcherOptions(_services, new[] { this.GetType().Assembly }));
17-
_processor = new CustomerSendByDataProcessor(_services.BuildServiceProvider(), dispatcherOptions);
17+
_processor = new CustomSendByDataProcessor(_services.BuildServiceProvider(), dispatcherOptions);
1818
}
1919

2020
[TestMethod]

0 commit comments

Comments
 (0)