зеркало из https://github.com/aspnet/Localization.git
Merge pull request #369 from hishamco/useRequestLocalization
Add a builder API for configuring UseRequestLocalization
This commit is contained in:
Коммит
629ffb7ede
|
@ -2,7 +2,6 @@
|
|||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
|
@ -24,31 +23,19 @@ namespace LocalizationSample
|
|||
|
||||
public void Configure(IApplicationBuilder app, IStringLocalizer<Startup> SR)
|
||||
{
|
||||
var supportedCultures = new List<CultureInfo>
|
||||
{
|
||||
new CultureInfo("en-US"),
|
||||
new CultureInfo("en-AU"),
|
||||
new CultureInfo("en-GB"),
|
||||
new CultureInfo("es-ES"),
|
||||
new CultureInfo("ja-JP"),
|
||||
new CultureInfo("fr-FR"),
|
||||
new CultureInfo("zh"),
|
||||
new CultureInfo("zh-CN")
|
||||
};
|
||||
var options = new RequestLocalizationOptions
|
||||
{
|
||||
DefaultRequestCulture = new RequestCulture("en-US"),
|
||||
SupportedCultures = supportedCultures,
|
||||
SupportedUICultures = supportedCultures
|
||||
};
|
||||
// Optionally create an app-specific provider with just a delegate, e.g. look up user preference from DB.
|
||||
// Inserting it as position 0 ensures it has priority over any of the default providers.
|
||||
//options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
|
||||
//{
|
||||
var supportedCultures = new [] { "en-US", "en-AU", "en-GB", "es-ES", "ja-JP", "fr-FR", "zh", "zh-CN" };
|
||||
app.UseRequestLocalization(options =>
|
||||
options
|
||||
.AddSupportedCultures(supportedCultures)
|
||||
.AddSupportedUICultures(supportedCultures)
|
||||
.SetDefaultCulture(supportedCultures[0])
|
||||
// Optionally create an app-specific provider with just a delegate, e.g. look up user preference from DB.
|
||||
// Inserting it as position 0 ensures it has priority over any of the default providers.
|
||||
//.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(async context =>
|
||||
//{
|
||||
|
||||
//}));
|
||||
|
||||
app.UseRequestLocalization(options);
|
||||
//}));
|
||||
);
|
||||
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
|
|
|
@ -43,6 +43,7 @@ namespace Microsoft.AspNetCore.Builder
|
|||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
|
@ -50,5 +51,72 @@ namespace Microsoft.AspNetCore.Builder
|
|||
|
||||
return app.UseMiddleware<RequestLocalizationMiddleware>(Options.Create(options));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the <see cref="RequestLocalizationMiddleware"/> to automatically set culture information for
|
||||
/// requests based on information provided by the client.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
|
||||
/// <param name="optionsAction"></param>
|
||||
/// <remarks>
|
||||
/// This will going to instantiate a new <see cref="RequestLocalizationOptions"/> that doesn't come from the services.
|
||||
/// </remarks>
|
||||
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
|
||||
public static IApplicationBuilder UseRequestLocalization(
|
||||
this IApplicationBuilder app,
|
||||
Action<RequestLocalizationOptions> optionsAction)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
if (optionsAction == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(optionsAction));
|
||||
}
|
||||
|
||||
var options = new RequestLocalizationOptions();
|
||||
optionsAction.Invoke(options);
|
||||
|
||||
return app.UseMiddleware<RequestLocalizationMiddleware>(Options.Create(options));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the <see cref="RequestLocalizationMiddleware"/> to automatically set culture information for
|
||||
/// requests based on information provided by the client.
|
||||
/// </summary>
|
||||
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
|
||||
/// <param name="cultures">The culture names to be added by the application, which is represents both supported cultures and UI cultures.</param>
|
||||
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
|
||||
/// <remarks>
|
||||
/// Note that the first culture is the default culture name.
|
||||
/// </remarks>
|
||||
public static IApplicationBuilder UseRequestLocalization(
|
||||
this IApplicationBuilder app,
|
||||
params string[] cultures)
|
||||
{
|
||||
if (app == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(app));
|
||||
}
|
||||
|
||||
if (cultures == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(cultures));
|
||||
}
|
||||
|
||||
if (cultures.Length == 0)
|
||||
{
|
||||
throw new ArgumentException(Resources.Exception_CulturesShouldNotBeEmpty);
|
||||
}
|
||||
|
||||
var options = new RequestLocalizationOptions()
|
||||
.AddSupportedCultures(cultures)
|
||||
.AddSupportedUICultures(cultures)
|
||||
.SetDefaultCulture(cultures[0]);
|
||||
|
||||
return app.UseMiddleware<RequestLocalizationMiddleware>(Options.Create(options));
|
||||
}
|
||||
}
|
||||
}
|
37
src/Microsoft.AspNetCore.Localization/Properties/Resources.Designer.cs
сгенерированный
Normal file
37
src/Microsoft.AspNetCore.Localization/Properties/Resources.Designer.cs
сгенерированный
Normal file
|
@ -0,0 +1,37 @@
|
|||
// <auto-generated />
|
||||
namespace Microsoft.AspNetCore.Localization
|
||||
{
|
||||
using System.Reflection;
|
||||
using System.Resources;
|
||||
|
||||
internal static class Resources
|
||||
{
|
||||
private static readonly ResourceManager _resourceManager
|
||||
= new ResourceManager("Microsoft.AspNetCore.Localization.Resources", typeof(Resources).GetTypeInfo().Assembly);
|
||||
|
||||
/// <summary>
|
||||
/// Please provide at least one culture.
|
||||
/// </summary>
|
||||
internal static string Exception_CulturesShouldNotBeEmpty
|
||||
{
|
||||
get { return GetString("Exception_CulturesShouldNotBeEmpty"); }
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
{
|
||||
var value = _resourceManager.GetString(name);
|
||||
|
||||
System.Diagnostics.Debug.Assert(value != null);
|
||||
|
||||
if (formatterNames != null)
|
||||
{
|
||||
for (var i = 0; i < formatterNames.Length; i++)
|
||||
{
|
||||
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
|
||||
}
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,5 +109,52 @@ namespace Microsoft.AspNetCore.Builder
|
|||
/// </list>
|
||||
/// </summary>
|
||||
public IList<IRequestCultureProvider> RequestCultureProviders { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds the set of the supported cultures by the application.
|
||||
/// </summary>
|
||||
/// <param name="cultures">The cultures to be added.</param>
|
||||
/// <returns>The <see cref="RequestLocalizationOptions"/>.</returns>
|
||||
public RequestLocalizationOptions AddSupportedCultures(params string[] cultures)
|
||||
{
|
||||
var supportedCultures = new List<CultureInfo>();
|
||||
|
||||
foreach (var culture in cultures)
|
||||
{
|
||||
supportedCultures.Add(new CultureInfo(culture));
|
||||
}
|
||||
|
||||
SupportedCultures = supportedCultures;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds the set of the supported UI cultures by the application.
|
||||
/// </summary>
|
||||
/// <param name="uiCultures">The UI cultures to be added.</param>
|
||||
/// <returns>The <see cref="RequestLocalizationOptions"/>.</returns>
|
||||
public RequestLocalizationOptions AddSupportedUICultures(params string[] uiCultures)
|
||||
{
|
||||
var supportedUICultures = new List<CultureInfo>();
|
||||
foreach (var culture in uiCultures)
|
||||
{
|
||||
supportedUICultures.Add(new CultureInfo(culture));
|
||||
}
|
||||
|
||||
SupportedUICultures = supportedUICultures;
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the default culture which is used by the application when a supported culture could not be determined by
|
||||
/// one of the configured <see cref="IRequestCultureProvider"/>s.
|
||||
/// </summary>
|
||||
/// <param name="defaultCulture">The default culture to be set.</param>
|
||||
/// <returns>The <see cref="RequestLocalizationOptions"/>.</returns>
|
||||
public RequestLocalizationOptions SetDefaultCulture(string defaultCulture)
|
||||
{
|
||||
DefaultRequestCulture = new RequestCulture(defaultCulture);
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,123 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="Exception_CulturesShouldNotBeEmpty" xml:space="preserve">
|
||||
<value>Please provide at least one culture.</value>
|
||||
</data>
|
||||
</root>
|
|
@ -0,0 +1,42 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using LocalizationWebsite.Models;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Localization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Localization;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace LocalizationWebsite
|
||||
{
|
||||
public class StartupBuilderAPIs
|
||||
{
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddLocalization(options => options.ResourcesPath = "Resources");
|
||||
}
|
||||
|
||||
public void Configure(
|
||||
IApplicationBuilder app,
|
||||
ILoggerFactory loggerFactory,
|
||||
IStringLocalizer<Customer> customerStringLocalizer)
|
||||
{
|
||||
var supportedCultures = new[] { "en-US", "fr-FR" };
|
||||
app.UseRequestLocalization(options =>
|
||||
options
|
||||
.AddSupportedCultures(supportedCultures)
|
||||
.AddSupportedUICultures(supportedCultures)
|
||||
.SetDefaultCulture("ar-YE")
|
||||
);
|
||||
|
||||
app.Run(async (context) =>
|
||||
{
|
||||
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
|
||||
var requestCulture = requestCultureFeature.RequestCulture;
|
||||
await context.Response.WriteAsync(customerStringLocalizer["Hello"]);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,6 +77,15 @@ namespace Microsoft.AspNetCore.Localization.FunctionalTests
|
|||
"Bonjour from StartupResourcesAtRootFolder Bonjour from Test in root folder Bonjour from Customer in Models folder");
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public Task Localization_BuilderAPIs()
|
||||
{
|
||||
return RunTest(
|
||||
typeof(StartupBuilderAPIs),
|
||||
"ar-YE",
|
||||
"Hello");
|
||||
}
|
||||
|
||||
private async Task RunTest(Type startupType, string culture, string expected)
|
||||
{
|
||||
var webHostBuilder = new WebHostBuilder().UseStartup(startupType);
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Xunit;
|
||||
|
||||
|
@ -84,6 +85,48 @@ namespace Microsoft.AspNetCore.Localization
|
|||
Assert.Collection(options.SupportedUICultures, item => Assert.Equal(explicitCulture, item));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuilderAPIs_AddSupportedCultures()
|
||||
{
|
||||
// Arrange
|
||||
var supportedCultures = new[] { "en-US", "ar-YE" };
|
||||
|
||||
// Act
|
||||
var options = new RequestLocalizationOptions()
|
||||
.AddSupportedCultures(supportedCultures);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(supportedCultures, options.SupportedCultures.Select(c => c.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuilderAPIs_AddSupportedUICultures()
|
||||
{
|
||||
// Arrange
|
||||
var supportedUICultures = new[] { "en-US", "ar-YE" };
|
||||
|
||||
// Act
|
||||
var options = new RequestLocalizationOptions()
|
||||
.AddSupportedUICultures(supportedUICultures);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(supportedUICultures, options.SupportedUICultures.Select(c => c.Name));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuilderAPIs_SetDefaultCulture()
|
||||
{
|
||||
// Arrange
|
||||
var defaultCulture = "ar-YE";
|
||||
|
||||
// Act
|
||||
var options = new RequestLocalizationOptions()
|
||||
.SetDefaultCulture(defaultCulture);
|
||||
|
||||
// Assert
|
||||
Assert.Equal(defaultCulture, options.DefaultRequestCulture.Culture.Name);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
CultureInfo.CurrentCulture = _initialCulture;
|
||||
|
|
Загрузка…
Ссылка в новой задаче