在多语言网站中未应用文化差异

4
我有一个非常不寻常的问题让我完全感到困惑。我们有一个多语言网站,因此我们采用资源文件。然而,我们视图中的每个烧录文本(例如<a href="#">@TextResources.my_key</a>)都将本地化为随机文化。这仅发生在我的 Azure 部署上,我无法在本地重现。
更加神秘的是,有一小段文字总是尊重我的文化变化。该文本通过方法调用检索:
<a href="#">@.ConfigUtils.getTerms()</a>

方法是:

public static string getTerms()
{
    string key = GetKeyFromDb(CONSTANTS.TERMS);
    if (!string.IsNullOrEmpty(key))
    {
        return TextResources.ResourceManager.GetString(key);

我仍在从我们的资源文件中阅读,但在这种情况下,它正在按照预期进行本地化!文化是在视图中读取资源文件后,在调用此方法之前应用的吗?!

我们所有的控制器都继承自一个基础控制器,在其中我们重写了OnActionExecuting()来应用我们的文化:

protected override void OnActionExecuting(ActionExecutingContext filterContext) {
    ContextModel ctx = (ContextModel) Session["ContextModel"];
    // Set the correct localization according to the value set by the user
    if (ctx != null && ctx.UserLanguageId != null){
        Thread.CurrentThread.CurrentUICulture = new CultureInfo (ctx.UserLanguageId);
        Thread.CurrentThread.CurrentCulture = new CultureInfo(ctx.UserLanguageId);
    }
}

在我开始将文化管理代码移动到不同位置并重新部署到Azure以希望解决问题之前,我希望有人能想出为什么只有通过方法调用检索的文本被本地化。 OnActionExecuting()在操作之前执行,因此我认为这是放置文化管理代码的适当位置。还有其他地方更好吗?
更新
看起来这个问题在部署后出现,但可以通过重新启动云服务来解决。
更新2 根据@RichardSchneider的要求,自动生成的TextResources代码如下:
public static string my_key{
    get {
        return ResourceManager.GetString("my_key", resourceCulture);
    }
}

@Jcl 很有趣,但出于某种原因,该网站有时会本地化为荷兰语... - Mister Epic
1
@MisterEpic,在OnActionExecuting的开头执行Debug.WriteLine(new { SynchronizationContext.Current }),会显示什么?是AspNetSynchronizationContext吗? - noseratio - open to work
1
@Noseratio 的评论很可能是正确的 - 如果你在代码中使用了 async,你很有可能做错了... 可能会添加答案。 - Alexei Levenkov
@AlexeiLevenkov,我想我们已经在这里找到了解决方法(https://dev59.com/L4fca4cB1Zd3GeqPh1_F#28227165) :) - noseratio - open to work
1
@Noseratio - 你也应该在这里回答它(或者OP自己回答)...所以维基就是它,因为我无法将其关闭为重复项... - Alexei Levenkov
显示剩余2条评论
3个回答

2

这个问题已经在这里得到了回答: 异步和线程文化


一个可能的选项是您在代码中使用了 async.ConfigureAwait(false)。结果是,awiat(获取文本/渲染视图)之后的代码会从它所在的线程中随机选择文化,而不是您希望在操作过滤器的同步部分中设置的文化。

可能的解决方法 - 不要使用 .ConfigureAwait(false),或者如果必须使用,则通过所有调用显式传递文化,并在进行区域敏感调用之前确保将其设置回来。

更加偏远的可能性:假设您在 ASP.Net 应用程序中使用默认资源文件生成以实现其正常功能,则应该

  • 设置 CurrentUICulture
  • 确保生成的资源管理器的 Culture 属性设置为 null

根据您看到的行为,我猜测有些东西在开始时设置了 Culture 错误,因此您会得到"随机"文化。

要进行调试,请尝试检查 Culture 属性的值 - 应该为 null。


非常好的建议。我最终找到了根本原因,但我将来一定会记住你在这里提到的内容。 - Mister Epic

1
该方法有效是因为它使用了ResourceManager,它尊重当前的文化。 TextResources.my_key失败,因为它(很可能)只在第一次使用时分配了一个值。 更新 my_key的自动生成代码将区域信息传递给ResourceManager.GetString。建议修改自动生成器,使用仅一个参数的重载来生成:
public static string my_key{
get {
    return ResourceManager.GetString("my_key");
}
}

如果不可能的话,那么你需要使用OnActionExecuting来设置resource_culture。为了让它起作用,resource_culture需要成为一个线程本地变量。

你能详细说明第二段吗?TextResources对象也应该遵守当前的语言文化,是吗? - Mister Epic
TextResources.my_key 似乎是一个属性,我猜测在每次 get 操作时并不会访问 ResourceManager。请展示 TextResources 中相关的代码。 - Richard Schneider
这段代码是自动生成的,但我已经将其包含在上面了。谢谢! - Mister Epic

0
如果其他人遇到了同样的问题,我已经找到了根本原因。我们有一个页面,用户可以通过电子邮件中提供给他们的URL下载报告。该URL包括用于本地化的语言查询字符串变量:

/report/download?id=123&lang=de

在控制器操作中,原始作者在我们的资源对象上设置了文化,而不是线程:
TextResources.Culture = new CultureInfo("de");

查看元数据:

[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
public class TextResources
{
public static CultureInfo Culture { get; set; }

因此,当我们在视图中应用本地化时,似乎该属性优先于线程文化。由于该属性是静态的,因此它在为报告提供服务的任何 Azure 实例上全局应用。因此,当人们以各种语言下载这些报告时,效果看起来是随机的。

我承认我仍然不清楚以下内容为什么总是尊重线程文化:

public static string getTerms()
{
    string key = GetKeyFromDb(CONSTANTS.TERMS);
    if (!string.IsNullOrEmpty(key))
    {
         return TextResources.ResourceManager.GetString(key);

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接