pwd*_*dst 5 c# delphi asp.net-mvc localization asp.net-web-api
我目前正在编写一个现有(Delphi)基于桌面的软件产品的ASP.NET MVC 4 Web版本(使用Razor视图引擎),该产品目前允许客户(企业)完全自定义其实例中的所有文本.应用程序,既可以本地化,也可以根据特定环境进行自定义.
例如,条款─
可能会改变为业务中使用的个别术语.
目前,这种自定义只是在存储在应用程序数据库中的文本字符串中完成,并在Delphi数据库中的每个表单加载中进行比较和加载.即,将表单上的每个字符串与数据库英语字符串进行比较,并在表单上呈现基于所选语言环境的替换(如果可用).我觉得这不是可扩展的,也不是特别高效的.
我也不熟悉在本地化方法中发生定制的想法,应用程序中的每个字符串都可以由最终客户更改 - 它可能导致文本一致性方面的支持问题,以及指令不正确的混淆更改或未更新.应用程序中有许多字符串,除了将它们本地化为用户的语言环境(本地语言和/或格式约定)之外,可能不应该更改.
我个人宁愿坚持使用RESX资源文件和资源键而不是字符串匹配来本地化应用程序的Web版本的ASP.NET API和约定.这比字符串匹配要灵活得多,其中字符串可能具有不同的上下文或大小写,并且不能简单地进行大量更改(许多英语单词在不同的上下文中可能具有不同的含义,并且可能不会在其他上下文中映射到相同的含义集)语言),关键是避免往返数据库以获取获取页面所需的字符串,并且还允许使用围绕标准RESX文件的大量工具轻松进行转换.这也意味着不需要自定义实现来维护或记录未来的开发人员.
然而,这确实给出了我们如何处理这些自定义术语的问题.
我目前正在考虑我们应该为这些术语设置单独的RESX文件,其中列出了给定语言环境的默认值.然后我会创建一个新的数据库表,就像这样
CREATE TABLE [dbo].[WEB_CUSTOM_TERMS]
(
[TERM_ID] int identity primary key,
[COMPANY_ID] int NOT NULL, -- Present for legacy reasons
[LOCALE] varchar(8) NOT NULL,
[TERM_KEY] varchar(40) NOT NULL,
[TERM] nvarchar(50) -- Intentionally short, this is to be used for single words or short phrases
);
Run Code Online (Sandbox Code Playgroud)
这可能会在需要时读入Dictionary <string,string>并由IIS缓存以提供查找,而不会延迟连接到SQL Server并执行查询.
public static class DatabaseTerms
{
private static string DictionaryKey
{
get { return string.Format("CustomTermsDictionary-{0}", UserCulture); }
}
private static string UserCulture
{
get { return System.Threading.Thread.CurrentThread.CurrentCulture.Name; }
}
public static Dictionary<string, string> TermsDictionary
{
get
{
if (HttpContext.Current.Cache[DictionaryKey] != null)
{
var databaseTerms = HttpContext.Current.Cache[DictionaryKey] as Dictionary<string, string>;
if (databaseTerms != null)
{
return databaseTerms;
}
}
var membershipProvider = Membership.Provider as CustomMembershipProvider;
int? companyId = null;
if (membershipProvider != null)
{
companyId = CustomMembershipProvider.CompanyId;
}
using (var context = new VisionEntities())
{
var databaseTerms = (from term in context.CustomTerms
where (companyId == null || term.CompanyId == companyId) &&
(term.Locale == UserCulture)
orderby term.Key
select term).ToDictionary(t => t.Key, t => t.Text);
HttpContext.Current.Cache.Insert(DictionaryKey, databaseTerms, null, DateTime.MaxValue,
new TimeSpan(0, 30, 0), CacheItemPriority.BelowNormal, null);
return databaseTerms;
}
}
set
{
if (HttpContext.Current.Cache[DictionaryKey] != null)
{
HttpContext.Current.Cache.Remove(DictionaryKey);
}
HttpContext.Current.Cache.Insert(DictionaryKey, value, null, DateTime.Now.AddHours(8),
new TimeSpan(0, 30, 0), CacheItemPriority.BelowNormal, null);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后我可以有一个暴露公共属性的类,根据这个字典值或 RESX文件中的值返回一个字符串- 取其为空.就像是-
public static class CustomTerm
{
public static string Product
{
get
{
return (DatabaseTerms.TermsDictionary.ContainsKey("Product") ?
DatabaseTerms.TermsDictionary["Product"] : CustomTermsResources.Product);
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后,如果需要,可以使用字符串格式将这些字符串添加到更大的本地化字符串,或者将它们自己用作菜单等
这种方法的主要缺点是需要提前预测最终客户可能希望定制的条款,但我确实认为这可能是两全其美的.
这看起来像一个可行的方法,其他开发人员如何处理这个问题?
提前致谢.
我们的应用程序中有类似的设置,我们允许某些模块具有自定义名称以适合客户品牌。
此解决方案的第一步是我们在运行时了解客户端上下文,并将其填充到 HttpContext.Items 中。
对于那些可以自定义的项目,我们引入了包含基本密钥的资源文件。如果企业需要定制我们在密钥名称前添加前缀(即Client_key)
一旦所有这些都就位,就可以通过简单的合并来获取自定义或默认值。
Resx 文件片段
<data name="TotalLeads" xml:space="preserve">
<value>Total Leads</value>
</data>
<data name="Client_TotalLeads" xml:space="preserve">
<value>Total Prospects</value>
</data>
Run Code Online (Sandbox Code Playgroud)
用于处理自定义资源和基础资源之间切换的类
public static class CustomEnterpriseResource
{
public static string GetString(string key)
{
return GetString(key, Thread.CurrentThread.CurrentUICulture);
}
public static string GetString(string key, string languageCode)
{
return GetString(key, new CultureInfo(languageCode));
}
public static string GetString(string key, CultureInfo cultureInfo)
{
var customKey = ((EnterpriseContext)HttpContext.Current.Items[EnterpriseContext.EnterpriseContextKey]).ResourcePrefix + key;
return Resources.Enterprise.ResourceManager.GetString(customKey, cultureInfo)
?? Resources.Enterprise.ResourceManager.GetString(key, cultureInfo);
}
}
Run Code Online (Sandbox Code Playgroud)
另外,为了协助视图,我们为此创建了一个 html 帮助器。
public static class EnterpriseResourceHelper
{
/// <summary>
/// Gets a customizable resource
/// </summary>
/// <param name="helper">htmlHelper</param>
/// <param name="key">Key of the resource</param>
/// <returns>Either enterprise customized resource or base resource for current culture.</returns>
public static string EnterpriseResource(this HtmlHelper helper, string key)
{
return CustomEnterpriseResource.GetString(key);
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1491 次 |
| 最近记录: |