2008年12月8日,星期一

建立多语言SharePoint网站-引入语言存储

如果有人要求您在SharePoint中构建多语言网站,那么与单一语言网站相比,很快就会发现一些额外的注意事项。这些可能包括:

  • 信息架构
  • 语言/文化检测
  • 决定是否使用变体
  • 网址策略

..等等。显然,这些决策将为每个多语言项目提供不同的“答案”,通常,客户的特定要求将指导您的方法。但是,在大多数此类项目中可能仍将保持不变的一项挑战是:

  • 如何处理许多小的文本字符串 不属于创作页面内容的内容 需要翻译并以适当的语言显示

这是我在此重点关注的挑战。为了说明这一点,这是来自BBC网站的一个示例,在该示例中,我突出显示了可能需要翻译但不属于特定页面的所有字符串:

英国广播公司的例子

..那只是一页-原来一个典型的网站 许多 这些。如果您只需要翻译在编辑模式下显示给作者的其他字符串,则可以轻松找到总数达数百个的字符串。因此,我们开始需要用于存储/检索这些“页面家具”物品的框架。如果我们使用的是收缩包装的产品,.Net资源文件可能是一个不错的选择,但是这种方法对于网站而言可能不够灵活,并且不允许内容作者/高级用户输入翻译内容。显然,需要基于SharePoint列表的内容,因此请输入“语言商店”,这是我对问题的解决方案,您现在可以从Codeplex下载(末尾的链接)。

语言商店简介

语言商店是我先前的改编 配置存储 解决方案,并遵循一些相同的原则:

  • 值存储在SharePoint列表中
  • 提供了一个API,可通过单个方法调用来检索值
  • 使用缓存框架以获得最佳性能
  • 轻松部署为.wsp

列表中的项目已分类,并且每种语言的翻译都有一列:

LanguageStoreListNarrow

请注意,列表中的每个翻译列均以约定“ LANG_<culture name>'(N.B.您可能将“文化名称”称为“语言环境ID”或类似名称)-因此,当需要在网站上添加新语言时,您只需创建一个具有适当名称的新列并添加翻译即可。您可以在 CultureInfo类的MSDN文档.

更新 -的 MSDN上的“国家语言支持” API参考页 是更好的参考-自从我链接到CultureInfo页面以来,它已经发生了变化。

检索值

要检索值,我们只需调用GetValue()方法并传递项目的类别和标题即可检索:

string sButtonText = LanguageStore.GetValue("Search", "SearchGoButtonText");

另外,由于我们可能在语言存储区中放置的许多项仅用于页面的表示,因此不得不切换到代码隐藏以获取这些值并将它们分配给控件的“文本”通常是可耻的的财产。因此,我提供了一种类似于SPUrl的标记化方法,该方法使您可以将Language 商店值简单地放入标记中,如下所示:


<asp:Button runat="server"id ="btnSearch"文字="<%$ SPLangStore:Search | SearchGoButtonText%>" />

我喜欢这个,因为这意味着您最终不会在代码后面留下很多行,而只是为了从Language 商店中获取值并将它们分配给ASP.Net标签或控件。对于那些不知道如何完成的人,我将在下一篇文章中写更多有关它的内容,因为我认为它是.Net中一个很酷的,未被充分利用的工具。

语言商店如何确定要检索的语言

在当前的实现中,SPWeb的区域设置用于确定检索哪些翻译。它是代码中的单个方法(实际上是一行!),因此,如果您有不同的要求,则可以轻松更改此方案。我们正在当前项目中使用语言存储,并且使用SPWeb设置对我们来说很有意义,因为我们正在以大约30种语言构建大约100个不同的站点,而不是 以本地语言显示的网站(根据用户的线程文化或类似语言)。

请注意,如果语言存储区不包含所请求区域性的值,则将使用回退过程,类似于.Net的全球化框架:

  1. 查看首选文化  e.g. fr -CH 法语(瑞士)
  2. 检查首选文化的父母,例如 fr 对于法语
  3. 检查默认语言(由配置决定),例如 对于英语

在某些项目可能具有诸如美国英语(EN-US)和英式英语(EN-GB)的不同版本的情况下,这很有用,但是其他项目不需要区分,因此可以在父列中输入一个值(EN )。

顺便说一句,如果您想知道SPWeb区域设置在哪里,因为您不需要更改它们,它们就在这里:

区域设置链接

区域设置页面

复选框允许您在给定Web上进行的区域设置级联到子Web,因此我们只需一次在站点的根部进行设置即可。


其他零碎
  • 所有项目都包装在解决方案/功能中,因此无需手动创建站点列/内容类型/语言存储列表等。还有一个安装脚本,可让您轻松安装解决方案。
  • 缓存的实现当前基于文件的CacheDependency -这使项目更新时服务器场中所有服务器上的缓存均无效,但确实要求所有WFE都可以写入此位置(例如,防火墙不会妨碍该方式) )。
  • 语言存储区也可以在没有SPContext的地方使用,例如列表事件接收器。在这种情况下,它将在SharePoint Web应用程序的web.config文件中查找值,以建立包含语言存储的网站的URL(注意:在将语言存储安装到您的网站时,这些web.config密钥会自动添加)。这也意味着它可以在SharePoint应用程序之外使用,例如控制台应用程序。
  • 可以从您网站的根网站的默认位置移动语言商店(为此,请从“语言商店列表”模板(在安装过程中添加)中创建一个新列表(在所需的任何子网站中),以及修改添加到web.config中的'LanguageStoreWebName'/'LanguageStoreListName'键以指向新位置。或者,如果您已经添加了100个不想重新创建的项目,则可以使用其他工具, 的SharePoint内容部署向导,位于 http://www.codeplex.com/SPDeploymentWizard 移动列表。)
  • 包括所有源代码和解决方案/功能文件,因此,如果您要更改任何内容,都可以。
  • 下载中的readme.txt中包含安装说明。

您可以从以下位置下载语言商店和所有源代码 www.codeplex.com/SPLanguageStore。欢迎所有反馈!

33条评论:

匿名 said...

克里斯,你好

很好的扩展,感谢您与社区分享!

关于性能的一种想法。与.NET资源文件相比,您如何评价语言存储的性能?

亲切的问候,
索伦

克里斯·奥'Brien说过...

索伦

我没有进行直接比较,但是我很确定我希望性能能够达到 更好 如果有什么。除非应用程序池刚刚被回收,否则语言存储将从内存中检索,并且总是比磁盘或数据库更快。

谢谢,

克里斯。

匿名 said...

相对于更改resx文件,就像使用这种方法,使用wsp部署新的resx文件,然后运行某种类型的timerjob将其复制到所有Web前端inetpub目录中,仅需一点翻译即可。

匿名 said...

克里斯你好

我真的很喜欢您的Config 商店,这是一种以正确方式执行的常识解决方案。

使用语言存储,您可以再次完成它,我特别喜欢提供声明性和程序化实现的方式(这正是我想要使用的方式)。

祝您圣诞节快乐,我想您已经赚到了剩下的一切!

匿名 said...

克里斯,

出色的工作!这确实的确勾选了所有框。

杰米

匿名 said...

克里斯再次担任GR8职位,我有几个疑问,我希望得到您的建议:
1.如果我们使用的是Sharepoint日语模板(1041),则语言列名称应该是什么,应该是LANG_JA还是LANG_JA-JP?

2.您认为您提到的这种方法(由于缓存的事实)比SPUtility.GetlocalizedString()更好,并且将(自定义应用程序专用)资源文件保留在12 \ resources文件夹中,效果更好?

3.如果页面上的标签超过30个,与调用GetValue()方法30次以上相比,调用单个方法并传递数组并获取collection \ array中的所有本地化字符串会更有效吗?您是否认为创建另一个方法来接受集合并返回本地化的字符串集合比调用GetValue()30次以上更有意义?

感谢您为社区付出的巨大努力。

问候
MOSSBUDDY

克里斯·奥'Brien说过...

MOSSBUDDY,

感谢您的评论,一些很好的问题。一一拿下:

1.不幸的是,不是100%确定吗,我想知道SPWeb设置的下拉菜单中是否有两个“日语”选项?无论如何,您可以做的是通过添加跟踪开关来打开跟踪,在Web区域中以日语区域设置发出请求,然后您会看到是否正在请求JA或JA-JP。

2.我认为缓存应该意味着语言存储的性能会稍好一些,但是我认为与该解决方案配合使用的主要原因是,它是一个用于存储值(而不是文件上的SharePoint列表)的事实。文件系统)。

3.是的,我同意这是一个正确的观点,并且将是对当前框架的一个很好的增强-我希望尽快解决这个问题。不过请记住,这只是与之相关的第一个匹配项(在应用程序池回收之后),因为所有其他匹配项都将从内存中获取值。

谢谢,

克里斯。

匿名 said...

您简直很棒,感谢您的评论。您度过了一个愉快的圣诞节和节日快乐。您正在为社区做一个很棒的工作。感谢所有gr8的作品

盖海姆说过...

多语言网站的绝佳解决方案!

小细节:我不得不用<asp:Button runat="server" id="btnSearch" Text="<%$ SPLang商店:Search | SearchGoButtonText%>" />

缓存没有'一开始无法正常工作,但是由于有了跟踪,我很快发现CacheDependencyFile无法访问。

克里斯·奥'Brien说过...

夏普

糟糕,非常感谢您所做的更正,我将更新本文。

是的,对该部分的跟踪帮助我诊断了几次无法写入文件;-)

干杯,

克里斯。

斯里肯斯说过...

克里斯你好

I 做了 not find the source code 在 the 网址 you mentioned. Please let me know fr om where i can download the code

谢谢,
斯里

克里斯·奥'Brien说过...

您好Srikanth,

您可以在Codeplex网站上的“发布”选项卡上找到源代码。

HTH,

克里斯。

未知说过...

克里斯,你好
它也可以与WSS一起使用吗?还是变异功能是此解决方案所必需的?

问候,
连续波

克里斯·奥'Brien说过...

克里斯,你好

我没有明确测试,但是其中没有使用MOSS功能的东西。和我 做了 测试相关 配置存储 仅使用WSS的解决方案-确实应该没问题。

谢谢,

克里斯。

大卫说过...

克里斯,

这看起来很棒。潜在地,这可以帮助我。但我有个问题。我在一个webapp中有许多使用hosheader网址的网站集。基本上是单独网站集中的单独网站。不使用原始列表的默认网站集。我的问题是,我可以为每个网站集创建一个语言存储列表吗?

谢谢,

D.

克里斯·奥'Brien说过...

@dcarr,

您当然可以这样做,但是您需要更改此代码。您确定不希望只拥有一个集中式列表吗?我们有100个网站集(像您一样,很有趣地托管了标头网站集),但仍然首选集中式模型。代码处理得很好。

但是,如果您确实喜欢许多语言商店列表,请查看我们的“姐妹”项目,即 配置存储 框架。在2.0.0.0版本中,我添加了使用多个列表的功能(如果在“本地”列表中找不到内容,则使用1个主列表)。由于代码是90%相同,因此您应该能够相当简单地移植所需的位。

HTH,

克里斯。

纳格帕勒元帅说过...

克里斯你好,

在项目接收者类中使用Lang商店时,将引发null异常,原因是使用SPContext类的getCultureForRequest()方法。其中SPContext为null

我希望您可以在下一版本中解决此问题。

干杯
元帅

克里斯·奥'Brien说过...

@元帅,

嗯,我还没有考虑过将语言存储区用于事件接收器。我想我不会说不支持它,但是...您希望如何在事件接收器中确定文化​​?

如果您对这种逻辑的想法有所了解,我将尝试找到时间来实现它。

HTH,

克里斯。

纳格帕勒元帅说过...

可能不是SPCurrent对象的替代者,您需要在“ getCultureForRequest()”方法中创建SPSite和SPWeb对象。

克里斯·奥'Brien说过...

@元帅,

好的,我现在修改了代码,测试并上传到Codeplex。抱歉,我花了几天时间才能实现,但希望这会给您一种以您想要的方式使用语言存储的方法。由于语言存储代码本身不知道要实例化哪个SPSite / SPWeb,因此我添加了GetValue()方法的新重载,该方法允许您传递SPWeb。在功能接收器(您的方案)中,您将通过properties.Feature.Parent获取此对象。

版本1.0.1.0 语言商店Codeplex网站 具有更新的代码。

希望有帮助!

克里斯。

纳格帕勒元帅说过...

谢谢克里斯,将在新项目中使用更新的语言存储。当前项目在UAT中,并且我们已在功能中使用.resx来获取令牌值。

非常感谢您为共享和开发有用的组件所做的努力。 :)

德文德拉 said...

克里斯你好
Gr8文章。
我正在使用阿拉伯语和英语。
我想将“阿拉伯语”列添加到“语言”存储中,我必须对该代码进行哪些更改。

德文德拉 said...

克里斯,你好
我已经实现了这一点。很好的文章。
但是我试图在用户控件上实现同样的功能。则它没有显示任何内容。能否请您告诉我如何在Usercontrol中实现相同功能。

克里斯·奥'Brien说过...

嗨Devendra,

通常,通过以下方式添加新语言的列:

-使用适当的名称将新列添加到“语言存储”列表中,例如亚美尼亚阿拉伯语为“ LANG_ar-YE”(例如),阿拉伯语为“ LANG_ar”
-如文章中所述将SPWeb.Locale设置设置为适当的语言

但是,我从未实现过从右到左的语言,因此不确定这些语言是否需要额外的内容。如果是这样,那将是.Net,而不是语言商店特有的任何内容。

HTH,

克里斯。

克里斯·奥'Brien说过...

德文德拉

对于您的第二个问题-嗯,不确定问题出在哪里。我从语言商店渲染字符串的90%都使用了用户控件!

我猜这是问题的另一种原因(例如,列名未与SPWeb.Locale设置或类似名称``对齐'')。建议启用跟踪以帮助诊断问题(使用标准的Systems.Diagnostics跟踪)。

HTH,

克里斯。

德文德拉 said...

克里斯,你好

lblerror.Text = LanguageStore.GetValue(“记录添加成功_c”,“记录添加成功_t”);

我在用户控件中添加的这段代码。
我遇到错误
“名称'LanguageStore'在当前上下文中不存在”

为此,我在用户控件中添加了哪些名称空间。或请建议我要做哪些更改。

克里斯·奥'Brien说过...

德文德拉

嗯,好-您需要添加对我的程序集(COB.SharePoint.Utilities.LanguageStore.dll)的引用,并将“使用”指令(或VB中的“导入”)添加到包含LanguageStore类的名称空间-这是“ COB.SharePoint.Utilities”。

HTH,

克里斯。

未知说过...

克里斯!

您的解决方案乍一看很棒,但我可以't install it.

我下载了1.1.0.0版本。您在自述文件中写道:1.找到'COB.SharePoint.Utilities.LanguageStore_Install.bat' file in the 'InstallPackage'目录,并修改'url'网站网址(网络应用程序网址)的参数。

I ran the bat with: "COB.SharePoint.Utilities.LanguageStore_Install.bat 网址 http://myweb.com" order.

但这会引发异常:
Can't find the web application (http://cob.test.dev).

请帮我。我该如何解决?我误会了吗?

克里斯·奥'Brien说过...

@JÃzzef,

Ah - you need to edit the .bat file and change the URL in there, not pass it as a parameter. You're getting this error because http://cob.test.dev is still in the batch file.

HTH,

克里斯。

尚邦 said...

嗨,我尝试使用该解决方案创建一个新的语言,即马来语(ms),我尝试使用带代码(ms-my)的马来语(马来西亚)。但是我的主要问题是添加标题n类别。是否有关于标题n类别的任何指南或文章。谢谢

克里斯·奥'Brien说过...

@shambon,

标题和类别仅供您用来对要存储的项目进行分类。您'从代码中的语言存储中检索值时,将需要同时使用两者-GetValue()方法采用与要检索的项目的标题和类别相对应的参数。

HTH,

克里斯。

未知说过...

嗨,克里斯,您能告诉我SharePoint 2010解决方案的更新版本是否已存在。我已经从CodePlex下载了解决方案,我'我不确定是否仅Visual Studio转换就足够了?

非常感谢你

克里斯·奥'Brien说过...

@皮疹,

It'自从我看了这个项目已经有一段时间了-我还没有'有必要在SP2010上使用它(到目前为止),所以我还没有'创建了一个SP2010特定的VS项目。

我会尝试VS升级向导-我不会'尤其希望由此产生任何问题,'s what I'd如果我现在需要使用语言存储,该怎么办。

谢谢,

克里斯。