【问题标题】:Showing different message in multilanguage dynamically以多语言动态显示不同的消息
【发布时间】:2018-11-23 06:43:25
【问题描述】:

我已经成功创建了一个基于here 的多语言应用程序。能够更改语言时我很棒。

现在我陷入了这种境地。我的应用程序使用硬件运行。所以有一个屏幕与硬件交互并显示状态文本块。消息将根据硬件的响应而变化,例如“请稍候..”“将您的身份证扫描到扫描仪中”“扫描完成”“已识别个人资料,继续交易”

这个变体如何以多语言显示到单个文本块中?

假设文本块将命名为TbxStatus.Text。如何在 ResourceDictionary 文件中设置消息以及如何处理它应该采用哪个资源字符串键?

已编辑 [我尝试过什么]

这是我根据资源字典编写的用于切换语言和显示的代码:-

App.cs

public static String Directory;
public static App Instance;
public static event EventHandler LanguageChangedEvent;
public App()
{
    // Initialize static variables
    Instance = this;
    Directory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
    Instance.SetLanguageResourceDictionary(Instance.GetLocXAMLFilePath("en-US"));
}

public static void LoadLanguageLocalization()
{
    try
    {
        ViewModel.AppConfigViewModel.LocalizationProperty.LangLoc = new List<ApplicationModel.LanguageLocalization>
        {
            new ApplicationModel.LanguageLocalization { LanguageID = 1, CountryCode = "ms-MY", LanguageName = "Bahasa Malaysia" },
            new ApplicationModel.LanguageLocalization { LanguageID = 2, CountryCode = "en-US", LanguageName = "English" },
            new ApplicationModel.LanguageLocalization { LanguageID = 3, CountryCode = "zh-CN", LanguageName = "Chinese" },
            new ApplicationModel.LanguageLocalization { LanguageID = 4, CountryCode = "ta-IN", LanguageName = "Tamil" }
        };
    }
    catch (Exception ex)
    {
        LogEvents($"[App] Exception on LoadLanguageLocalization. Message-{ex.Message}. Stack Trace-{ex.StackTrace}", EventLogEntryType.Error);
        ViewModel.AppConfigViewModel.LocalizationProperty.LangLoc = null;
    }
}
public void SwitchLanguage(string inFiveCharLang)
{
    if (System.Globalization.CultureInfo.CurrentCulture.Name.Equals(inFiveCharLang))
        return;

    var ci = new System.Globalization.CultureInfo(inFiveCharLang);
    Thread.CurrentThread.CurrentCulture = ci;
    Thread.CurrentThread.CurrentUICulture = ci;

    SetLanguageResourceDictionary(GetLocXAMLFilePath(inFiveCharLang));
    LanguageChangedEvent?.Invoke(this, new EventArgs());
}
private string GetLocXAMLFilePath(string inFiveCharLang)
{
    string locXamlFile = "Resources." + inFiveCharLang + ".xaml";
    return Path.Combine(Directory, "Language", locXamlFile);
}
public void SetLanguageResourceDictionary(String inFile)
{
    if (File.Exists(inFile))
    {
        // Read in ResourceDictionary File
        var languageDictionary = new ResourceDictionary();
        languageDictionary.Source = new Uri(inFile);

        // Remove any previous Localization dictionaries loaded
        int langDictId = -1;
        for (int i = 0; i < Resources.MergedDictionaries.Count; i++)
        {
            var md = Resources.MergedDictionaries[i];
            // Make sure your Localization ResourceDictionarys have the ResourceDictionaryName
            // key and that it is set to a value starting with "Loc-".
            if (md.Contains("LanguageDictionaryName"))
            {
                if (md["LanguageDictionaryName"].ToString().StartsWith("Lang-"))
                {
                    langDictId = i;
                    break;
                }
            }
        }
        if (langDictId == -1)
        {
            // Add in newly loaded Resource Dictionary
            Resources.MergedDictionaries.Add(languageDictionary);
        }
        else
        {
            // Replace the current langage dictionary with the new one
            Resources.MergedDictionaries[langDictId] = languageDictionary;
        }
    }
}

SelectLanguage.cs

private async void Page_Loaded(object sender, RoutedEventArgs e)
{
    try
    {
        App.LogEvents($"[{PageTitle}] Loaded: Select language", System.Diagnostics.EventLogEntryType.Information);
        BindingToPropertyControl();
    }
    catch (System.Exception ex)
    {
        string error = $"[{PageTitle}] Exception on Page_Loaded. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
        App.LogEvents(error, System.Diagnostics.EventLogEntryType.Error);
    }
}
private void BindingToPropertyControl()
{
    try
    {
        if (ViewModel.AppConfigViewModel.LocalizationProperty.LangLoc != null)
        {
            LanguagePack.ItemsSource = ViewModel.AppConfigViewModel.LocalizationProperty.LangLoc;
        }
    }
    catch (System.Exception ex)
    {
        string error = $"[{PageTitle}] Exception on BindingToPropertyControl. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
        App.LogEvents(error, System.Diagnostics.EventLogEntryType.Error);
    }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
    try
    {
        ScreenTimer.Stop();
        Button btn = (Button)sender;
        string LangCode = btn.Tag.ToString();
        App.LogEvents($"[{PageTitle}] Selecting language: {LangCode}", System.Diagnostics.EventLogEntryType.Information);
        App.Instance.SwitchLanguage(LangCode.ToString());
        Dispatcher.BeginInvoke(DispatcherPriority.Send, new Action(delegate ()
        {
            NavigationService.Navigate(new Uri(ApplicationModel.NaviModel.NaviSelectOptions, UriKind.RelativeOrAbsolute));
        }));
    }
    catch (System.Exception ex)
    {
        string error = $"[{PageTitle}] Exception on Button_Click. Message: {ex.Message}. StackTrace: {ex.StackTrace}";
        App.LogEvents(error, System.Diagnostics.EventLogEntryType.Error);
    }
}

SelectLanguage.xaml

<ScrollViewer x:Name="ScrollLanguage" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
    <WrapPanel Height="Auto" Width="{Binding ElementName=ScrollLanguage, Path=ViewportWidth}">
        <ItemsControl Name="LanguagePack">
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="0,20" VerticalAlignment="Stretch" Width="{Binding ElementName=ScrollLanguage, Path=ViewportWidth}">
                        <Button Click="Button_Click" Tag="{Binding CountryCode}" Content="{Binding LanguageName}" VerticalAlignment="Center" Height="150" FontSize="60" Background="#FF1A5C9E" BorderBrush="{x:Null}"/>
                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
        </ItemsControl>
    </WrapPanel>
</ScrollViewer>

SelectOptions.xaml

<TextBlock x:Name="tbTitle" TextWrapping="Wrap" Text="{StaticResource ResourceKey=SelectMerchant_Title}" FontSize="100" TextAlignment="Center" Padding="0,0,0,50" Foreground="White"/>
<Button x:Name="btnEatIn" Content="{StaticResource ResourceKey=SelectMerchant_Opt1}" VerticalAlignment="Center" Height="150" FontSize="60" Background="#FF057A5A" BorderBrush="{x:Null}"/>
<Button x:Name="btnEatIn" Content="{StaticResource ResourceKey=SelectMerchant_Opt2}" VerticalAlignment="Center" Height="150" FontSize="60" Background="#FF057A5A" BorderBrush="{x:Null}"/>

Resources.en-US.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:sys="clr-namespace:System;assembly=mscorlib">

    <!-- The name of this ResourceDictionary. Should not be localized. -->
    <sys:String x:Key="LanguageDictionaryName" Localization.Comments="$Content(DoNotLocalize)">Lang-en-US</sys:String>

    <!-- Localization specific styles -->
    <FlowDirection x:Key="FlowDirection_Default" Localization.Comments="$Content(DoNotLocalize)">LeftToRight</FlowDirection>
    <!--<FlowDirection x:Key="FlowDirection_Reverse" Localization.Comments="$Content(DoNotLocalize)">RightToLeft</FlowDirection>-->

    <!-- SELECT ORDER TYPE -->
    <sys:String x:Key="SelectMerchant_Title">Self-Service Kiosk</sys:String>
    <sys:String x:Key="SelectMerchant_Opt1">Register new applicant</sys:String>
    <sys:String x:Key="SelectMerchant_Opt2">Meal Application</sys:String>
</ResourceDictionary>

回到我所面临的,我可以通过使用资源键来显示不同的语言,但是如何在多语言显示中显示动态(非静态)的消息或状态?

例如,在验证屏幕上,我有一个 TextBlock,目前我正在从硬件订阅事件引发。如何根据已选择的语言显示状态? .

<StackPanel VerticalAlignment="Top" Margin="120,180,120,0" Grid.Row="1">
       <TextBlock x:Name="tbGeneralStatus" TextWrapping="Wrap" Text="Please wait..." TextAlignment="Center" FontSize="50" Foreground="Yellow"/>
</StackPanel>

tbGeneralStatus.Text 将显示 “请稍候..”“将您的 ID 扫描到扫描仪中”“扫描完成”、“已识别配置文件,继续交易”来自 Barcode Scanner 类的委托事件。

【问题讨论】:

  • 发布一些代码,向我们展示您迄今为止在 WPF 中的尝试
  • @LittleBit 这不是重复的问题。我可以根据我关注的链接更改不同的语言,我的问题不是根据选择切换屏幕语言,而是将多种语言处理为单个文本,例如“请稍候..”、“将您的 ID 扫描到扫描仪”、“扫描完成”、“已识别个人资料,继续交易”。在我询问这个​​论坛之前我已经搜索过这个
  • 可能您已经有一个用于硬件相关状态的枚举。在这种情况下,您需要决定如何本地化您的枚举。在这里找到不同的策略:stackoverflow.com/questions/17380900/enum-localization
  • @mahlatse 更新了我的帖子

标签: wpf multilingual resourcedictionary


【解决方案1】:

我认为您需要稍微了解一下 MVVM,以便使用 WPF 使事情变得更容易。一开始需要一些努力,但绝对值得。我以为你只是停留在如何接收和翻译状态,所以我会在查看代码后尝试提供更多信息。

快速指导,基于Enum localization,但未经部门验证。

您需要一个视图模型来充当您要更新的窗口的数据上下文。它必须实现 INotifyPropertyChange 接口才能实时更新状态。

class YourWindowViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    private string _statusText = string.Empty;
    public string StatusText
    {
        get { return _statusText; }
        set
        {
            _statusText = value;
            OnPropertyChanged("StatusText");
        }
    }

    public void YourMessageHandler(Status newStatus)
    {
        StatusText = GetLocalizedStatusText(newStatus);
    }

    private string GetLocalizedStatusText(Status newStatus)
    {
        switch (newStatus)
        {
            case Status.Wait: return Resources.StatusWaiting;
            case Status.Continue: return Resources.StatusContinue;
            case Status.Scan: return Resources.StatusScanId;
            default: return string.Empty;
        }
    }
}

public enum Status
{
    Wait,
    Scan,
    Continue
}

要绑定到您的窗口,请像这样:

<Window.DataContext>
    <local:YourWindowViewModel/>
</Window.DataContext>

并更改您的 TextBlock 控件以绑定到视图模型上的 StatusText

<StackPanel VerticalAlignment="Top" Margin="120,180,120,0" Grid.Row="1">
    <TextBlock TextWrapping="Wrap" Text="{Binding StatusText}" TextAlignment="Center" FontSize="50" Foreground="Yellow"/>
</StackPanel>

请注意,由于我不知道您的委托/msgHandler 格式,因此我放置了一个通用的“YourMessageHandler”方法来接收不断变化的状态

【讨论】:

  • 老实说,我不明白如何将 MVVM 模式应用到我当前的应用程序中。我已经阅读了各种 MVVM 教程,但是我迷失了如何在我的应用程序中完成它,特别是如何从其他文件(视图模型)控制 wpf 页面(视图),目前我正在处理页面本身后面的屏幕,而不是来自其他类(传统方法)。
猜你喜欢
  • 2014-01-14
  • 1970-01-01
  • 2017-03-12
  • 1970-01-01
  • 1970-01-01
  • 2013-01-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多