From ed509f65a23e5d12dfab360a44260ce4234a275b Mon Sep 17 00:00:00 2001 From: Kirthi Krishnamraju Date: Tue, 15 Sep 2015 11:48:38 -0700 Subject: [PATCH] fix #2747: Fix Mvc localization test once dnx support reading resources --- .../MvcLocalizationMvcBuilderExtensions.cs | 49 +++++++++- ...MvcLocalizationMvcCoreBuilderExtensions.cs | 56 ++++++++++- .../Internal/MvcLocalizationServices.cs | 7 +- .../ViewLocalizer.cs | 1 - .../LocalizationTest.cs | 70 ++------------ ...lizationServiceCollectionExtensionsTest.cs | 75 ++++++++++++++- .../ViewLocalizerTest.cs | 4 +- test/WebSites/LocalizationWebSite/Startup.cs | 7 +- .../TestStringLocalizer.cs | 96 ------------------- .../TestStringLocalizerFactory.cs | 52 ---------- 10 files changed, 185 insertions(+), 232 deletions(-) delete mode 100644 test/WebSites/LocalizationWebSite/TestStringLocalizer.cs delete mode 100644 test/WebSites/LocalizationWebSite/TestStringLocalizerFactory.cs diff --git a/src/Microsoft.AspNet.Mvc.Localization/DependencyInjection/MvcLocalizationMvcBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Localization/DependencyInjection/MvcLocalizationMvcBuilderExtensions.cs index bfdc0c2f72..c1e6b44ce5 100644 --- a/src/Microsoft.AspNet.Mvc.Localization/DependencyInjection/MvcLocalizationMvcBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Localization/DependencyInjection/MvcLocalizationMvcBuilderExtensions.cs @@ -1,9 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Microsoft.AspNet.Mvc.Localization.Internal; using Microsoft.AspNet.Mvc.Razor; +using Microsoft.Framework.Localization; namespace Microsoft.Framework.DependencyInjection { @@ -13,7 +14,7 @@ namespace Microsoft.Framework.DependencyInjection public static class MvcLocalizationMvcBuilderExtensions { /// - /// Adds MVC localization to the application. + /// Adds MVC view localization to the application. /// /// The . /// The . @@ -28,7 +29,7 @@ namespace Microsoft.Framework.DependencyInjection } /// - /// Adds MVC localization to the application. + /// Adds MVC view localization to the application. /// /// The . /// The view format for localized views. @@ -42,7 +43,47 @@ namespace Microsoft.Framework.DependencyInjection throw new ArgumentNullException(nameof(builder)); } - MvcLocalizationServices.AddLocalizationServices(builder.Services, format); + AddViewLocalization(builder, format, setupAction: null); + return builder; + } + + /// + /// Adds MVC view localization to the application. + /// + /// The . + /// An action to configure the . + /// The . + public static IMvcBuilder AddViewLocalization( + this IMvcBuilder builder, + Action setupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + AddViewLocalization(builder, LanguageViewLocationExpanderFormat.Suffix, setupAction); + return builder; + } + + /// + /// Adds MVC view localization to the application. + /// + /// The . + /// The view format for localized views. + /// An action to configure the . + /// The . + public static IMvcBuilder AddViewLocalization( + this IMvcBuilder builder, + LanguageViewLocationExpanderFormat format, + Action setupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + MvcLocalizationServices.AddLocalizationServices(builder.Services, format, setupAction); return builder; } } diff --git a/src/Microsoft.AspNet.Mvc.Localization/DependencyInjection/MvcLocalizationMvcCoreBuilderExtensions.cs b/src/Microsoft.AspNet.Mvc.Localization/DependencyInjection/MvcLocalizationMvcCoreBuilderExtensions.cs index 7c67737dcc..8cd1b66f9f 100644 --- a/src/Microsoft.AspNet.Mvc.Localization/DependencyInjection/MvcLocalizationMvcCoreBuilderExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Localization/DependencyInjection/MvcLocalizationMvcCoreBuilderExtensions.cs @@ -1,9 +1,10 @@ -// Copyright (c) .NET Foundation. All rights reserved. +// 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 Microsoft.AspNet.Mvc.Localization.Internal; using Microsoft.AspNet.Mvc.Razor; +using Microsoft.Framework.Localization; namespace Microsoft.Framework.DependencyInjection { @@ -52,11 +53,62 @@ namespace Microsoft.Framework.DependencyInjection throw new ArgumentNullException(nameof(builder)); } + builder.AddViews(); + builder.AddRazorViewEngine(); + + MvcLocalizationServices.AddLocalizationServices(builder.Services, format, setupAction: null); + return builder; + } + + /// + /// Adds MVC localization to the application. + /// + /// The . + /// An action to configure the . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddViewLocalization( + this IMvcCoreBuilder builder, + Action setupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } + + return AddViewLocalization(builder, LanguageViewLocationExpanderFormat.Suffix, setupAction); + } + + /// + /// Adds MVC localization to the application. + /// + /// The . + /// The view format for localized views. + /// An action to configure the . + /// The . + /// + /// Adding localization also adds support for views via + /// and the Razor view engine + /// via . + /// + public static IMvcCoreBuilder AddViewLocalization( + this IMvcCoreBuilder builder, + LanguageViewLocationExpanderFormat format, + Action setupAction) + { + if (builder == null) + { + throw new ArgumentNullException(nameof(builder)); + } builder.AddViews(); builder.AddRazorViewEngine(); - MvcLocalizationServices.AddLocalizationServices(builder.Services, format); + MvcLocalizationServices.AddLocalizationServices(builder.Services, format, setupAction); return builder; } } diff --git a/src/Microsoft.AspNet.Mvc.Localization/Internal/MvcLocalizationServices.cs b/src/Microsoft.AspNet.Mvc.Localization/Internal/MvcLocalizationServices.cs index bc82ebd3fe..6db27e82c2 100644 --- a/src/Microsoft.AspNet.Mvc.Localization/Internal/MvcLocalizationServices.cs +++ b/src/Microsoft.AspNet.Mvc.Localization/Internal/MvcLocalizationServices.cs @@ -1,10 +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; using System.Linq; using Microsoft.AspNet.Mvc.Razor; using Microsoft.Framework.DependencyInjection; using Microsoft.Framework.DependencyInjection.Extensions; +using Microsoft.Framework.Localization; using Microsoft.Framework.WebEncoders; namespace Microsoft.AspNet.Mvc.Localization.Internal @@ -13,7 +15,8 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal { public static void AddLocalizationServices( IServiceCollection services, - LanguageViewLocationExpanderFormat format) + LanguageViewLocationExpanderFormat format, + Action setupAction) { services.Configure( options => @@ -29,7 +32,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal services.TryAdd(ServiceDescriptor.Instance(HtmlEncoder.Default)); } - services.AddLocalization(); + services.AddLocalization(setupAction); } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Mvc.Localization/ViewLocalizer.cs b/src/Microsoft.AspNet.Mvc.Localization/ViewLocalizer.cs index 6bc5512597..943f6faefb 100644 --- a/src/Microsoft.AspNet.Mvc.Localization/ViewLocalizer.cs +++ b/src/Microsoft.AspNet.Mvc.Localization/ViewLocalizer.cs @@ -103,7 +103,6 @@ namespace Microsoft.AspNet.Mvc.Localization { baseName = baseName.Substring(1); } - baseName = _applicationName + "." + baseName; _localizer = _localizerFactory.Create(baseName, _applicationName); } diff --git a/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs b/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs index 143ec75880..0d248be37f 100644 --- a/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs +++ b/test/Microsoft.AspNet.Mvc.FunctionalTests/LocalizationTest.cs @@ -2,12 +2,9 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System.Collections.Generic; -using System.IO; using System.Net.Http; using System.Reflection; -using System.Resources; using System.Threading.Tasks; -using System.Xml.Linq; using Microsoft.AspNet.Testing; using Microsoft.Net.Http.Headers; using Xunit; @@ -87,9 +84,6 @@ mypartial { get { - // Dnx does not support reading resources yet. Coreclr return null value while trying to read resources. - // https://github.com/aspnet/Mvc/issues/2747 -#if DNX451 var expected1 = @"Hello there!! Learn More @@ -97,20 +91,15 @@ Hi John ! You are in 2015 year and today is Thursday"; yield return new[] {"en-GB", expected1 }; - var expected2 = + if (!TestPlatformHelper.IsMono) + { + // https://github.com/aspnet/Mvc/issues/3172 + var expected2 = @"Bonjour! apprendre Encore Plus Salut John ! Vous êtes en 2015 an aujourd'hui est Thursday"; - yield return new[] { "fr", expected2 }; -#else - var expectedCoreClr = -@"Hello there!! -Learn More -Hi"; - yield return new[] {"en-GB", expectedCoreClr }; - yield return new[] {"fr", expectedCoreClr }; -#endif - + yield return new[] { "fr", expected2 }; + } } } @@ -125,14 +114,6 @@ Hi"; "Cookie", new CookieHeaderValue("ASPNET_CULTURE", cultureCookie).ToString()); - if (!value.StartsWith("en")) - { - // Manually generating .resources file since we don't autogenerate .resources file yet. - WriteResourceFile("HomeController." + value + ".resx"); - WriteResourceFile("Views.Shared._LocalizationLayout.cshtml." + value + ".resx"); - } - WriteResourceFile("Views.Home.Locpage.cshtml." + value + ".resx"); - // Act var response = await Client.SendAsync(request); var body = await response.Content.ReadAsStringAsync(); @@ -140,44 +121,5 @@ Hi"; // Assert Assert.Equal(expected, body.Trim()); } - - private void WriteResourceFile(string resxFileName) - { - var resxFilePath = Path.Combine("..", "WebSites", SiteName, "Resources"); - var resxFullFileName = Path.Combine(resxFilePath, resxFileName); - if (File.Exists(resxFullFileName)) - { - using (var fs = File.OpenRead(resxFullFileName)) - { - var document = XDocument.Load(fs); - - var binDirPath = Path.Combine(resxFilePath, "bin"); - if (!Directory.Exists(binDirPath)) - { - Directory.CreateDirectory(binDirPath); - } - - // Put in "bin" sub-folder of resx file - var targetPath = Path.Combine( - binDirPath, - Path.ChangeExtension(resxFileName, ".resources")); - - using (var targetStream = File.Create(targetPath)) - { - var rw = new ResourceWriter(targetStream); - - foreach (var e in document.Root.Elements("data")) - { - var name = e.Attribute("name").Value; - var value = e.Element("value").Value; - - rw.AddResource(name, value); - } - - rw.Generate(); - } - } - } - } } } diff --git a/test/Microsoft.AspNet.Mvc.Localization.Test/Internal/MvcLocalizationServiceCollectionExtensionsTest.cs b/test/Microsoft.AspNet.Mvc.Localization.Test/Internal/MvcLocalizationServiceCollectionExtensionsTest.cs index e06657a01d..c737bd9273 100644 --- a/test/Microsoft.AspNet.Mvc.Localization.Test/Internal/MvcLocalizationServiceCollectionExtensionsTest.cs +++ b/test/Microsoft.AspNet.Mvc.Localization.Test/Internal/MvcLocalizationServiceCollectionExtensionsTest.cs @@ -27,7 +27,8 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal // Act MvcLocalizationServices.AddLocalizationServices( collection, - LanguageViewLocationExpanderFormat.Suffix); + LanguageViewLocationExpanderFormat.Suffix, + setupAction: null); // Assert Assert.Collection(collection, @@ -93,7 +94,8 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal MvcLocalizationServices.AddLocalizationServices( collection, - LanguageViewLocationExpanderFormat.Suffix); + LanguageViewLocationExpanderFormat.Suffix, + setupAction: null); // Assert Assert.Collection(collection, @@ -158,7 +160,8 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal // Act MvcLocalizationServices.AddLocalizationServices( collection, - LanguageViewLocationExpanderFormat.Suffix); + LanguageViewLocationExpanderFormat.Suffix, + setupAction: null); collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer<>), typeof(TestHtmlLocalizer<>))); collection.Add(ServiceDescriptor.Transient(typeof(IHtmlLocalizer), typeof(TestViewLocalizer))); @@ -235,6 +238,72 @@ namespace Microsoft.AspNet.Mvc.Localization.Internal Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); }); } + + [Fact] + public void AddLocalizationServicesWithLocalizationOptions_AddsNeededServices() + { + // Arrange + var collection = new ServiceCollection(); + + // Act + MvcLocalizationServices.AddLocalizationServices( + collection, + LanguageViewLocationExpanderFormat.Suffix, + options => options.ResourcesPath = "Resources"); + + // Assert + Assert.Collection(collection, + service => + { + Assert.Equal(typeof(IConfigureOptions), service.ServiceType); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + }, + service => + { + Assert.Equal(typeof(IHtmlLocalizerFactory), service.ServiceType); + Assert.Equal(typeof(HtmlLocalizerFactory), service.ImplementationType); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + }, + service => + { + Assert.Equal(typeof(IHtmlLocalizer<>), service.ServiceType); + Assert.Equal(typeof(HtmlLocalizer<>), service.ImplementationType); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + }, + service => + { + Assert.Equal(typeof(IViewLocalizer), service.ServiceType); + Assert.Equal(typeof(ViewLocalizer), service.ImplementationType); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + }, + service => + { + Assert.Equal(typeof(IHtmlEncoder), service.ServiceType); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + }, + service => + { + Assert.Equal(typeof(IStringLocalizerFactory), service.ServiceType); + Assert.Equal(typeof(ResourceManagerStringLocalizerFactory), service.ImplementationType); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + }, + service => + { + Assert.Equal(typeof(IStringLocalizer<>), service.ServiceType); + Assert.Equal(typeof(StringLocalizer<>), service.ImplementationType); + Assert.Equal(ServiceLifetime.Transient, service.Lifetime); + }, + service => + { + Assert.Equal(typeof(IConfigureOptions), service.ServiceType); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + }, + service => + { + Assert.Equal(typeof(IOptions<>), service.ServiceType); + Assert.Equal(ServiceLifetime.Singleton, service.Lifetime); + }); + } } public class TestViewLocalizer : IViewLocalizer diff --git a/test/Microsoft.AspNet.Mvc.Localization.Test/ViewLocalizerTest.cs b/test/Microsoft.AspNet.Mvc.Localization.Test/ViewLocalizerTest.cs index d7f2e5f3ea..62e8e84c2c 100644 --- a/test/Microsoft.AspNet.Mvc.Localization.Test/ViewLocalizerTest.cs +++ b/test/Microsoft.AspNet.Mvc.Localization.Test/ViewLocalizerTest.cs @@ -27,7 +27,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Test htmlLocalizer.Setup(h => h["Hello"]).Returns(localizedString); var htmlLocalizerFactory = new Mock(); - htmlLocalizerFactory.Setup(h => h.Create("TestApplication.example", "TestApplication")) + htmlLocalizerFactory.Setup(h => h.Create("example", "TestApplication")) .Returns(htmlLocalizer.Object); var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object); @@ -60,7 +60,7 @@ namespace Microsoft.AspNet.Mvc.Localization.Test var htmlLocalizerFactory = new Mock(); htmlLocalizerFactory.Setup( - h => h.Create("TestApplication.example", "TestApplication")).Returns(htmlLocalizer.Object); + h => h.Create("example", "TestApplication")).Returns(htmlLocalizer.Object); var viewLocalizer = new ViewLocalizer(htmlLocalizerFactory.Object, applicationEnvironment.Object); diff --git a/test/WebSites/LocalizationWebSite/Startup.cs b/test/WebSites/LocalizationWebSite/Startup.cs index 70fbd3666f..0ae5506883 100644 --- a/test/WebSites/LocalizationWebSite/Startup.cs +++ b/test/WebSites/LocalizationWebSite/Startup.cs @@ -3,7 +3,6 @@ using Microsoft.AspNet.Builder; using Microsoft.Framework.DependencyInjection; -using Microsoft.Framework.Localization; namespace LocalizationWebSite { @@ -11,11 +10,7 @@ namespace LocalizationWebSite { public void ConfigureServices(IServiceCollection services) { - services.AddMvc().AddViewLocalization(); - - // Adding TestStringLocalizerFactory since ResourceStringLocalizerFactory uses ResourceManager. DNX does - // not support getting non-enu resources from ResourceManager yet. - services.AddSingleton(); + services.AddMvc().AddViewLocalization(options => options.ResourcesPath = "Resources"); } public void Configure(IApplicationBuilder app) diff --git a/test/WebSites/LocalizationWebSite/TestStringLocalizer.cs b/test/WebSites/LocalizationWebSite/TestStringLocalizer.cs deleted file mode 100644 index be3d4a2fbd..0000000000 --- a/test/WebSites/LocalizationWebSite/TestStringLocalizer.cs +++ /dev/null @@ -1,96 +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. - -using System; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Resources; -using Microsoft.Framework.Localization; -using Microsoft.Framework.Localization.Internal; - -namespace LocalizationWebSite -{ - public class TestStringLocalizer : IStringLocalizer - { - private readonly IResourceNamesCache _resourceNamesCache; - private ResourceManager _resourceManager; - private readonly AssemblyWrapper _resourceAssemblyWrapper; - private readonly string _resourceBaseName; - private string _applicationBasePath; - - public TestStringLocalizer(ResourceManager resourceManager, - AssemblyWrapper resourceAssembly, - string baseName, - IResourceNamesCache resourceNamesCache, - string applicationBasePath) - { - _resourceAssemblyWrapper = resourceAssembly; - _resourceManager = resourceManager; - _resourceBaseName = baseName; - _resourceNamesCache = resourceNamesCache; - _applicationBasePath = applicationBasePath; - } - - public virtual LocalizedString this[string name] - { - get - { - var value = GetStringSafely(name, null); - return new LocalizedString(name, value ?? name, resourceNotFound: value == null); - } - } - - public virtual LocalizedString this[string name, params object[] arguments] - { - get - { - var format = GetStringSafely(name, null); - var value = string.Format(format ?? name, arguments); - return new LocalizedString(name, value, resourceNotFound: format == null); - } - } - - public IStringLocalizer WithCulture(CultureInfo culture) - { - return new TestStringLocalizer(_resourceManager, - _resourceAssemblyWrapper, - _resourceBaseName, - _resourceNamesCache, - _applicationBasePath); - } - - public virtual IEnumerable GetAllStrings(bool includeAncestorCultures) => - GetAllStrings(includeAncestorCultures, CultureInfo.CurrentUICulture); - - protected IEnumerable GetAllStrings(bool includeAncestorCultures, CultureInfo culture) - { - throw new NotImplementedException(); - } - - protected string GetStringSafely(string name, CultureInfo culture) - { - var resourceValue = string.Empty; -#if DNX451 - var cultureName = (culture ?? CultureInfo.CurrentUICulture).Name; - var resourceFile = _resourceManager.BaseName.Substring(_resourceManager.BaseName.IndexOf('.') + 1) + "." + cultureName; - var filePath = Path.Combine(_applicationBasePath, "Resources", "bin"); - - if (File.Exists(Path.Combine(filePath, resourceFile + ".resources"))) - { - _resourceManager = ResourceManager.CreateFileBasedResourceManager(resourceFile, filePath, null); - } -#endif - try - { - // retrieve the value of the specified key - resourceValue = _resourceManager.GetString(name); - } - catch (MissingManifestResourceException) - { - return name; - } - return resourceValue; - } - } -} diff --git a/test/WebSites/LocalizationWebSite/TestStringLocalizerFactory.cs b/test/WebSites/LocalizationWebSite/TestStringLocalizerFactory.cs deleted file mode 100644 index 3ece76b6d6..0000000000 --- a/test/WebSites/LocalizationWebSite/TestStringLocalizerFactory.cs +++ /dev/null @@ -1,52 +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. - -using System; -using System.Reflection; -using System.Resources; -using Microsoft.Framework.Localization; -using Microsoft.Framework.Localization.Internal; -using Microsoft.Dnx.Runtime; - -namespace LocalizationWebSite -{ - public class TestStringLocalizerFactory : IStringLocalizerFactory - { - private readonly IApplicationEnvironment _applicationEnvironment; - private readonly IResourceNamesCache _resourceNamesCache = new ResourceNamesCache(); - - public TestStringLocalizerFactory(IApplicationEnvironment applicationEnvironment) - { - _applicationEnvironment = applicationEnvironment; - } - - public IStringLocalizer Create(Type resourceSource) - { - var typeInfo = resourceSource.GetTypeInfo(); - var assembly = typeInfo.Assembly; - var baseName = typeInfo.FullName; - return new TestStringLocalizer( - new ResourceManager(resourceSource), - new AssemblyWrapper(assembly), - baseName, - _resourceNamesCache, - _applicationEnvironment.ApplicationBasePath); - } - - public IStringLocalizer Create(string baseName, string location) - { - if (string.IsNullOrEmpty(location)) - { - location = _applicationEnvironment.ApplicationName; - } - var assembly = Assembly.Load(new AssemblyName(location)); - - return new TestStringLocalizer( - new ResourceManager(baseName, assembly), - new AssemblyWrapper(assembly), - baseName, - _resourceNamesCache, - _applicationEnvironment.ApplicationBasePath); - } - } -}