我正在研究多语言ASP.NET MVC应用程序(MVC4)。
我想让我的资源文件字符串在运行时可以编辑而无需重新编译应用程序并且没有应用程序池回收使用.resx
文件看起来不可能,所以我迁移到在数据库中存储字符串资源。
我必须从数据库获取每个标签/字符串资源,因此每个请求都会有更多数据库命中。 如何解决?
我已经google了一下,有人建议在字典中加载资源并将其存储为应用程序变量,登录/登录页面并将该字典用作资源而不是数据库命中。
我很困惑,什么是有效的方法。有人可以指导我正确的方向避免更多的数据库命中?
任何帮助/建议都将受到高度赞赏。
由于
答案 0 :(得分:0)
我使用.resx文件进行本地化时遇到了同样的问题。当翻译人员不是程序员时,他们工作得不好。现在,我们的管理区域中有一个翻译页面。效果很好。
我们仍然没有很好解决方案的一个领域是数据注释,它仍然使用.resx文件。我修改了下面的源代码,删除了对我们实际数据库结构或表的任何引用。
如果数据库中不存在条目,则使用基础.resx文件会出现回退。如果.resx文件中没有条目,我会在找到国会大厦字母时拆分该单词(CamelSpace是一种字符串扩展方法)。
最后,根据您的实现,您可能需要删除上下文缓存,尤其是在缓存进程外的情况下。
一些用法示例:
@LanguageDb.Translate("Enter your first name below","FirstNamePrompt")
@LanguageDb.Me.FirstName
@String
.Format(LanguageDb
.Translate(@"You can be insured for
{0} down and {1} payments of {2}"),
Model.Down,Model.NumPayments,
Model.InstallmentAmount)
public class LanguageDb : DynamicObject
{
public static dynamic Me = new LanguageDb();
private LanguageDb() { }
public static string Translate(string englishPhrase, string resourceCode = null)
{
return GetTranslation(englishPhrase, resourceCode) ?? englishPhrase;
}
public override bool TryGetMember(GetMemberBinder binder, out object result)
{
result = GetTranslation(binder.Name);
return true;
}
private static string GetTranslation(string resourceName, string resourceCode = null)
{
resourceCode = resourceCode ?? resourceName;
if (resourceCode.Contains(" ") || resourceCode.Length > 50)
{
resourceCode = resourceName.GetHashCode().ToString(CultureInfo.InvariantCulture);
}
var lang = (string)HttpContext.Current.Request.RequestContext.RouteData.Values["lang"] ?? "en";
// cache entries for an hour
var result = Get(subagent + "_" + lang + "_" + resourceCode, 3600, () =>
{
// cache a datacontext object for 30 seconds.
var context = Get("_context", 30, () => new YourDataContext()) as YourDataContext;
var translation = context.Translations.FirstOrDefault(row => row.lang == lang && row.Code == resourceCode);
if (translation == null)
{
translation = new Lookup {
Code = resourceCode,
lang = lang,
Value = Language.ResourceManager.GetString(resourceName, Language.Culture)
?? resourceName.CamelSpace()
};
context.Translations.Add(translation);
context.SaveChanges();
}
return translation.Value;
});
return result;
}
public override bool TrySetMember(SetMemberBinder binder, object value)
{
// ignore this
return true;
}
public static T Get<T>(string cacheId, int secondsToCache, Func<T> getItemCallback) where T : class
{
T item = HttpRuntime.Cache.Get(cacheId) as T;
if (item == null)
{
item = getItemCallback();
if (secondsToCache > 0)
{
HttpRuntime.Cache.Insert(
cacheId, item, null, Cache.NoAbsoluteExpiration,
new TimeSpan(0, 0, secondsToCache), CacheItemPriority.Normal, null);
}
else
{
HttpRuntime.Cache.Insert(cacheId, item);
}
}
return item;
}
}