来自数据库的 Silverlight 本地化,而不是 resx

发布于 2024-10-19 15:27:13 字数 2448 浏览 1 评论 0原文

我有一个需要本地化的 Silverlight 4 OOB 应用程序。过去我使用了传统的 resx 路线,但我被要求遵循现有 winforms 应用程序的架构。

所有字符串当前都存储在数据库中 - 我使用 Web 服务将这些字符串拉下来并将其写入本地 Effiproz 隔离存储数据库中。登录时,我加载一个包含用户语言的语言字符串的 Dictionary 对象。这很好用。

但是,我想自动化 UI 本地化(WinForms 应用程序这样做): 循环浏览页面上的所有控件并查找任何文本块 - 如果有文本属性,我会将其替换为本地化版本。如果找不到文本,则我将字符串写入数据库以进行本地化。

这在简单的表单上可以正常工作,但是一旦您拥有扩展器/滚动查看器和内容控件,VisualTree 解析器就不会返回控件的子级,因为它们不一定可见(请参见下面的代码)。 这是一个已知问题并且阻碍了我的自动化尝试。

我的第一个问题是:有没有一种方法可以通过循环复杂(非视觉)元素并在字典中查找值来自动执行页面加载?

我的第二个问题是:如果没有,那么处理此问题的最佳方法是将字符串加载到应用程序资源字典中并更改我的所有页面以引用它,或者我应该考虑生成 resx 文件,无论是在服务器上(并按正常方式将其与应用程序打包)还是在客户端上(我有下载的字符串,我可以制作并加载 resx 文件吗?)

感谢您的任何指示。

这是我现有的代码,不适用于折叠元素和复杂的内容控件:

  public void Translate(DependencyObject dependencyObject)
    {
        //this uses the VisualTreeHelper which only shows controls that are actually visible (so if they are in a collapsed expander they will not be returned). You need to call it OnLoaded to make sure all controls have been added
        foreach (var child in dependencyObject.GetAllChildren(true))
        {
            TranslateTextBlock(child);
        }
    }

private void TranslateTextBlock(DependencyObject child)
{
    var textBlock = child as TextBlock;
    if (textBlock == null) return;

    var value = (string)child.GetValue(TextBlock.TextProperty);
    if (!string.IsNullOrEmpty(value))
    {
        var newValue = default(string);
        if (!_languageMappings.TryGetValue(value, out newValue))
        {
            //write the value back to the collection so it can be marked for translation
            _languageMappings.Add(value, string.Empty);
            newValue = "Not Translated";
        }
        child.SetValue(TextBlock.TextProperty, newValue);
    }
}

然后我尝试了两种不同的方法:

1)将字符串存储在普通的字典对象中 2)将字符串存储在普通字典对象中并将其作为资源添加到应用程序中,然后您可以将其引用为

TextBlock Text="{Binding Path=[Equipment], Source={StaticResource ResourceHandler}}" 



App.GetApp.DictionaryStrings = new AmtDictionaryDAO().GetAmtDictionaryByLanguageID(App.GetApp.CurrentSession.DefaultLanguageId);

Application.Current.Resources.Add("ResourceHandler", App.GetApp.DictionaryStrings);

//http://forums.silverlight.net/forums/p/168712/383052.aspx

I have a Silverlight 4 OOB application which needs localizing. In the past I have used the conventional resx route but I have been asked to follow the architecture of an existing winforms app.

All the strings are currently stored in a database - I use a webservice to pull these down and write them into a local Effiproz Isolated Storage database. On Login I load a Dictionary object with the language strings for the users language. This works fine.

However, I want to automate the UI localization (the WinForms app does it like this):
Loop through all the controls on the page and look for any Textblocks - if there is a text property I replace it with the localized version. If the text is not found, then I WRITE the string to the database for localization.

This works ok on simple forms but as soon as you have expanders/scrollviewers and content controls then the VisualTree parser does not return the children of the controls as they are not necessarily visible (see my code below). This is a known issue and thwarts my automation attempt.

My first question is: Is there a way of automating this on page load by looping through the complex (non-visual) elements and looking up the value in a dictionary?

My second question is: If not, then is the best way of handling this is to load the strings into an app resource dictionary and change all my pages to reference it, or should I look into generating resx files, either on the server (and package it with the app as per normal) or on the client (I have the downloaded strings, can I make and load resx files?)

Thanks for any pointers.

Here is my existing code that does not work on collapsed elements and complex content controls:

  public void Translate(DependencyObject dependencyObject)
    {
        //this uses the VisualTreeHelper which only shows controls that are actually visible (so if they are in a collapsed expander they will not be returned). You need to call it OnLoaded to make sure all controls have been added
        foreach (var child in dependencyObject.GetAllChildren(true))
        {
            TranslateTextBlock(child);
        }
    }

private void TranslateTextBlock(DependencyObject child)
{
    var textBlock = child as TextBlock;
    if (textBlock == null) return;

    var value = (string)child.GetValue(TextBlock.TextProperty);
    if (!string.IsNullOrEmpty(value))
    {
        var newValue = default(string);
        if (!_languageMappings.TryGetValue(value, out newValue))
        {
            //write the value back to the collection so it can be marked for translation
            _languageMappings.Add(value, string.Empty);
            newValue = "Not Translated";
        }
        child.SetValue(TextBlock.TextProperty, newValue);
    }
}

Then I have tried 2 different approaches:

1) Store the strings in a normal dictionary object
2) Store the strings in a normal dictionary object and add it to the Application as a Resource, then you can reference it as

TextBlock Text="{Binding Path=[Equipment], Source={StaticResource ResourceHandler}}" 



App.GetApp.DictionaryStrings = new AmtDictionaryDAO().GetAmtDictionaryByLanguageID(App.GetApp.CurrentSession.DefaultLanguageId);

Application.Current.Resources.Add("ResourceHandler", App.GetApp.DictionaryStrings);

//http://forums.silverlight.net/forums/p/168712/383052.aspx

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

寄居人 2024-10-26 15:27:13

好吧,所以没有人回答这个问题,我想出了一个解决方案。

基本上,您似乎可以使用将语言字典加载到全局资源中

Application.Current.Resources.Add("ResourceHandler", App.GetApp.DictionaryStrings);

<TextBlock Text="{Binding [Equipment], Source={StaticResource ResourceHandler}}" />

,然后像普通的 StaticResource 一样访问它。我们需要将所有丢失的字符串记录到数据库中进行翻译 - 为此,我选择使用一个调用 Localize 扩展方法的转换器(因此可以在后面代码中的任何字符串上完成),然后查找字典(不是资源)中的字符串,如果它不存在,可以用它做一些事情(将其写入本地数据库)。

Text="{Binding Source='Logged on User', Converter={StaticResource LocalizationConverter}}"/>

这个方法对我们来说效果很好。

Ok, so nobody answered this and I came up with a solution.

Basically it seems that you can load the language dictionary into your global resources using

Application.Current.Resources.Add("ResourceHandler", App.GetApp.DictionaryStrings);

<TextBlock Text="{Binding [Equipment], Source={StaticResource ResourceHandler}}" />

and then access it like a normal StaticResource. We have the requirement of noting all our missing strings into a database for translation - for this reason I chose to use a Converter that calls a Localise extension method (so it can be done on any string in the code behind) which then looks up the string in the Dictionary (not the resource) and can do something with it (write it to a local DB) if it does not exist.

Text="{Binding Source='Logged on User', Converter={StaticResource LocalizationConverter}}"/>

This method works ok for us.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文