首页 > 解决方案 > 以多语言动态显示不同的消息

问题描述

我已经从这里成功创建了一个多语言应用程序。能够更改语言时我很棒。

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

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

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

编辑[我尝试了什么]

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

应用程序.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;
        }
    }
}

选择语言.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);
    }
}

选择语言.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>

选择选项.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 将显示来自 Barcode Scanner 类的委托事件的“请稍候..”“将您的 ID 扫描到扫描仪”“扫描完成”“已识别个人资料,继续交易” 。

标签: wpfmultilingualresourcedictionary

解决方案


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

基于枚举本地化但未经部门验证的快速指南。

您需要一个视图模型来充当要更新的窗口的数据上下文。它必须实现 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”方法,该方法接收不断变化的状态


推荐阅读