Skip to content

Commit 629ffb7

Browse files
authored
Merge pull request #369 from hishamco/useRequestLocalization
Add a builder API for configuring UseRequestLocalization
2 parents 5005d6c + db4cc14 commit 629ffb7

File tree

8 files changed

+381
-25
lines changed

8 files changed

+381
-25
lines changed

samples/LocalizationSample/Startup.cs

Lines changed: 12 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5-
using System.Collections.Generic;
65
using System.Globalization;
76
using Microsoft.AspNetCore.Builder;
87
using Microsoft.AspNetCore.Hosting;
@@ -24,31 +23,19 @@ public void ConfigureServices(IServiceCollection services)
2423

2524
public void Configure(IApplicationBuilder app, IStringLocalizer<Startup> SR)
2625
{
27-
var supportedCultures = new List<CultureInfo>
28-
{
29-
new CultureInfo("en-US"),
30-
new CultureInfo("en-AU"),
31-
new CultureInfo("en-GB"),
32-
new CultureInfo("es-ES"),
33-
new CultureInfo("ja-JP"),
34-
new CultureInfo("fr-FR"),
35-
new CultureInfo("zh"),
36-
new CultureInfo("zh-CN")
37-
};
38-
var options = new RequestLocalizationOptions
39-
{
40-
DefaultRequestCulture = new RequestCulture("en-US"),
41-
SupportedCultures = supportedCultures,
42-
SupportedUICultures = supportedCultures
43-
};
44-
// Optionally create an app-specific provider with just a delegate, e.g. look up user preference from DB.
45-
// Inserting it as position 0 ensures it has priority over any of the default providers.
46-
//options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
47-
//{
48-
49-
//}));
26+
var supportedCultures = new [] { "en-US", "en-AU", "en-GB", "es-ES", "ja-JP", "fr-FR", "zh", "zh-CN" };
27+
app.UseRequestLocalization(options =>
28+
options
29+
.AddSupportedCultures(supportedCultures)
30+
.AddSupportedUICultures(supportedCultures)
31+
.SetDefaultCulture(supportedCultures[0])
32+
// Optionally create an app-specific provider with just a delegate, e.g. look up user preference from DB.
33+
// Inserting it as position 0 ensures it has priority over any of the default providers.
34+
//.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
35+
//{
5036

51-
app.UseRequestLocalization(options);
37+
//}));
38+
);
5239

5340
app.Use(async (context, next) =>
5441
{

src/Microsoft.AspNetCore.Localization/ApplicationBuilderExtensions.cs

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,80 @@ public static IApplicationBuilder UseRequestLocalization(
4343
{
4444
throw new ArgumentNullException(nameof(app));
4545
}
46+
4647
if (options == null)
4748
{
4849
throw new ArgumentNullException(nameof(options));
4950
}
5051

5152
return app.UseMiddleware<RequestLocalizationMiddleware>(Options.Create(options));
5253
}
54+
55+
/// <summary>
56+
/// Adds the <see cref="RequestLocalizationMiddleware"/> to automatically set culture information for
57+
/// requests based on information provided by the client.
58+
/// </summary>
59+
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
60+
/// <param name="optionsAction"></param>
61+
/// <remarks>
62+
/// This will going to instantiate a new <see cref="RequestLocalizationOptions"/> that doesn't come from the services.
63+
/// </remarks>
64+
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
65+
public static IApplicationBuilder UseRequestLocalization(
66+
this IApplicationBuilder app,
67+
Action<RequestLocalizationOptions> optionsAction)
68+
{
69+
if (app == null)
70+
{
71+
throw new ArgumentNullException(nameof(app));
72+
}
73+
74+
if (optionsAction == null)
75+
{
76+
throw new ArgumentNullException(nameof(optionsAction));
77+
}
78+
79+
var options = new RequestLocalizationOptions();
80+
optionsAction.Invoke(options);
81+
82+
return app.UseMiddleware<RequestLocalizationMiddleware>(Options.Create(options));
83+
}
84+
85+
/// <summary>
86+
/// Adds the <see cref="RequestLocalizationMiddleware"/> to automatically set culture information for
87+
/// requests based on information provided by the client.
88+
/// </summary>
89+
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
90+
/// <param name="cultures">The culture names to be added by the application, which is represents both supported cultures and UI cultures.</param>
91+
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
92+
/// <remarks>
93+
/// Note that the first culture is the default culture name.
94+
/// </remarks>
95+
public static IApplicationBuilder UseRequestLocalization(
96+
this IApplicationBuilder app,
97+
params string[] cultures)
98+
{
99+
if (app == null)
100+
{
101+
throw new ArgumentNullException(nameof(app));
102+
}
103+
104+
if (cultures == null)
105+
{
106+
throw new ArgumentNullException(nameof(cultures));
107+
}
108+
109+
if (cultures.Length == 0)
110+
{
111+
throw new ArgumentException(Resources.Exception_CulturesShouldNotBeEmpty);
112+
}
113+
114+
var options = new RequestLocalizationOptions()
115+
.AddSupportedCultures(cultures)
116+
.AddSupportedUICultures(cultures)
117+
.SetDefaultCulture(cultures[0]);
118+
119+
return app.UseMiddleware<RequestLocalizationMiddleware>(Options.Create(options));
120+
}
53121
}
54122
}

src/Microsoft.AspNetCore.Localization/Properties/Resources.Designer.cs

Lines changed: 37 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/Microsoft.AspNetCore.Localization/RequestLocalizationOptions.cs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,5 +109,52 @@ public RequestCulture DefaultRequestCulture
109109
/// </list>
110110
/// </summary>
111111
public IList<IRequestCultureProvider> RequestCultureProviders { get; set; }
112+
113+
/// <summary>
114+
/// Adds the set of the supported cultures by the application.
115+
/// </summary>
116+
/// <param name="cultures">The cultures to be added.</param>
117+
/// <returns>The <see cref="RequestLocalizationOptions"/>.</returns>
118+
public RequestLocalizationOptions AddSupportedCultures(params string[] cultures)
119+
{
120+
var supportedCultures = new List<CultureInfo>();
121+
122+
foreach (var culture in cultures)
123+
{
124+
supportedCultures.Add(new CultureInfo(culture));
125+
}
126+
127+
SupportedCultures = supportedCultures;
128+
return this;
129+
}
130+
131+
/// <summary>
132+
/// Adds the set of the supported UI cultures by the application.
133+
/// </summary>
134+
/// <param name="uiCultures">The UI cultures to be added.</param>
135+
/// <returns>The <see cref="RequestLocalizationOptions"/>.</returns>
136+
public RequestLocalizationOptions AddSupportedUICultures(params string[] uiCultures)
137+
{
138+
var supportedUICultures = new List<CultureInfo>();
139+
foreach (var culture in uiCultures)
140+
{
141+
supportedUICultures.Add(new CultureInfo(culture));
142+
}
143+
144+
SupportedUICultures = supportedUICultures;
145+
return this;
146+
}
147+
148+
/// <summary>
149+
/// Set the default culture which is used by the application when a supported culture could not be determined by
150+
/// one of the configured <see cref="IRequestCultureProvider"/>s.
151+
/// </summary>
152+
/// <param name="defaultCulture">The default culture to be set.</param>
153+
/// <returns>The <see cref="RequestLocalizationOptions"/>.</returns>
154+
public RequestLocalizationOptions SetDefaultCulture(string defaultCulture)
155+
{
156+
DefaultRequestCulture = new RequestCulture(defaultCulture);
157+
return this;
158+
}
112159
}
113160
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<root>
3+
<!--
4+
Microsoft ResX Schema
5+
6+
Version 2.0
7+
8+
The primary goals of this format is to allow a simple XML format
9+
that is mostly human readable. The generation and parsing of the
10+
various data types are done through the TypeConverter classes
11+
associated with the data types.
12+
13+
Example:
14+
15+
... ado.net/XML headers & schema ...
16+
<resheader name="resmimetype">text/microsoft-resx</resheader>
17+
<resheader name="version">2.0</resheader>
18+
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
19+
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
20+
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
21+
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
22+
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
23+
<value>[base64 mime encoded serialized .NET Framework object]</value>
24+
</data>
25+
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
26+
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
27+
<comment>This is a comment</comment>
28+
</data>
29+
30+
There are any number of "resheader" rows that contain simple
31+
name/value pairs.
32+
33+
Each data row contains a name, and value. The row also contains a
34+
type or mimetype. Type corresponds to a .NET class that support
35+
text/value conversion through the TypeConverter architecture.
36+
Classes that don't support this are serialized and stored with the
37+
mimetype set.
38+
39+
The mimetype is used for serialized objects, and tells the
40+
ResXResourceReader how to depersist the object. This is currently not
41+
extensible. For a given mimetype the value must be set accordingly:
42+
43+
Note - application/x-microsoft.net.object.binary.base64 is the format
44+
that the ResXResourceWriter will generate, however the reader can
45+
read any of the formats listed below.
46+
47+
mimetype: application/x-microsoft.net.object.binary.base64
48+
value : The object must be serialized with
49+
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
50+
: and then encoded with base64 encoding.
51+
52+
mimetype: application/x-microsoft.net.object.soap.base64
53+
value : The object must be serialized with
54+
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
55+
: and then encoded with base64 encoding.
56+
57+
mimetype: application/x-microsoft.net.object.bytearray.base64
58+
value : The object must be serialized into a byte array
59+
: using a System.ComponentModel.TypeConverter
60+
: and then encoded with base64 encoding.
61+
-->
62+
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
63+
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
64+
<xsd:element name="root" msdata:IsDataSet="true">
65+
<xsd:complexType>
66+
<xsd:choice maxOccurs="unbounded">
67+
<xsd:element name="metadata">
68+
<xsd:complexType>
69+
<xsd:sequence>
70+
<xsd:element name="value" type="xsd:string" minOccurs="0" />
71+
</xsd:sequence>
72+
<xsd:attribute name="name" use="required" type="xsd:string" />
73+
<xsd:attribute name="type" type="xsd:string" />
74+
<xsd:attribute name="mimetype" type="xsd:string" />
75+
<xsd:attribute ref="xml:space" />
76+
</xsd:complexType>
77+
</xsd:element>
78+
<xsd:element name="assembly">
79+
<xsd:complexType>
80+
<xsd:attribute name="alias" type="xsd:string" />
81+
<xsd:attribute name="name" type="xsd:string" />
82+
</xsd:complexType>
83+
</xsd:element>
84+
<xsd:element name="data">
85+
<xsd:complexType>
86+
<xsd:sequence>
87+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
88+
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
89+
</xsd:sequence>
90+
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
91+
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
92+
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
93+
<xsd:attribute ref="xml:space" />
94+
</xsd:complexType>
95+
</xsd:element>
96+
<xsd:element name="resheader">
97+
<xsd:complexType>
98+
<xsd:sequence>
99+
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
100+
</xsd:sequence>
101+
<xsd:attribute name="name" type="xsd:string" use="required" />
102+
</xsd:complexType>
103+
</xsd:element>
104+
</xsd:choice>
105+
</xsd:complexType>
106+
</xsd:element>
107+
</xsd:schema>
108+
<resheader name="resmimetype">
109+
<value>text/microsoft-resx</value>
110+
</resheader>
111+
<resheader name="version">
112+
<value>2.0</value>
113+
</resheader>
114+
<resheader name="reader">
115+
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
116+
</resheader>
117+
<resheader name="writer">
118+
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
119+
</resheader>
120+
<data name="Exception_CulturesShouldNotBeEmpty" xml:space="preserve">
121+
<value>Please provide at least one culture.</value>
122+
</data>
123+
</root>
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
3+
4+
using LocalizationWebsite.Models;
5+
using Microsoft.AspNetCore.Builder;
6+
using Microsoft.AspNetCore.Http;
7+
using Microsoft.AspNetCore.Localization;
8+
using Microsoft.Extensions.DependencyInjection;
9+
using Microsoft.Extensions.Localization;
10+
using Microsoft.Extensions.Logging;
11+
12+
namespace LocalizationWebsite
13+
{
14+
public class StartupBuilderAPIs
15+
{
16+
public void ConfigureServices(IServiceCollection services)
17+
{
18+
services.AddLocalization(options => options.ResourcesPath = "Resources");
19+
}
20+
21+
public void Configure(
22+
IApplicationBuilder app,
23+
ILoggerFactory loggerFactory,
24+
IStringLocalizer<Customer> customerStringLocalizer)
25+
{
26+
var supportedCultures = new[] { "en-US", "fr-FR" };
27+
app.UseRequestLocalization(options =>
28+
options
29+
.AddSupportedCultures(supportedCultures)
30+
.AddSupportedUICultures(supportedCultures)
31+
.SetDefaultCulture("ar-YE")
32+
);
33+
34+
app.Run(async (context) =>
35+
{
36+
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
37+
var requestCulture = requestCultureFeature.RequestCulture;
38+
await context.Response.WriteAsync(customerStringLocalizer["Hello"]);
39+
});
40+
}
41+
}
42+
}

0 commit comments

Comments
 (0)