wpf - 以多语言动态显示不同的消息
问题描述
我已经从这里成功创建了一个多语言应用程序。能够更改语言时我很棒。
现在我陷入了这种境地。我的应用程序使用硬件运行。所以有一个屏幕与硬件交互并显示状态文本块。消息将根据硬件的响应而变化,例如“请稍候..”、“将您的 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 扫描到扫描仪”、“扫描完成”、“已识别个人资料,继续交易” 。
解决方案
我认为您需要稍微了解一下 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”方法,该方法接收不断变化的状态
推荐阅读
- javascript - 承诺解决未定义,但数据仍在发布
- python - Python 无法导入名称 Django
- javascript - 在 React 中添加 3 个字段
- android - 在哪里放置我的 android 应用程序所需的 c++ .so 库
- python - 我如何改进这段代码以使其无错误
- python - 赋值前引用的局部变量 'q'
- java - 如何使 JPanel 大小适用于 JFrame?
- c# - 如何在 C# 中将 Treeview 转换为 JSON
- python - 在单个文件中构建多个文件,例如 .py .png
- javascript - JS函数if/else切换显示不起作用