您在我的mvc 4应用程序上有一个站点地图,如下所示:
<?xml version="1.0" encoding="utf-8" ?> <mvcSiteMap xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0" xsi:schemaLocation="http://mvcsitemap.codeplex.com/schemas/MvcSiteMap-File-4.0 MvcSiteMapSchema.xsd"> <mvcSiteMapNode title="Users" controller="User" action="Index" area="" preservedRouteParameters="culture,projectid"> <mvcSiteMapNode title="New" controller="User" action="Create" area="" preservedRouteParameters="culture,projectid"/> <mvcSiteMapNode title="Edit" controller="User" action="Edit" area="" preservedRouteParameters="culture,projectid,id"/> <mvcSiteMapNode title="Profile" controller="User" action="Details" area="" preservedRouteParameters="culture,id"/> </mvcSiteMapNode> </mvcSiteMap>
我在用于全球化我的应用程序的另一个项目中有很少的资源文件,我需要在一个单独的项目中使用资源文件,因为它在ddl等少数项目中使用.
如何为我的站点地图实施全球化?
解决方法
我将采用的方法是切换到外部DI,然后实现一个自定义IStringLocalizer类,可以从另一个程序集中读取资源.这是一个有效的例子.我也在GitHub上创建了一个
demo application.
using System; using System.Collections.Specialized; using System.Resources; namespace MvcSiteMapProvider.Globalization { public class ResourceManagerStringLocalizer : IStringLocalizer { public ResourceManagerStringLocalizer( ResourceManager resourceManager ) { if (resourceManager == null) throw new ArgumentNullException("resourceManager"); this.resourceManager = resourceManager; } protected readonly ResourceManager resourceManager; /// <summary> /// Gets the localized text for the supplied attributeName. /// </summary> /// <param name="attributeName">The name of the attribute (as if it were in the original XML file).</param> /// <param name="value">The current object's value of the attribute.</param> /// <param name="enableLocalization">True if localization has been enabled,otherwise false.</param> /// <param name="classKey">The resource key from the ISiteMap class.</param> /// <param name="implicitResourceKey">The implicit resource key.</param> /// <param name="explicitResourceKeys">A <see cref="T:System.Collections.Specialized.NameValueCollection"/> containing the explicit resource keys.</param> /// <returns></returns> public virtual string GetResourceString(string attributeName,string value,bool enableLocalization,string classKey,string implicitResourceKey,NameValueCollection explicitResourceKeys) { if (attributeName == null) { throw new ArgumentNullException("attributeName"); } if (enableLocalization) { string result = string.Empty; if (explicitResourceKeys != null) { string[] values = explicitResourceKeys.GetValues(attributeName); if ((values == null) || (values.Length <= 1)) { result = value; } else if (this.resourceManager.BaseName.Equals(values[0])) { try { result = this.resourceManager.GetString(values[1]); } catch (MissingManifestResourceException) { if (!string.IsNullOrEmpty(value)) { result = value; } } } } if (!string.IsNullOrEmpty(result)) { return result; } } if (!string.IsNullOrEmpty(value)) { return value; } return string.Empty; } } }
然后你可以将它注入你的DI配置模块(显示的StructureMap示例,但任何DI容器都可以).
首先,您需要指定不通过将其添加到excludeTypes变量来自动注册IStringLocalizer接口.
var excludeTypes = new Type[] { // Use this array to add types you wish to explicitly exclude from convention-based // auto-registration. By default all types that either match I[TypeName] = [TypeName] or // I[TypeName] = [TypeName]Adapter will be automatically wired up as long as they don't // have the [ExcludeFromAutoRegistrationAttribute]. // // If you want to override a type that follows the convention,you should add the name // of either the implementation name or the interface that it inherits to this list and // add your manual registration code below. This will prevent duplicate registrations // of the types from occurring. // Example: // typeof(SiteMap),// typeof(SiteMapNodeVisibilityProviderStrategy) typeof(IStringLocalizer) };
然后提供ResourceManagerStringLocalizer(及其依赖项)的显式注册.
// Configure localization // Fully qualified namespace.resourcefile (.resx) name without the extension string resourceBaseName = "SomeAssembly.Resources.Resource1"; // A reference to the assembly where your resources reside. Assembly resourceAssembly = typeof(SomeAssembly.Class1).Assembly; // Register the ResourceManager (note that this is application wide - if you are // using ResourceManager in your DI setup already you may need to use a named // instance or SmartInstance to specify a specific object to inject) this.For<ResourceManager>().Use(() => new ResourceManager(resourceBaseName,resourceAssembly)); // Register the ResourceManagerStringLocalizer (uses the ResourceManger) this.For<IStringLocalizer>().Use<ResourceManagerStringLocalizer>();
那么只需要适当地指定资源.您需要使用Base Name(在本例中为SomeAssembly.Resources.Resource1)启动它们,然后将资源的键指定为第二个参数.
<mvcSiteMapNode title="$resources:SomeAssembly.Resources.Resource1,ContactTitle" controller="Home" action="Contact"/>
要么
[MvcSiteMapNode(Title = "$resources:SomeAssembly.Resources.Resource1,ContactTitle",Controller = "Home",Action = "Contact)]
请注意,使BaseName正确是使其工作的关键.请参阅以下MSDN文档:http://msdn.microsoft.com/en-us/library/yfsz7ac5(v=vs.110).aspx