已经实现了更简单的方式二, [推荐]
https://community.sitecore.net/technical_blogs/b/sitecorejohn_blog/posts/repost-overriding-sitecore-39-s-logic-to-determine-the-context-language
https://community.sitecore.net/technical_blogs/b/sitecorejohn_blog/posts/prevent-the-sitecore-asp-net-cms-from-interpreting-url-path-prefixes-as-language-names
Sitecore 支持多语言, 确定上下文语言的默认逻辑是使用以下面的变量:
sc_lang
查询字符串参数 web.config
中指定的DefaultLanguage
设置 今天我们主要说明一下, 如果自定义URL中的语言前缀, Sitecore 默认语言前缀: en
, zh-CN
, zh-TW
, it-IT
...
以简体中文为例: Sitecore默认URL路径中都会包含zh-CN
, http://www.xxx.com/zh-CN/about
把zh-CN
替换为cn
, 访问http://www.xxx.com/cn/about
能够正常显示简体中文页面.
实现上面的目标, 要自定义几个pipeline.
Sitecore.Links.LinkProvider
中的GetItemUrl
方法, 在生成的URL中把zh-CN
替换为cn
.Sitecore.Pipelines.HttpRequest.LanguageResolver
pipeline. 把客户端请求URL中的cn
转换为zh-CN
语言.ItemResolver
继承自Sitecore.Pipelines.HttpRequest.HttpRequestProcessor
, 根据请求的URL路径找到相应的Sitecore Item.CustomLinkProvider
代码片段public class CustomLinkProvider : Sitecore.Links.LinkProvider
{
public override string GetItemUrl(Item item, UrlOptions options)
{
Assert.ArgumentNotNull(item, "item");
var url = base.GetItemUrl(item, options);
//LanguageResolver alias
if (LanguageResolver.LanguageMappings.ContainsKey(Context.Site?.Name ?? string.Empty))
{
var alias = LanguageResolver.LanguageMappings[Context.Site.Name];
foreach (var key in alias.Keys)
{
if (string.IsNullOrEmpty(alias[key]))
continue;
var lang = alias[key];
if (!new Regex($"^/{lang}(/.*)?$").IsMatch(url))
continue;
url = new Regex($"^/{lang}(/|$)").Replace(url, $"/{key}/");
break;
}
}
return url;
}
}
CustomLinkProvider
配置片段<linkManager set:defaultProvider="CustomLinkProvider">
<providers>
<add name="CustomLinkProvider">
<patch:attribute name="type">Sitecore.Custom.Website.Pipelines.CustomLinkProvider, Sitecore.Custom.Website</patch:attribute>
<patch:attribute name="languageEmbedding">always</patch:attribute>
<patch:attribute name="lowercaseUrls">true</patch:attribute>
</add>
</providers>
</linkManager>
LanguageResolver
代码public class LanguageResolver : Sitecore.Pipelines.HttpRequest.LanguageResolver
{
public static Dictionary<string, Dictionary<string, string>> LanguageMappings { get; } = new Dictionary<string, Dictionary<string, string>>();
public void AddLanguageMapping(XmlNode node)
{
var website = node?.Attributes?["name"]?.Value;
if (string.IsNullOrEmpty(website))
{
return;
}
if (!LanguageMappings.ContainsKey(website))
{
LanguageMappings.Add(website, new Dictionary<string, string>());
}
var mapping = LanguageMappings[website];
foreach (XmlNode childNode in node.ChildNodes)
{
var alias = childNode?.Attributes?["alias"]?.Value;
var culture = childNode?.Attributes?["culture"]?.Value;
if (string.IsNullOrEmpty(alias) || string.IsNullOrEmpty(culture) )
{
continue;
}
if (!mapping.ContainsKey(alias))
{
mapping.Add(alias, culture);
}
}
}
public override void Process(HttpRequestArgs args)
{
var language = GetCustomLanguage(HttpContext.Current.Request);
if (language == null)
{
base.Process(args);
return;
}
Sitecore.Context.Language = language;
Tracer.Info("Language changed to \"" + language.Name + "\" as custon language alias.");
}
private Language GetCustomLanguage(HttpRequest request)
{
var languageName = string.Empty;
//don't contain current site, return
if (!LanguageMappings.ContainsKey(Context.Site?.Name ?? string.Empty))
{
return null;
}
//get site mapping
var mapping = LanguageMappings[Context.Site.Name];
//get the language name from url
var requestUrl = request.Url.AbsolutePath;
if (requestUrl.Length == 1)
languageName = "en";
var alias = requestUrl.Split('/')[1];
if (mapping == null || !mapping.ContainsKey(alias))
return null;
languageName = mapping[alias];
Language result;
return Language.TryParse(languageName, out result) ? result : null;
}
}
LanguageResolver
配置片段<httpRequestBegin>
<processor type="Sitecore.Habitat.Website.Pipelines.LanguageResolver, Sitecore.Habitat.Website" patch:instead="processor[@type='Sitecore.Pipelines.HttpRequest.LanguageResolver, Sitecore.Kernel']" >
<settings hint="raw:AddLanguageMapping">
<website name="website">
<mapping alias="cn" culture="zh-cn" />
</website>
</settings>
</processor>
</httpRequestBegin>
ItemResolver
代码片段public class ItemResolver : HttpRequestProcessor
{
public override void Process(HttpRequestArgs args)
{
if (Sitecore.Context.Item != null)
{
return;
}
if (!LanguageResolver.LanguageMappings.ContainsKey(Context.Site?.Name ?? string.Empty))
{
return;
}
var mapping = LanguageResolver.LanguageMappings[Context.Site.Name];
if (HttpContext.Current != null && !string.IsNullOrWhiteSpace(HttpContext.Current.Request.FilePath))
{
string prefix = WebUtil.ExtractLanguageName(HttpContext.Current.Request.FilePath);
if (!string.IsNullOrWhiteSpace(prefix) && mapping.ContainsKey(prefix) && args.Url.ItemPath.StartsWith($"{Context.Site.StartPath}/{prefix}"))
{
var item = Sitecore.Context.Database.GetItem(args.Url.ItemPath.ReplaceFirst($"{Context.Site.StartPath}/{prefix}", Context.Site.RootPath), Sitecore.Context.Language, Data.Version.Latest);
if(item != null)
{
Sitecore.Context.Item = item;
Sitecore.Diagnostics.Log.Info($"Item full path: {item.Paths.FullPath}", this);
}
}
}
}
}
ItemResolver
配置片段<httpRequestBegin>
<processor type="Sitecore.Habitat.Website.Pipelines.ItemResolver, Sitecore.Habitat.Website" patch:after="processor[@type='Sitecore.Pipelines.HttpRequest.ItemResolver, Sitecore.Kernel']" />
</httpRequestBegin>
截图如下:
正常到这里就应该结束了, 不过还有一点需要说明一下, 如果把zh-CN
替换为zh
还需要再多一个步骤.
这是因为Sitecore, 可以正常解析zh语言,它也是中文, 但又有区别于zh-CN
, 这没有仔细研究.
以下是调试信息:
zh
Sitecore.Context.Language.CultureInfo
{zh}
Calendar: {System.Globalization.GregorianCalendar}
CompareInfo: {CompareInfo - zh}
CultureTypes: NeutralCultures | InstalledWin32Cultures
DateTimeFormat: {System.Globalization.DateTimeFormatInfo}
DisplayName: "Chinese"
EnglishName: "Chinese"
IetfLanguageTag: "zh"
IsNeutralCulture: true
IsReadOnly: true
KeyboardLayoutId: 30724
LCID: 30724
Name: "zh"
NativeName: "中文"
NumberFormat: {System.Globalization.NumberFormatInfo}
OptionalCalendars: {System.Globalization.Calendar[1]}
Parent: {}
TextInfo: {TextInfo - zh}
ThreeLetterISOLanguageName: "zho"
ThreeLetterWindowsLanguageName: "CHS"
TwoLetterISOLanguageName: "zh"
UseUserOverride: false
zh-CN
Sitecore.Context.Language.CultureInfo
{zh-CN}
Calendar: {System.Globalization.GregorianCalendar}
CompareInfo: {CompareInfo - zh-CN}
CultureTypes: SpecificCultures | InstalledWin32Cultures | FrameworkCultures
DateTimeFormat: {System.Globalization.DateTimeFormatInfo}
DisplayName: "Chinese (Simplified, PRC)"
EnglishName: "Chinese (Simplified, China)"
IetfLanguageTag: "zh-CN"
IsNeutralCulture: false
IsReadOnly: true
KeyboardLayoutId: 2052
LCID: 2052
Name: "zh-CN"
NativeName: "中文(中国)"
NumberFormat: {System.Globalization.NumberFormatInfo}
OptionalCalendars: {System.Globalization.Calendar[1]}
Parent: {zh-CHS}
TextInfo: {TextInfo - zh-CN}
ThreeLetterISOLanguageName: "zho"
ThreeLetterWindowsLanguageName: "CHS"
TwoLetterISOLanguageName: "zh"
UseUserOverride: false
如果一个Item 新增了zh-CN
语言版本, 但通过zh
去访问, 无法显示zh-CN
语言的内容, 因为语言不一样.
为什么? 难道LanguageResolver
没有工作? 没有正常解析语言?
是的, Sitecore中有一个StripLanguage
pipeline, 它会自动识语言前缀删除并重定向. 所以在LanguageResolver
中查找自定义语言前缀zh
时没有找到.
重写Sitecore.Pipelines.PreprocessRequest.StripLanguage
Pipeline, 把让Sitecore跳过处理zh
语言前缀.
StripLanguage
代码片段public class StripLanguage : Sitecore.Pipelines.PreprocessRequest.StripLanguage
{
List<string> IgnorePrefix { get; } = new List<string>();
public void IgnoreUrlPrefix(XmlNode node)
{
var urlPrefix = node?.Attributes?["name"]?.Value;
if (string.IsNullOrEmpty(urlPrefix))
{
return;
}
if (!IgnorePrefix.Contains(urlPrefix))
{
IgnorePrefix.Add(urlPrefix);
}
}
public override void Process(PreprocessRequestArgs args)
{
if (HttpContext.Current != null && !string.IsNullOrWhiteSpace(HttpContext.Current.Request.FilePath))
{
string prefix = WebUtil.ExtractLanguageName(HttpContext.Current.Request.FilePath);
if (!string.IsNullOrWhiteSpace(prefix) && IgnorePrefix.Contains(prefix))
{
return;
}
}
base.Process(args);
}
}
StripLanguage
配置片段<preprocessRequest>
<processor type="Sitecore.Habitat.Website.Pipelines.StripLanguage, Sitecore.Habitat.Website" patch:instead="processor[@type='Sitecore.Pipelines.PreprocessRequest.StripLanguage, Sitecore.Kernel']" >
<settings hint="raw:IgnoreUrlPrefix">
<alias name="zh" />
</settings>
</processor>
</preprocessRequest>
以上是我在最近的项目中实现的自定义Sitecore语言前缀, 看起来确实比想像的要麻烦一点, 如果你有更好的想法或实现, 欢迎评论.
还没有人评论,抢个沙发吧...