diff --git a/samples/LocalizationSample/Startup.cs b/samples/LocalizationSample/Startup.cs index ef6e638b22..8f1bb0d0e6 100644 --- a/samples/LocalizationSample/Startup.cs +++ b/samples/LocalizationSample/Startup.cs @@ -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 SR) { - var supportedCultures = new List - { - 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) => { diff --git a/src/Microsoft.AspNetCore.Localization/ApplicationBuilderExtensions.cs b/src/Microsoft.AspNetCore.Localization/ApplicationBuilderExtensions.cs index 4e55497cb2..9f2a0dac59 100644 --- a/src/Microsoft.AspNetCore.Localization/ApplicationBuilderExtensions.cs +++ b/src/Microsoft.AspNetCore.Localization/ApplicationBuilderExtensions.cs @@ -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(Options.Create(options)); } + + /// + /// Adds the to automatically set culture information for + /// requests based on information provided by the client. + /// + /// The . + /// + /// + /// This will going to instantiate a new that doesn't come from the services. + /// + /// The . + public static IApplicationBuilder UseRequestLocalization( + this IApplicationBuilder app, + Action 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(Options.Create(options)); + } + + /// + /// Adds the to automatically set culture information for + /// requests based on information provided by the client. + /// + /// The . + /// The culture names to be added by the application, which is represents both supported cultures and UI cultures. + /// The . + /// + /// Note that the first culture is the default culture name. + /// + 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(Options.Create(options)); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNetCore.Localization/Properties/Resources.Designer.cs b/src/Microsoft.AspNetCore.Localization/Properties/Resources.Designer.cs new file mode 100644 index 0000000000..581e3cda17 --- /dev/null +++ b/src/Microsoft.AspNetCore.Localization/Properties/Resources.Designer.cs @@ -0,0 +1,37 @@ +// +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); + + /// + /// Please provide at least one culture. + /// + 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; + } + } +} diff --git a/src/Microsoft.AspNetCore.Localization/RequestLocalizationOptions.cs b/src/Microsoft.AspNetCore.Localization/RequestLocalizationOptions.cs index a3a39b4fcb..16776364f0 100644 --- a/src/Microsoft.AspNetCore.Localization/RequestLocalizationOptions.cs +++ b/src/Microsoft.AspNetCore.Localization/RequestLocalizationOptions.cs @@ -109,5 +109,52 @@ namespace Microsoft.AspNetCore.Builder /// /// public IList RequestCultureProviders { get; set; } + + /// + /// Adds the set of the supported cultures by the application. + /// + /// The cultures to be added. + /// The . + public RequestLocalizationOptions AddSupportedCultures(params string[] cultures) + { + var supportedCultures = new List(); + + foreach (var culture in cultures) + { + supportedCultures.Add(new CultureInfo(culture)); + } + + SupportedCultures = supportedCultures; + return this; + } + + /// + /// Adds the set of the supported UI cultures by the application. + /// + /// The UI cultures to be added. + /// The . + public RequestLocalizationOptions AddSupportedUICultures(params string[] uiCultures) + { + var supportedUICultures = new List(); + foreach (var culture in uiCultures) + { + supportedUICultures.Add(new CultureInfo(culture)); + } + + SupportedUICultures = supportedUICultures; + return this; + } + + /// + /// Set the default culture which is used by the application when a supported culture could not be determined by + /// one of the configured s. + /// + /// The default culture to be set. + /// The . + public RequestLocalizationOptions SetDefaultCulture(string defaultCulture) + { + DefaultRequestCulture = new RequestCulture(defaultCulture); + return this; + } } } diff --git a/src/Microsoft.AspNetCore.Localization/Resources.resx b/src/Microsoft.AspNetCore.Localization/Resources.resx new file mode 100644 index 0000000000..17ef00c8c6 --- /dev/null +++ b/src/Microsoft.AspNetCore.Localization/Resources.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Please provide at least one culture. + + \ No newline at end of file diff --git a/test/LocalizationWebsite/StartupBuilderAPIs.cs b/test/LocalizationWebsite/StartupBuilderAPIs.cs new file mode 100644 index 0000000000..4dd4ec41e3 --- /dev/null +++ b/test/LocalizationWebsite/StartupBuilderAPIs.cs @@ -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 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(); + var requestCulture = requestCultureFeature.RequestCulture; + await context.Response.WriteAsync(customerStringLocalizer["Hello"]); + }); + } + } +} diff --git a/test/Microsoft.AspNetCore.Localization.FunctionalTests/LocalizationTest.cs b/test/Microsoft.AspNetCore.Localization.FunctionalTests/LocalizationTest.cs index f0a0a94228..5f09115be2 100644 --- a/test/Microsoft.AspNetCore.Localization.FunctionalTests/LocalizationTest.cs +++ b/test/Microsoft.AspNetCore.Localization.FunctionalTests/LocalizationTest.cs @@ -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); diff --git a/test/Microsoft.AspNetCore.Localization.Tests/RequestLocalizationOptionsTest.cs b/test/Microsoft.AspNetCore.Localization.Tests/RequestLocalizationOptionsTest.cs index 12c6f0aca6..c33a673321 100644 --- a/test/Microsoft.AspNetCore.Localization.Tests/RequestLocalizationOptionsTest.cs +++ b/test/Microsoft.AspNetCore.Localization.Tests/RequestLocalizationOptionsTest.cs @@ -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;