Глобализация в MVCSiteMapProvider

Привет, у меня есть карта сайта в моем приложении 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.

Как я могу реализовать глобализацию моей карты сайта?


person jcmordan    schedule 04.08.2014    source источник


Ответы (1)


Подход, который я бы выбрал, состоял бы в том, чтобы переключиться на внешний DI, а затем реализовать собственный класс IStringLocalizer, который может считывать ресурсы из другой сборки. Вот рабочий пример. Я также создал демонстрационное приложение на GitHub.

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).

Прежде всего, вам нужно указать, чтобы интерфейс 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>();

Тогда просто нужно правильно указать ресурсы. Вам нужно начать их с базового имени (в данном случае SomeAssembly.Resources.Resource1), а затем указать ключ ресурса в качестве второго аргумента.

<mvcSiteMapNode title="$resources:SomeAssembly.Resources.Resource1,ContactTitle" controller="Home" action="Contact"/>

Or

[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

person NightOwl888    schedule 05.08.2014
comment
Спасибо, у вас есть рабочий пример с этим решением? - извините, я видел пример на github - person jcmordan; 05.08.2014
comment
Привет, у меня возникла эта ошибка при запуске приложения: объект ресурса с именем класса «Test.Resources.Resources» и ключом «SiteMap_New» не найден. Мой ресурс находится в проекте с именем Test.Resources, и есть все файлы ресурсов, такие как Resoruces.resx, Resources.es.resx, Class1.cs и т. Д. - person jcmordan; 06.08.2014
comment
Имя основано на пространстве имен, а не на имени сборки. Это должно быть полное пространство имен + имя файла ресурсов. См. stackoverflow.com/questions/27757/. Еще одна причина, которая может вызвать это, - если ваша конфигурация DI неправильно заменила экземпляр IStringLocalizer - он должен аварийно завершить работу, если вы прокомментируете строку For ‹IStringLocalizer› () в качестве теста. - person NightOwl888; 06.08.2014
comment
Спасибо, успешно реализую это решение! - person jcmordan; 06.08.2014