【问题标题】:Globalization in MVCSiteMapProviderMVSiteMapProvider 中的全球化
【发布时间】:2014-08-04 20:02:43
【问题描述】:

您好,我的 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,projectid,id"/>            
    </mvcSiteMapNode>
</mvcSiteMap>

我在另一个项目中用于全球化我的应用程序的资源文件很少,我需要将资源文件放在一个单独的项目中,因为它用于 ddl 等少数项目。

如何为我的站点地图实现全球化?

【问题讨论】:

    标签: asp.net-mvc sitemap globalization breadcrumbs mvcsitemapprovider


    【解决方案1】:

    我将采用的方法是切换到外部 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 配置模块(显示了结构图示例,但任何 DI 容器都可以)。

    首先,您需要通过将 IStringLocalizer 接口添加到 excludeTypes 变量中来指定不自动注册它。

    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

    【讨论】:

    • 谢谢,你有这个解决方案的工作示例吗? -- 对不起,我在 github 上看到了这个例子
    • 您好,当您运行我的应用程序时出现此错误:找不到类名为“Test.Resources.Resources”和键“SiteMap_New”的资源对象。我的资源在名为 Test.Resources 的项目中,里面有 Resoruces.resx、Resources.es.resx、Class1.cs 等所有资源文件。
    • 名称基于命名空间,而不是程序集名称。它必须是完全限定的命名空间 + 资源文件的名称。见stackoverflow.com/questions/27757/…。可能导致这种情况的另一件事是,如果您的 DI 配置没有正确替换 IStringLocalizer 实例 - 如果您将 For() 行注释为测试,它应该会崩溃。
    • 谢谢,我成功实现了这个解决方案!
    猜你喜欢
    • 2020-08-20
    • 2010-11-18
    • 2013-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-27
    • 1970-01-01
    相关资源
    最近更新 更多