我正在为已经在ASP.NET MVC 5中发布的网站配置本地化。
我所遵循的将本地化集成到我的网站的指南来自codeproject,我发现它非常好:https://www.codeproject.com/Articles/1095786/Route-friendly-localization-of-ASP-NET-MVC
现在解释这个问题,每当我加载没有路径路径的主页索引http://www.example.com/
时,它将重定向到正确的语言http://www.example.com/en
,这是所需的结果。
我的网站网址格式为http://www.example.com/controller/action
。每当我访问http://www.example.com/controller/
时,它现在会将我重定向回http://www.example.com/en
而不是http://www.example.com/en/controller/index
。当我尝试输入http://www.example.com/controller/action
时,它会抛出404错误而不是http://www.example.com/en/controller/action
。
我认为问题出在GetLocalistedUrl
文件的LocalizationHelper.cs
函数中。
public static string GetLocalisedUrl(Uri initialUri, IList<string> controllersNames, IList<string> userLangs)
{
var res = string.Empty;
var supportedLocales = GetSupportedLocales();
var origUrl = initialUri;
// Dicide requested url to parts
var cleanedSegments = origUrl.Segments.Select(X => X.Replace("/", "")).ToList();
// Check is already supported locale defined in route
// cleanedSegments[0] is empty string, so lang parameter will be in [1] url segment
var isLocaleDefined = cleanedSegments.Count > 1 && supportedLocales.Contains(cleanedSegments[1]);
// does request need to be changed
var isRequestPathToHandle =
// Url has controller's name part
(cleanedSegments.Count > 1 && cleanedSegments.Intersect(controllersNames).Count() > 0) ||
// This condition is for default (initial) route
(cleanedSegments.Count == 1) ||
// initial route with lang parameter that is not supported -> need to change it
(cleanedSegments.Count == 2 && !supportedLocales.Contains(cleanedSegments[1]));
if (!isLocaleDefined && isRequestPathToHandle)
{
var langVal = "";
// Get user preffered language from Accept-Language header
if (userLangs != null && userLangs.Count > 0)
{
// For our locale name approach we'll take only first part of lang-locale definition
var splitted = userLangs[0].Split(new char[] { '-' });
langVal = splitted[0];
}
// If we don't support requested language - then redirect to requested page with default language
if (!supportedLocales.Contains(langVal))
langVal = supportedLocales[0];
var normalisedPathAndQuery = origUrl.PathAndQuery;
if ((cleanedSegments.Count > 2 &&
!controllersNames.Contains(cleanedSegments[1]) &&
controllersNames.Contains(cleanedSegments[2])) ||
(cleanedSegments.Count == 2) && (!controllersNames.Contains(cleanedSegments[1])))
{
// Second segment contains lang parameter, third segment contains controller name
cleanedSegments.RemoveAt(1);
// Remove wrong locale name from initial Uri
normalisedPathAndQuery = string.Join("/", cleanedSegments) + origUrl.Query;
}
// Finally, create new uri with language loocale
res = string.Format("{0}://{1}:{2}/{3}{4}", origUrl.Scheme, origUrl.Host, origUrl.Port, langVal.ToLower(), normalisedPathAndQuery);
}
return res;
}
在创建的IHttpModule扩展中调用该函数。
public class LangQueryAppenderModule : IHttpModule
{
/// <summary>
/// List of supported locales
/// </summary>
private readonly IList<string> _supportedLocales;
/// <summary>
/// We need to have controllers list to correctly handle situations
/// when target method name is missed
/// </summary>
private readonly IList<string> _controllersNamesList;
public LangQueryAppenderModule()
{
// Get list of supported locales
_supportedLocales = LocalizationHelper.GetSupportedLocales();
// Get controllers list of current project by reflection
var asmPath = HttpContext.Current.Server.MapPath("~/bin/Central.dll");
Assembly asm = Assembly.LoadFile(asmPath);
var controllerTypes = asm.GetTypes()
.Where(type => typeof(Controller).IsAssignableFrom(type));
_controllersNamesList = new List<string>();
foreach (var controllerType in controllerTypes)
{
var fullName = controllerType.Name;
// We need only name part of Controller class that is used in route
_controllersNamesList.Add(fullName.Substring(0, fullName.Length - "Controller".Length));
}
}
// In the Init function, register for HttpApplication
// events by adding your handlers.
public void Init(HttpApplication application)
{
application.BeginRequest += (new EventHandler(this.Application_BeginRequest));
}
private void Application_BeginRequest(Object source, EventArgs e)
{
try
{
HttpApplication app = (HttpApplication)source;
HttpContext ctx = app.Context;
// We will redirect to url with defined locale only in case for HTTP GET verb
// cause we assume that all requests with other verbs will be called from site directly
// where all the urls created with URLHelper, so it complies with routing rules and will contain "lang" parameter
if (string.Equals(ctx.Request.HttpMethod, "GET", StringComparison.OrdinalIgnoreCase))
{
var localisedUri = LocalizationHelper.GetLocalisedUrl(ctx.Request.Url, _controllersNamesList, ctx.Request.UserLanguages);
if (!string.IsNullOrEmpty(localisedUri))
// Perform redirect action to changed url if it exists
ctx.Response.Redirect(localisedUri);
}
}
catch (Exception)
{
// Some logging logic could be here
}
}
public void Dispose() { }
}
答案 0 :(得分:0)
我修复了这个问题,因为我的一些超链接有上限,我必须在任何控制器名称比较上使用string.ToLower()
,以确保找到匹配的控制器。
public static string GetLocalisedUrl(Uri initialUri, IList<string> controllersNames, IList<string> userLangs)
{
var res = string.Empty;
var supportedLocales = GetSupportedLocales();
var origUrl = initialUri;
// Dicide requested url to parts
var cleanedSegments = origUrl.Segments.Select(X => X.Replace("/", "")).ToList();
// Check is already supported locale defined in route
// cleanedSegments[0] is empty string, so lang parameter will be in [1] url segment
var isLocaleDefined = cleanedSegments.Count > 1 && supportedLocales.Contains(cleanedSegments[1]);
cleanedSegments = cleanedSegments.ConvertAll(d => d.ToLower());
// does request need to be changed
var isRequestPathToHandle =
// Url has controller's name part
(cleanedSegments.Count > 1 && cleanedSegments.Intersect(controllersNames).Count() > 0) ||
// This condition is for default (initial) route
(cleanedSegments.Count == 1) ||
// initial route with lang parameter that is not supported -> need to change it
(cleanedSegments.Count == 2 && !supportedLocales.Contains(cleanedSegments[1]));
if (!isLocaleDefined && isRequestPathToHandle)
{
var langVal = "";
// Get user preffered language from Accept-Language header
if (userLangs != null && userLangs.Count > 0)
{
// For our locale name approach we'll take only first part of lang-locale definition
var splitted = userLangs[0].Split(new char[] { '-' });
langVal = splitted[0];
}
// If we don't support requested language - then redirect to requested page with default language
if (!supportedLocales.Contains(langVal))
langVal = supportedLocales[0];
var normalisedPathAndQuery = origUrl.PathAndQuery;
if ((cleanedSegments.Count > 2 &&
!controllersNames.Contains(cleanedSegments[1].ToLower()) &&
controllersNames.Contains(cleanedSegments[2].ToLower())) ||
(cleanedSegments.Count == 2) && (!controllersNames.Contains(cleanedSegments[1])))
{
// Second segment contains lang parameter, third segment contains controller name
cleanedSegments.RemoveAt(1);
// Remove wrong locale name from initial Uri
normalisedPathAndQuery = string.Join("/", cleanedSegments) + origUrl.Query;
}
// Finally, create new uri with language loocale
res = string.Format("{0}://{1}:{2}/{3}{4}", origUrl.Scheme, origUrl.Host, origUrl.Port, langVal.ToLower(), normalisedPathAndQuery.ToLower());
}
return res;
}