Fix #111: Design changes to known/allowed culture list and cache

This commit is contained in:
Kirthi Krishnamraju 2015-10-19 15:33:14 -07:00
parent d25ad6607e
commit 636459a6f7
26 changed files with 458 additions and 638 deletions

View File

@ -19,8 +19,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
global.json = global.json
EndProjectSection
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "CultureInfoGenerator", "src\CultureInfoGenerator\CultureInfoGenerator.xproj", "{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}"
EndProject
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "Microsoft.Extensions.Globalization.CultureInfoCache", "src\Microsoft.Extensions.Globalization.CultureInfoCache\Microsoft.Extensions.Globalization.CultureInfoCache.xproj", "{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{B723DB83-A670-4BCB-95FB-195361331AD2}"
@ -55,10 +53,6 @@ Global
{55D9501F-15B9-4339-A0AB-6082850E5FCE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{55D9501F-15B9-4339-A0AB-6082850E5FCE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{55D9501F-15B9-4339-A0AB-6082850E5FCE}.Release|Any CPU.Build.0 = Release|Any CPU
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB}.Release|Any CPU.Build.0 = Release|Any CPU
{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A}.Release|Any CPU.ActiveCfg = Release|Any CPU
@ -88,7 +82,6 @@ Global
{23E3BC23-3464-4D9B-BF78-02CB2182BEF0} = {FB313677-BAB3-4E49-8CDB-4FA4A9564767}
{A1FCF259-70F6-4605-AA2D-E4B356BE771A} = {FB313677-BAB3-4E49-8CDB-4FA4A9564767}
{55D9501F-15B9-4339-A0AB-6082850E5FCE} = {79878809-8D1C-4BD4-BA99-F1F13FF96FD8}
{BD22AE1C-6631-4DA6-874D-0DC0F803CEAB} = {FB313677-BAB3-4E49-8CDB-4FA4A9564767}
{F3988D3A-A4C8-4FD7-BAFE-13E0D0A1659A} = {FB313677-BAB3-4E49-8CDB-4FA4A9564767}
{287AD58D-DF34-4F16-8616-FD78FA1CADF9} = {B723DB83-A670-4BCB-95FB-195361331AD2}
{19A2A931-5C60-47A0-816A-0DC9C4CE5736} = {B723DB83-A670-4BCB-95FB-195361331AD2}

View File

@ -2,6 +2,7 @@
// 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.AspNet.Builder;
using Microsoft.AspNet.Http;
@ -24,16 +25,30 @@ namespace LocalizationSample
var options = new RequestLocalizationOptions
{
// Set options here to change middleware behavior
//SupportedCultures = new List<CultureInfo>
//{
// new CultureInfo("en-US"),
// new CultureInfo("en-AU")
//},
//SupportedUICultures = new List<CultureInfo>
//{
// new CultureInfo("en-US"),
// new CultureInfo("en-AU")
//}
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"),
new CultureInfo("zh-CHT")
},
SupportedUICultures = 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"),
new CultureInfo("zh-CHT")
}
};
// Optionally create an app-specific provider with just a delegate, e.g. look up user preference from DB.
@ -43,7 +58,7 @@ namespace LocalizationSample
//}));
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Use(async (context, next) =>
{

View File

@ -2,6 +2,8 @@
// 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 System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
@ -23,7 +25,7 @@ namespace Microsoft.AspNet.Localization
public int MaximumAcceptLanguageHeaderValuesToTry { get; set; } = 3;
/// <inheritdoc />
public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext)
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
if (httpContext == null)
{
@ -34,7 +36,7 @@ namespace Microsoft.AspNet.Localization
if (acceptLanguageHeader == null || acceptLanguageHeader.Count == 0)
{
return Task.FromResult((RequestCulture)null);
return Task.FromResult((ProviderCultureResult)null);
}
var languages = acceptLanguageHeader.AsEnumerable();
@ -47,30 +49,14 @@ namespace Microsoft.AspNet.Localization
}
var orderedLanguages = languages.OrderByDescending(h => h, StringWithQualityHeaderValueComparer.QualityComparer)
.ToList();
.Select(x => x.Value).ToList();
foreach (var language in orderedLanguages)
if (orderedLanguages.Any())
{
// Allow empty string values as they map to InvariantCulture, whereas null culture values will throw in
// the CultureInfo ctor
if (language.Value != null)
{
var culture = CultureInfoCache.GetCultureInfo(language.Value);
if (culture != null)
{
var requestCulture = new RequestCulture(culture);
requestCulture = ValidateRequestCulture(requestCulture);
if (requestCulture?.Culture == culture)
{
return Task.FromResult(requestCulture);
}
}
}
return Task.FromResult(new ProviderCultureResult(orderedLanguages));
}
return Task.FromResult((RequestCulture)null);
return Task.FromResult((ProviderCultureResult)null);
}
}
}

View File

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Globalization;
using Microsoft.AspNet.Localization;
namespace Microsoft.AspNet.Builder
@ -15,34 +16,46 @@ namespace Microsoft.AspNet.Builder
/// Adds the <see cref="RequestLocalizationMiddleware"/> to automatically set culture information for
/// requests based on information provided by the client using the default options.
/// </summary>
/// <param name="builder">The <see cref="IApplicationBuilder"/>.</param>
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
/// <param name="defaultRequestCulture">The default <see cref="RequestCulture"/> to use if none of the
/// requested cultures match supported cultures.</param>
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
public static IApplicationBuilder UseRequestLocalization(this IApplicationBuilder builder)
public static IApplicationBuilder UseRequestLocalization(
this IApplicationBuilder app,
RequestCulture defaultRequestCulture)
{
if (builder == null)
if (app == null)
{
throw new ArgumentNullException(nameof(builder));
throw new ArgumentNullException(nameof(app));
}
if (defaultRequestCulture == null)
{
throw new ArgumentNullException(nameof(defaultRequestCulture));
}
var options = new RequestLocalizationOptions();
return UseRequestLocalization(builder, options);
return UseRequestLocalization(app, options, defaultRequestCulture);
}
/// <summary>
/// Adds the <see cref="RequestLocalizationMiddleware"/> to automatically set culture information for
/// requests based on information provided by the client.
/// </summary>
/// <param name="builder">The <see cref="IApplicationBuilder"/>.</param>
/// <param name="app">The <see cref="IApplicationBuilder"/>.</param>
/// <param name="options">The options to configure the middleware with.</param>
/// <param name="defaultRequestCulture">The default <see cref="RequestCulture"/> to use if none of the
/// requested cultures match supported cultures.</param>
/// <returns>The <see cref="IApplicationBuilder"/>.</returns>
public static IApplicationBuilder UseRequestLocalization(
this IApplicationBuilder builder,
RequestLocalizationOptions options)
this IApplicationBuilder app,
RequestLocalizationOptions options,
RequestCulture defaultRequestCulture)
{
if (builder == null)
if (app == null)
{
throw new ArgumentNullException(nameof(builder));
throw new ArgumentNullException(nameof(app));
}
if (options == null)
@ -50,7 +63,12 @@ namespace Microsoft.AspNet.Builder
throw new ArgumentNullException(nameof(options));
}
return builder.UseMiddleware<RequestLocalizationMiddleware>(options);
if (defaultRequestCulture == null)
{
throw new ArgumentNullException(nameof(defaultRequestCulture));
}
return app.UseMiddleware<RequestLocalizationMiddleware>(options, defaultRequestCulture);
}
}
}

View File

@ -2,6 +2,8 @@
// 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 System.Threading.Tasks;
using Microsoft.AspNet.Http;
using Microsoft.Extensions.Globalization;
@ -29,7 +31,7 @@ namespace Microsoft.AspNet.Localization
public string CookieName { get; set; } = DefaultCookieName;
/// <inheritdoc />
public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext)
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
if (httpContext == null)
{
@ -40,14 +42,12 @@ namespace Microsoft.AspNet.Localization
if (cookie == null)
{
return Task.FromResult((RequestCulture)null);
return Task.FromResult((ProviderCultureResult)null);
}
var requestCulture = ParseCookieValue(cookie);
var providerResultCulture = ParseCookieValue(cookie);
requestCulture = ValidateRequestCulture(requestCulture);
return Task.FromResult(requestCulture);
return Task.FromResult(providerResultCulture);
}
/// <summary>
@ -75,7 +75,7 @@ namespace Microsoft.AspNet.Localization
/// </summary>
/// <param name="value">The cookie value to parse.</param>
/// <returns>The <see cref="RequestCulture"/> or <c>null</c> if parsing fails.</returns>
public static RequestCulture ParseCookieValue(string value)
public static ProviderCultureResult ParseCookieValue(string value)
{
if (string.IsNullOrWhiteSpace(value))
{
@ -100,15 +100,25 @@ namespace Microsoft.AspNet.Localization
var cultureName = potentialCultureName.Substring(_culturePrefix.Length);
var uiCultureName = potentialUICultureName.Substring(_uiCulturePrefix.Length);
var culture = CultureInfoCache.GetCultureInfo(cultureName);
var uiCulture = CultureInfoCache.GetCultureInfo(uiCultureName);
if (culture == null || uiCulture == null)
if (cultureName == null && uiCultureName == null)
{
// No values specified for either so no match
return null;
}
return new RequestCulture(culture, uiCulture);
if (cultureName != null && uiCultureName == null)
{
// Value for culture but not for UI culture so default to culture value for both
uiCultureName = cultureName;
}
if (cultureName == null && uiCultureName != null)
{
// Value for UI culture but not for culture so default to UI culture value for both
cultureName = uiCultureName;
}
return new ProviderCultureResult(cultureName, uiCultureName);
}
}
}

View File

@ -12,13 +12,13 @@ namespace Microsoft.AspNet.Localization
/// </summary>
public class CustomRequestCultureProvider : RequestCultureProvider
{
private readonly Func<HttpContext, Task<RequestCulture>> _provider;
private readonly Func<HttpContext, Task<ProviderCultureResult>> _provider;
/// <summary>
/// Creates a new <see cref="CustomRequestCultureProvider"/> using the specified delegate.
/// </summary>
/// <param name="provider">The provider delegate.</param>
public CustomRequestCultureProvider(Func<HttpContext, Task<RequestCulture>> provider)
public CustomRequestCultureProvider(Func<HttpContext, Task<ProviderCultureResult>> provider)
{
if (provider == null)
{
@ -29,7 +29,7 @@ namespace Microsoft.AspNet.Localization
}
/// <inheritdoc />
public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext)
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
if (httpContext == null)
{

View File

@ -1,6 +1,8 @@
// 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 System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNet.Http;
@ -16,9 +18,9 @@ namespace Microsoft.AspNet.Localization
/// </summary>
/// <param name="httpContext">The <see cref="HttpContext"/> for the request.</param>
/// <returns>
/// The determined <see cref="RequestCulture"/>.
/// Returns <c>null</c> if the provider couldn't determine a <see cref="RequestCulture"/>.
/// The determined <see cref="ProviderCultureResult"/>.
/// Returns <c>null</c> if the provider couldn't determine a <see cref="ProviderCultureResult"/>.
/// </returns>
Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext);
Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext);
}
}

View File

@ -0,0 +1,66 @@
// 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 System.Collections.Generic;
namespace Microsoft.AspNet.Localization
{
/// <summary>
/// Details about the cultures obtained from <see cref="IRequestCultureProvider"/>.
/// </summary>
public class ProviderCultureResult
{
/// <summary>
/// Creates a new <see cref="ProviderCultureResult"/> object that has its <see cref="Cultures"/> and
/// <see cref="UICultures"/> properties set to the same culture value.
/// </summary>
/// <param name="culture">The name of the culture to be used for formatting, text, i.e. language.</param>
public ProviderCultureResult(string culture)
: this(new List<string> { culture }, new List<string> { culture })
{
}
/// <summary>
/// Creates a new <see cref="ProviderCultureResult"/> object has its <see cref="Cultures"/> and
/// <see cref="UICultures"/> properties set to the respective culture values provided.
/// </summary>
/// <param name="culture">The name of the culture to be used for formatting.</param>
/// <param name="uiCulture"> The name of the ui culture to be used for text, i.e. language.</param>
public ProviderCultureResult(string culture, string uiCulture)
: this(new List<string> { culture }, new List<string> { uiCulture })
{
}
/// <summary>
/// Creates a new <see cref="ProviderCultureResult"/> object that has its <see cref="Cultures"/> and
/// <see cref="UICultures"/> properties set to the same culture value.
/// </summary>
/// <param name="cultures">The list of cultures to be used for formatting, text, i.e. language.</param>
public ProviderCultureResult(IList<string> cultures)
: this(cultures, cultures)
{
}
/// <summary>
/// Creates a new <see cref="ProviderCultureResult"/> object has its <see cref="Cultures"/> and
/// <see cref="UICultures"/> properties set to the respective culture values provided.
/// </summary>
/// <param name="cultures">The list of cultures to be used for formatting.</param>
/// <param name="uiCultures">The list of ui cultures to be used for text, i.e. language.</param>
public ProviderCultureResult(IList<string> cultures, IList<string> uiCultures)
{
Cultures = cultures;
UICultures = uiCultures;
}
/// <summary>
/// Gets the list of cultures to be used for formatting.
/// </summary>
public IList<string> Cultures { get; }
/// <summary>
/// Gets the list of ui cultures to be used for text, i.e. language;
/// </summary>
public IList<string> UICultures { get; }
}
}

View File

@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Localization
public string UIQueryStringKey { get; set; } = "ui-culture";
/// <inheritdoc />
public override Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext)
public override Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext)
{
if (httpContext == null)
{
@ -37,7 +37,7 @@ namespace Microsoft.AspNet.Localization
var request = httpContext.Request;
if (!request.QueryString.HasValue)
{
return Task.FromResult((RequestCulture)null);
return Task.FromResult((ProviderCultureResult)null);
}
string queryCulture = null;
@ -56,7 +56,7 @@ namespace Microsoft.AspNet.Localization
if (queryCulture == null && queryUICulture == null)
{
// No values specified for either so no match
return Task.FromResult((RequestCulture)null);
return Task.FromResult((ProviderCultureResult)null);
}
if (queryCulture != null && queryUICulture == null)
@ -71,19 +71,9 @@ namespace Microsoft.AspNet.Localization
queryCulture = queryUICulture;
}
var culture = CultureInfoCache.GetCultureInfo(queryCulture);
var uiCulture = CultureInfoCache.GetCultureInfo(queryUICulture);
var providerResultCulture = new ProviderCultureResult(queryCulture, queryUICulture);
if (culture == null || uiCulture == null)
{
return Task.FromResult((RequestCulture)null);
}
var requestCulture = new RequestCulture(culture, uiCulture);
requestCulture = ValidateRequestCulture(requestCulture);
return Task.FromResult(requestCulture);
return Task.FromResult(providerResultCulture);
}
}
}

View File

@ -21,6 +21,27 @@ namespace Microsoft.AspNet.Localization
{
}
/// <summary>
/// Creates a new <see cref="RequestCulture"/> object has its <see cref="Culture"/> and <see cref="UICulture"/>
/// properties set to the same <see cref="CultureInfo"/> value.
/// </summary>
/// <param name="culture">The culture for the request.</param>
public RequestCulture(string culture)
: this(culture, culture)
{
}
/// <summary>
/// Creates a new <see cref="RequestCulture"/> object has its <see cref="Culture"/> and <see cref="UICulture"/>
/// properties set to the respective <see cref="CultureInfo"/> values provided.
/// </summary>
/// <param name="culture">The culture for the request to be used for formatting.</param>
/// <param name="uiCulture">The culture for the request to be used for text, i.e. language.</param>
public RequestCulture(string culture, string uiCulture)
: this (new CultureInfo(culture), new CultureInfo(uiCulture))
{
}
/// <summary>
/// Creates a new <see cref="RequestCulture"/> object has its <see cref="Culture"/> and <see cref="UICulture"/>
/// properties set to the respective <see cref="CultureInfo"/> values provided.

View File

@ -17,45 +17,7 @@ namespace Microsoft.AspNet.Localization
public RequestLocalizationOptions Options { get; set; }
/// <inheritdoc />
public abstract Task<RequestCulture> DetermineRequestCulture(HttpContext httpContext);
public abstract Task<ProviderCultureResult> DetermineProviderCultureResult(HttpContext httpContext);
/// <summary>
/// Determines if the given <see cref="RequestCulture"/> is valid according to the currently configured.
/// <see cref="RequestLocalizationOptions"/>.
/// </summary>
/// <param name="requestCulture">The <see cref="RequestCulture"/> to validate.</param>
/// <returns>
/// The original <see cref="RequestCulture"/> if it was valid, otherwise a new <see cref="RequestCulture"/>
/// with values for <see cref="RequestCulture.Culture"/> and <see cref="RequestCulture.UICulture"/> that are
/// valid for the current configuration, or <c>null</c> if neither <see cref="RequestCulture.Culture"/> or
/// <see cref="RequestCulture.UICulture"/> were valid.
/// </returns>
protected RequestCulture ValidateRequestCulture(RequestCulture requestCulture)
{
if (requestCulture == null || Options == null)
{
return requestCulture;
}
var result = requestCulture;
if (Options.SupportedCultures != null && !Options.SupportedCultures.Contains(result.Culture))
{
result = new RequestCulture(Options.DefaultRequestCulture.Culture, result.UICulture);
}
if (Options.SupportedUICultures != null && !Options.SupportedUICultures.Contains(result.UICulture))
{
result = new RequestCulture(result.Culture, Options.DefaultRequestCulture.UICulture);
}
if (requestCulture.Culture != result.Culture && requestCulture.UICulture != result.UICulture)
{
// Both cultures were invalid, just return null
return null;
}
return result;
}
}
}

View File

@ -2,12 +2,14 @@
// 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 System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Http.Features;
using Microsoft.Extensions.Globalization;
namespace Microsoft.AspNet.Localization
{
@ -19,13 +21,20 @@ namespace Microsoft.AspNet.Localization
{
private readonly RequestDelegate _next;
private readonly RequestLocalizationOptions _options;
private readonly RequestCulture _defaultRequestCulture;
/// <summary>
/// Creates a new <see cref="RequestLocalizationMiddleware"/>.
/// </summary>
/// <param name="next">The <see cref="RequestDelegate"/> representing the next middleware in the pipeline.</param>
/// <param name="options">The <see cref="RequestLocalizationOptions"/> representing the options for the <see cref="RequestLocalizationMiddleware"/>.</param>
public RequestLocalizationMiddleware(RequestDelegate next, RequestLocalizationOptions options)
/// <param name="options">The <see cref="RequestLocalizationOptions"/> representing the options for the
/// <see cref="RequestLocalizationMiddleware"/>.</param>
/// <param name="defaultRequestCulture">The default <see cref="RequestCulture"/> to use if none of the
/// requested cultures match supported cultures.</param>
public RequestLocalizationMiddleware(
RequestDelegate next,
RequestLocalizationOptions options,
RequestCulture defaultRequestCulture)
{
if (next == null)
{
@ -37,8 +46,14 @@ namespace Microsoft.AspNet.Localization
throw new ArgumentNullException(nameof(options));
}
if (defaultRequestCulture == null)
{
throw new ArgumentNullException(nameof(defaultRequestCulture));
}
_next = next;
_options = options;
_defaultRequestCulture = defaultRequestCulture;
}
/// <summary>
@ -53,8 +68,7 @@ namespace Microsoft.AspNet.Localization
throw new ArgumentNullException(nameof(context));
}
var requestCulture = _options.DefaultRequestCulture ??
new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
var requestCulture = _defaultRequestCulture;
IRequestCultureProvider winningProvider = null;
@ -62,12 +76,45 @@ namespace Microsoft.AspNet.Localization
{
foreach (var provider in _options.RequestCultureProviders)
{
var result = await provider.DetermineRequestCulture(context);
if (result != null)
var providerResultCulture = await provider.DetermineProviderCultureResult(context);
if (providerResultCulture != null)
{
requestCulture = result;
winningProvider = provider;
break;
var cultures = providerResultCulture.Cultures;
var uiCultures = providerResultCulture.UICultures;
CultureInfo cultureInfo = null;
CultureInfo uiCultureInfo = null;
if (_options.SupportedCultures != null)
{
cultureInfo = GetCultureInfo(cultures, _options.SupportedCultures);
}
if (_options.SupportedUICultures != null)
{
uiCultureInfo = GetCultureInfo(uiCultures, _options.SupportedUICultures);
}
if (cultureInfo == null && uiCultureInfo == null)
{
continue;
}
if (cultureInfo == null && uiCultureInfo != null)
{
cultureInfo = _defaultRequestCulture.Culture;
}
if (cultureInfo != null && uiCultureInfo == null)
{
uiCultureInfo = _defaultRequestCulture.UICulture;
}
var result = new RequestCulture(cultureInfo, uiCultureInfo);
if (result != null)
{
requestCulture = result;
winningProvider = provider;
break;
}
}
}
}
@ -89,5 +136,24 @@ namespace Microsoft.AspNet.Localization
CultureInfo.CurrentUICulture = requestCulture.UICulture;
#endif
}
private CultureInfo GetCultureInfo(IList<string> cultures, IList<CultureInfo> supportedCultures)
{
foreach (var culture in cultures)
{
// Allow empty string values as they map to InvariantCulture, whereas null culture values will throw in
// the CultureInfo ctor
if (culture != null)
{
var cultureInfo = CultureInfoCache.GetCultureInfo(culture, supportedCultures);
if (cultureInfo != null)
{
return cultureInfo;
}
}
}
return null;
}
}
}

View File

@ -17,8 +17,6 @@ namespace Microsoft.AspNet.Localization
/// </summary>
public RequestLocalizationOptions()
{
DefaultRequestCulture = new RequestCulture(CultureInfo.CurrentCulture, CultureInfo.CurrentUICulture);
RequestCultureProviders = new List<IRequestCultureProvider>
{
new QueryStringRequestCultureProvider { Options = this },
@ -27,14 +25,6 @@ namespace Microsoft.AspNet.Localization
};
}
/// <summary>
/// The default <see cref="RequestCulture"/> to use. This value will be used if none of the configured
/// <see cref="IRequestCultureProvider"/> options result in a non-<c>null</c> result.
/// Defaults to <see cref="RequestCulture.Culture"/> set to <see cref="CultureInfo.DefaultThreadCurrentCulture"/>
/// and <see cref="RequestCulture.UICulture"/> set to <see cref="CultureInfo.DefaultThreadCurrentUICulture"/>.
/// </summary>
public RequestCulture DefaultRequestCulture { get; set; }
/// <summary>
/// The cultures supported by the application. If this value is non-<c>null</c>, the
/// <see cref="RequestLocalizationMiddleware"/> will only set the current request culture to an entry in this

View File

@ -1,15 +1,18 @@
// 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 System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
namespace Microsoft.Extensions.Globalization
{
/// <summary>
/// Provides read-only cached instances of <see cref="CultureInfo"/>.
/// </summary>
public static partial class CultureInfoCache
public static class CultureInfoCache
{
private static readonly ConcurrentDictionary<string, CacheEntry> _cache = new ConcurrentDictionary<string, CacheEntry>();
@ -18,15 +21,17 @@ namespace Microsoft.Extensions.Globalization
/// <see cref="KnownCultureNames"/> will be used.
/// </summary>
/// <param name="name">The culture name.</param>
/// <param name="supportedCultures">The cultures supported by the application.</param>
/// <returns>
/// A read-only cached <see cref="CultureInfo"/> or <c>null</c> a match wasn't found in
/// <see cref="KnownCultureNames"/>.
/// </returns>
public static CultureInfo GetCultureInfo(string name)
public static CultureInfo GetCultureInfo(string name, IList<CultureInfo> supportedCultures)
{
// Allow only known culture names as this API is called with input from users (HTTP requests) and
// creating CultureInfo objects is expensive and we don't want it to throw either.
if (name == null || !KnownCultureNames.Contains(name))
if (name == null || supportedCultures == null ||
!supportedCultures.Any(supportedCulture => string.Equals(supportedCulture.Name, name, StringComparison.OrdinalIgnoreCase)))
{
return null;
}

View File

@ -1,445 +0,0 @@
// 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.
// *************************** THIS FILE IS GENERATED BY A TOOL ***************************
// To make changes to this file look at the CultureInfoGenerator project in this solution.
using System;
using System.Collections.Generic;
namespace Microsoft.Extensions.Globalization
{
/// <summary>
/// Contains a list of known culture names that can be used to create a <see cref="System.Globalization.CultureInfo"/>.
/// </summary>
public static partial class CultureInfoCache
{
/// <summary>
/// This list of known cultures was generated by CultureInfoGenerator using .NET Framework 4.6 RC or later on
/// Microsoft Windows NT 6.2.9200.0.
/// As new versions of .NET Framework and Windows are released, this list should be regenerated to ensure it
/// contains the latest culture names.
/// </summary>
public static readonly HashSet<string> KnownCultureNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"",
"af",
"af-ZA",
"am",
"am-ET",
"ar",
"ar-AE",
"ar-BH",
"ar-DZ",
"ar-EG",
"ar-IQ",
"ar-JO",
"ar-KW",
"ar-LB",
"ar-LY",
"ar-MA",
"ar-OM",
"ar-QA",
"ar-SA",
"ar-SY",
"ar-TN",
"ar-YE",
"arn",
"arn-CL",
"as",
"as-IN",
"az",
"az-Cyrl",
"az-Cyrl-AZ",
"az-Latn",
"az-Latn-AZ",
"ba",
"ba-RU",
"be",
"be-BY",
"bg",
"bg-BG",
"bn",
"bn-BD",
"bn-IN",
"bo",
"bo-CN",
"br",
"br-FR",
"bs",
"bs-Cyrl",
"bs-Cyrl-BA",
"bs-Latn",
"bs-Latn-BA",
"ca",
"ca-ES",
"ca-ES-valencia",
"chr",
"chr-Cher",
"chr-Cher-US",
"co",
"co-FR",
"cs",
"cs-CZ",
"cy",
"cy-GB",
"da",
"da-DK",
"de",
"de-AT",
"de-CH",
"de-DE",
"de-LI",
"de-LU",
"dsb",
"dsb-DE",
"dv",
"dv-MV",
"el",
"el-GR",
"en",
"en-029",
"en-AU",
"en-BZ",
"en-CA",
"en-GB",
"en-HK",
"en-IE",
"en-IN",
"en-JM",
"en-MY",
"en-NZ",
"en-PH",
"en-SG",
"en-TT",
"en-US",
"en-ZA",
"en-ZW",
"es",
"es-419",
"es-AR",
"es-BO",
"es-CL",
"es-CO",
"es-CR",
"es-DO",
"es-EC",
"es-ES",
"es-GT",
"es-HN",
"es-MX",
"es-NI",
"es-PA",
"es-PE",
"es-PR",
"es-PY",
"es-SV",
"es-US",
"es-UY",
"es-VE",
"et",
"et-EE",
"eu",
"eu-ES",
"fa",
"fa-IR",
"ff",
"ff-Latn",
"ff-Latn-SN",
"fi",
"fi-FI",
"fil",
"fil-PH",
"fo",
"fo-FO",
"fr",
"fr-BE",
"fr-CA",
"fr-CD",
"fr-CH",
"fr-CI",
"fr-CM",
"fr-FR",
"fr-HT",
"fr-LU",
"fr-MA",
"fr-MC",
"fr-ML",
"fr-RE",
"fr-SN",
"fy",
"fy-NL",
"ga",
"ga-IE",
"gd",
"gd-GB",
"gl",
"gl-ES",
"gn",
"gn-PY",
"gsw",
"gsw-FR",
"gu",
"gu-IN",
"ha",
"ha-Latn",
"ha-Latn-NG",
"haw",
"haw-US",
"he",
"he-IL",
"hi",
"hi-IN",
"hr",
"hr-BA",
"hr-HR",
"hsb",
"hsb-DE",
"hu",
"hu-HU",
"hy",
"hy-AM",
"id",
"id-ID",
"ig",
"ig-NG",
"ii",
"ii-CN",
"is",
"is-IS",
"it",
"it-CH",
"it-IT",
"iu",
"iu-Cans",
"iu-Cans-CA",
"iu-Latn",
"iu-Latn-CA",
"ja",
"ja-JP",
"jv",
"jv-Latn",
"jv-Latn-ID",
"ka",
"ka-GE",
"kk",
"kk-KZ",
"kl",
"kl-GL",
"km",
"km-KH",
"kn",
"kn-IN",
"ko",
"ko-KR",
"kok",
"kok-IN",
"ku",
"ku-Arab",
"ku-Arab-IQ",
"ky",
"ky-KG",
"lb",
"lb-LU",
"lo",
"lo-LA",
"lt",
"lt-LT",
"lv",
"lv-LV",
"mg",
"mg-MG",
"mi",
"mi-NZ",
"mk",
"mk-MK",
"ml",
"ml-IN",
"mn",
"mn-Cyrl",
"mn-MN",
"mn-Mong",
"mn-Mong-CN",
"mn-Mong-MN",
"moh",
"moh-CA",
"mr",
"mr-IN",
"ms",
"ms-BN",
"ms-MY",
"mt",
"mt-MT",
"my",
"my-MM",
"nb",
"nb-NO",
"ne",
"ne-IN",
"ne-NP",
"nl",
"nl-BE",
"nl-NL",
"nn",
"nn-NO",
"no",
"nqo",
"nqo-GN",
"nso",
"nso-ZA",
"oc",
"oc-FR",
"om",
"om-ET",
"or",
"or-IN",
"pa",
"pa-Arab",
"pa-Arab-PK",
"pa-IN",
"pl",
"pl-PL",
"prs",
"prs-AF",
"ps",
"ps-AF",
"pt",
"pt-AO",
"pt-BR",
"pt-PT",
"qut",
"qut-GT",
"quz",
"quz-BO",
"quz-EC",
"quz-PE",
"rm",
"rm-CH",
"ro",
"ro-MD",
"ro-RO",
"ru",
"ru-RU",
"rw",
"rw-RW",
"sa",
"sa-IN",
"sah",
"sah-RU",
"sd",
"sd-Arab",
"sd-Arab-PK",
"se",
"se-FI",
"se-NO",
"se-SE",
"si",
"si-LK",
"sk",
"sk-SK",
"sl",
"sl-SI",
"sma",
"sma-NO",
"sma-SE",
"smj",
"smj-NO",
"smj-SE",
"smn",
"smn-FI",
"sms",
"sms-FI",
"sn",
"sn-Latn",
"sn-Latn-ZW",
"so",
"so-SO",
"sq",
"sq-AL",
"sr",
"sr-Cyrl",
"sr-Cyrl-BA",
"sr-Cyrl-CS",
"sr-Cyrl-ME",
"sr-Cyrl-RS",
"sr-Latn",
"sr-Latn-BA",
"sr-Latn-CS",
"sr-Latn-ME",
"sr-Latn-RS",
"st",
"st-ZA",
"sv",
"sv-FI",
"sv-SE",
"sw",
"sw-KE",
"syr",
"syr-SY",
"ta",
"ta-IN",
"ta-LK",
"te",
"te-IN",
"tg",
"tg-Cyrl",
"tg-Cyrl-TJ",
"th",
"th-TH",
"ti",
"ti-ER",
"ti-ET",
"tk",
"tk-TM",
"tn",
"tn-BW",
"tn-ZA",
"tr",
"tr-TR",
"ts",
"ts-ZA",
"tt",
"tt-RU",
"tzm",
"tzm-Latn",
"tzm-Latn-DZ",
"tzm-Tfng",
"tzm-Tfng-MA",
"ug",
"ug-CN",
"uk",
"uk-UA",
"ur",
"ur-IN",
"ur-PK",
"uz",
"uz-Cyrl",
"uz-Cyrl-UZ",
"uz-Latn",
"uz-Latn-UZ",
"vi",
"vi-VN",
"wo",
"wo-SN",
"xh",
"xh-ZA",
"yo",
"yo-NG",
"zgh",
"zgh-Tfng",
"zgh-Tfng-MA",
"zh",
"zh-CN",
"zh-Hans",
"zh-Hant",
"zh-HK",
"zh-MO",
"zh-SG",
"zh-TW",
"zu",
"zu-ZA",
"zh-CHS",
"zh-CHT"
};
}
}

View File

@ -1,9 +1,12 @@
// 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 System.Collections.Generic;
using System.Globalization;
using LocalizationWebsite.Models;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Localization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
@ -26,7 +29,19 @@ namespace LocalizationWebsite
{
loggerFactory.AddConsole(minLevel: LogLevel.Warning);
app.UseRequestLocalization();
var options = new RequestLocalizationOptions
{
SupportedCultures = new List<CultureInfo>()
{
new CultureInfo("fr-FR")
},
SupportedUICultures = new List<CultureInfo>()
{
new CultureInfo("fr-FR")
}
};
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
var stringLocalizer = stringLocalizerFactory.Create("Test", location: null);

View File

@ -1,9 +1,12 @@
// 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 System.Collections.Generic;
using System.Globalization;
using LocalizationWebsite.Models;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Localization;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
@ -26,7 +29,19 @@ namespace LocalizationWebsite
{
loggerFactory.AddConsole(minLevel: LogLevel.Warning);
app.UseRequestLocalization();
var options = new RequestLocalizationOptions
{
SupportedCultures = new List<CultureInfo>()
{
new CultureInfo("fr-FR")
},
SupportedUICultures = new List<CultureInfo>()
{
new CultureInfo("fr-FR")
}
};
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
var stringLocalizer = stringLocalizerFactory.Create("Test", location: null);

View File

@ -12,7 +12,7 @@ using Xunit;
namespace Microsoft.Extensions.Localization.Tests
{
public class AccessLanguageHeaderRequestCultureProviderTest
public class AcceptLanguageHeaderRequestCultureProviderTest
{
[Fact]
public async void GetFallbackLanguage_ReturnsFirstNonNullCultureFromSupportedCultureList()
@ -27,7 +27,7 @@ namespace Microsoft.Extensions.Localization.Tests
new CultureInfo("en-US")
}
};
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -52,14 +52,13 @@ namespace Microsoft.Extensions.Localization.Tests
{
var options = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(new CultureInfo("fr-FR")),
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA"),
new CultureInfo("en-US")
}
};
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("fr-FR"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -83,14 +82,13 @@ namespace Microsoft.Extensions.Localization.Tests
{
var options = new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(new CultureInfo("fr-FR")),
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA"),
new CultureInfo("af-ZA")
}
};
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("fr-FR"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -124,7 +122,7 @@ namespace Microsoft.Extensions.Localization.Tests
new CultureInfo("ar-YE")
}
};
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();

View File

@ -1,6 +1,7 @@
// 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 System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
@ -19,11 +20,21 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
}
};
var provider = new CookieRequestCultureProvider();
provider.CookieName = "Preferences";
options.RequestCultureProviders.Insert(0, provider);
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -48,16 +59,26 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
}
};
var provider = new CookieRequestCultureProvider();
provider.CookieName = "Preferences";
options.RequestCultureProviders.Insert(0, provider);
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
Assert.Equal(options.DefaultRequestCulture.Culture.Name, requestCulture.Culture.Name);
Assert.Equal("en-US", requestCulture.Culture.Name);
return Task.FromResult(0);
});
}))
@ -73,16 +94,26 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
}
};
var provider = new CookieRequestCultureProvider();
provider.CookieName = "Preferences";
options.RequestCultureProviders.Insert(0, provider);
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
Assert.Equal(options.DefaultRequestCulture.Culture.Name, requestCulture.Culture.Name);
Assert.Equal("en-US", requestCulture.Culture.Name);
return Task.FromResult(0);
});
}))

View File

@ -2,6 +2,7 @@
// 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 System.Threading.Tasks;
using Microsoft.AspNet.Builder;
@ -21,14 +22,24 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar")
}
};
options.RequestCultureProviders.Insert(0, new CustomRequestCultureProvider(context =>
{
var culture = GetCultureInfoFromUrl(context);
var requestCulture = new RequestCulture(culture);
var culture = GetCultureInfoFromUrl(context, options.SupportedCultures);
var requestCulture = new ProviderCultureResult(culture);
return Task.FromResult(requestCulture);
}));
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -43,18 +54,16 @@ namespace Microsoft.Extensions.Localization.Tests
}
}
private CultureInfo GetCultureInfoFromUrl(HttpContext context)
private string GetCultureInfoFromUrl(HttpContext context, IList<CultureInfo> supportedCultures)
{
var currentCulture = "en";
var segments = context.Request.Path.Value.Split(new char[] { '/' }, StringSplitOptions.RemoveEmptyEntries);
if (segments.Length > 1 && segments[0].Length == 2)
{
if (CultureInfoCache.KnownCultureNames.Contains(segments[0]))
currentCulture = segments[0];
else
throw new InvalidOperationException($"The '{segments[0]}' is invalid culture name.");
currentCulture = segments[0];
}
return CultureInfoCache.GetCultureInfo(currentCulture);
return currentCulture;
}
}
}

View File

@ -1,6 +1,8 @@
// 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 System.Collections.Generic;
using System.Globalization;
using System.Threading.Tasks;
using Microsoft.AspNet.Builder;
using Microsoft.AspNet.Http.Features;
@ -17,8 +19,19 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
app.UseRequestLocalization(options);
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-YE")
}
};
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -40,13 +53,13 @@ namespace Microsoft.Extensions.Localization.Tests
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
Assert.Equal(options.DefaultRequestCulture.Culture.Name, requestCulture.Culture.Name);
Assert.Equal(options.DefaultRequestCulture.UICulture.Name, requestCulture.UICulture.Name);
Assert.Equal("en-US", requestCulture.Culture.Name);
Assert.Equal("en-US", requestCulture.UICulture.Name);
return Task.FromResult(0);
});
}))
@ -57,17 +70,27 @@ namespace Microsoft.Extensions.Localization.Tests
}
[Fact]
public async void GetDefaultCultureInfoIfCultureIsInvalid()
public async void GetDefaultCultureInfoIfCultureIsInSupportedCultureList()
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
app.UseRequestLocalization(options);
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
}
};
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
Assert.Equal(options.DefaultRequestCulture.Culture.Name, requestCulture.Culture.Name);
Assert.Equal("en-US", requestCulture.Culture.Name);
return Task.FromResult(0);
});
}))
@ -78,17 +101,27 @@ namespace Microsoft.Extensions.Localization.Tests
}
[Fact]
public async void GetDefaultCultureInfoIfUICultureIsInvalid()
public async void GetDefaultCultureInfoIfUICultureIsNotInSupportedList()
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
app.UseRequestLocalization(options);
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
}
};
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
var requestCulture = requestCultureFeature.RequestCulture;
Assert.Equal(options.DefaultRequestCulture.UICulture.Name, requestCulture.UICulture.Name);
Assert.Equal("en-US", requestCulture.UICulture.Name);
return Task.FromResult(0);
});
}))
@ -103,8 +136,18 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
app.UseRequestLocalization(options);
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
}
};
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -125,8 +168,18 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
app.UseRequestLocalization(options);
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
}
};
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -147,12 +200,22 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("ar-SA")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("ar-YE")
}
};
var provider = new QueryStringRequestCultureProvider();
provider.QueryStringKey = "c";
provider.UIQueryStringKey = "uic";
options.RequestCultureProviders.Insert(0, provider);
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();
@ -173,12 +236,22 @@ namespace Microsoft.Extensions.Localization.Tests
{
using (var server = TestServer.Create(app =>
{
var options = new RequestLocalizationOptions();
var options = new RequestLocalizationOptions()
{
SupportedCultures = new List<CultureInfo>
{
new CultureInfo("FR")
},
SupportedUICultures = new List<CultureInfo>
{
new CultureInfo("FR")
}
};
var provider = new QueryStringRequestCultureProvider();
provider.QueryStringKey = "c";
provider.UIQueryStringKey = "uic";
options.RequestCultureProviders.Insert(0, provider);
app.UseRequestLocalization(options);
app.UseRequestLocalization(options, defaultRequestCulture: new RequestCulture("en-US"));
app.Run(context =>
{
var requestCultureFeature = context.Features.Get<IRequestCultureFeature>();