前言 本章講述正確添加語言資源的方式,以及一段語言資源的多種樣式顯示。 例如:“@Winter,你好!感謝已使用軟體 800 天!” 在添加如上多語言資源項時,“XX,你好!感謝已使用軟體 X 天!” 那麼,你是怎麼添加語言資源的呢? 分別添加,“,你好!”、“感謝已使用軟體”、“年”3個,再通過界 ...
前言
本章講述正確添加語言資源的方式,以及一段語言資源的多種樣式顯示。
例如:“@Winter,你好!感謝已使用軟體 800 天!”
在添加如上多語言資源項時,“XX,你好!感謝已使用軟體 X 天!”
那麼,你是怎麼添加語言資源的呢?
分別添加,“,你好!”、“感謝已使用軟體”、“年”3個,再通過界面綁定動態變數 昵稱和使用天數?
假如你是按照如上添加語言資源的,那麼問題來了,添加如上英文語言資源呢?是不是也分別添加單個資源,再拼湊綁定?
添加語言資源
正確的做法是,添加整個語言資源,“{0},你好!感謝已使用軟體 {1} 天!”
原因:使用格式化的語言資源,那麼將中文資源翻譯成英文或者其它語言後,得到的譯文才符合原有的含義。
不然,一段一段翻譯後的文本拼接,得到的只會是,中式英文之類的。。。
語言格式化控制項
在添加了語言資源後,如何在WPF界面顯示呢?
簡單的文本樣式
假如只是實現簡單的文本拼接,且樣式相同時,可以直接綁定動態變數值 - 昵稱和使用年限,然後通過StringFormat或者Conveter去處理格式化文本。
- 如果只有一個動態變數,直接使用StringFormat處理即可。Text="{Binding Name,StringFormat={StaticResource TheFormatedText}}"
- 如果多個動態變數,可以使用多重綁定+Converter,實現文本格式化。
複雜的文本樣式
假如格式化文本,需要實現複雜的樣式和操作,例如:
- 文本+按鈕
- 文本+超鏈接
- 加粗文本+普通文本+紅色文本
以上,如何處理?
語言格式化控制項實現
Demo顯示效果:
1. 添加一個繼承TextBlock的用戶控制項ComplexTextBlock
1 /// <summary> 2 /// 解決複雜文本格式化樣式的文本框控制項 3 /// 如"已使用軟體 {0} 天",天數需要標紅加粗,或者用於【文本】【文字按鈕】【文本】的組合 4 /// </summary> 5 public class ComplexTextBlock : TextBlock 6 { 7 8 }
2. 重寫文本依賴屬性
為了監聽文本變更,所以重寫文本的依賴屬性。文本變更事件處理,之後會詳細介紹~
1 public new static DependencyProperty TextProperty = 2 DependencyProperty.Register("Text", typeof(string), typeof(ComplexTextBlock), new PropertyMetadata(TextPropertyChanged)); 3 4 public static string GetText(DependencyObject element) 5 { 6 return (string)element.GetValue(TextProperty); 7 } 8 public static void SetText(DependencyObject element, string value) 9 { 10 element.SetValue(TextProperty, value); 11 } 12 13 private static void TextPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 14 { 15 LoadComplexContent(d); 16 }
3. 添加動態變數顯示的控制項列表
如“@Winter,你好!感謝已使用軟體 800 天,可查看詳情!”,可以將昵稱、使用時間、詳情,分別設置為文本控制項、文本控制項、超鏈接按鈕,然後添加到動態控制項列表中。
1 public static DependencyProperty ContentFormatsProperty = 2 DependencyProperty.Register("ContentFormats", typeof(ContentFormatsCollection), typeof(ComplexTextBlock), 3 new PropertyMetadata(default(ContentFormatsCollection), ContentFormatsPropertyChanged)); 4 5 /// <summary> 6 /// 格式化內容列表 7 /// </summary> 8 public ContentFormatsCollection ContentFormats 9 { 10 get => (ContentFormatsCollection)GetValue(ContentFormatsProperty); 11 set => SetValue(ContentFormatsProperty, value); 12 } 13 14 private static void ContentFormatsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 15 { 16 LoadComplexContent(d); 17 }
4. 處理格式化文本
處理方法,主要是將當前格式化的文本拆分為多個文本段落和格式化字元“{0}”,然後將待顯示的動態變數(文本控制項/按鈕等)替換拆分後列表中的格式化字元。組合成完整的顯示文本。
其中,需要註意的是,文本的樣式繼承。
1 private const string FormattedKey = "{0}"; 2 3 /// <summary> 4 /// 載入複雜文本 5 /// </summary> 6 /// <param name="dependencyObject"></param> 7 private static void LoadComplexContent(DependencyObject dependencyObject) 8 { 9 if (!(dependencyObject is ComplexTextBlock complexTextBlock)) 10 { 11 return; 12 } 13 14 string text = GetText(complexTextBlock); 15 var contentFormats = complexTextBlock.ContentFormats; 16 17 if (string.IsNullOrEmpty(text) || contentFormats == null || contentFormats.Count == 0) 18 { 19 return; 20 } 21 22 for (int i = 0; i < contentFormats.Count; i++) 23 { 24 text = text.Replace(i.ToString(), "0"); 25 } 26 27 var list = GetTextList(text); 28 29 //清空當前文本 30 complexTextBlock.Text = null; 31 //分段載入文本 32 var stackPanel = new StackPanel(); 33 stackPanel.Orientation = Orientation.Horizontal; 34 stackPanel.VerticalAlignment = VerticalAlignment.Center; 35 36 int formatIndex = 0; 37 foreach (var paraText in list) 38 { 39 if (paraText == FormattedKey) 40 { 41 stackPanel.Children.Add(contentFormats[formatIndex++]); 42 } 43 else 44 { 45 var textLine = new TextBlock(); 46 if (complexTextBlock.Style != null) 47 { 48 textLine.Style = complexTextBlock.Style; 49 } 50 else 51 { 52 textLine.VerticalAlignment = complexTextBlock.VerticalAlignment; 53 textLine.HorizontalAlignment = complexTextBlock.HorizontalAlignment; 54 textLine.Background = complexTextBlock.Background; 55 textLine.FontFamily = complexTextBlock.FontFamily; 56 textLine.FontSize = complexTextBlock.FontSize; 57 textLine.Foreground = complexTextBlock.Foreground; 58 textLine.FontWeight = complexTextBlock.FontWeight; 59 textLine.FontStyle = complexTextBlock.FontStyle; 60 } 61 textLine.Text = paraText; 62 stackPanel.Children.Add(textLine); 63 } 64 } 65 complexTextBlock.Inlines.Add(stackPanel); 66 } 67 68 /// <summary> 69 /// 獲取分段文本列表 70 /// </summary> 71 /// <param name="text"></param> 72 /// <returns></returns> 73 private static List<string> GetTextList(string text) 74 { 75 var list = new List<string>(); 76 var formatIndex = text.IndexOf(FormattedKey, StringComparison.Ordinal); 77 78 //1.不存在格式化關鍵字,則直接返回當前文本 79 if (formatIndex == -1) 80 { 81 list.Add(text); 82 return list; 83 } 84 85 //2.存在格式化關鍵字 86 if (formatIndex == 0) 87 { 88 list.Add(FormattedKey); 89 } 90 else 91 { 92 list.Add(text.Substring(0, formatIndex)); 93 list.Add(FormattedKey); 94 } 95 96 //獲取下一格式化文本 97 if (formatIndex < text.Length) 98 { 99 list.AddRange(GetTextList(text.Substring(formatIndex + FormattedKey.Length))); 100 } 101 102 return list; 103 }
5. 控制項的使用
界面顯示:
調用實現:
1 <local:ComplexTextBlock Text="小王,好好{0},詳見{1}!" Style="{StaticResource ComplexTextBlockStyle}" Margin="0 10 0 0"> 2 <local:ComplexTextBlock.ContentFormats> 3 <local:ContentFormatsCollection> 4 <Button Content="學習" Click="ButtonBase_OnClick" VerticalAlignment="Center"></Button> 5 <Button x:Name="LinkedButton" Content="學習計劃" Click="LinkedButton_OnClick" Style="{StaticResource LinkedTextBlock}" VerticalAlignment="Center"/> 6 </local:ContentFormatsCollection> 7 </local:ComplexTextBlock.ContentFormats> 8 </local:ComplexTextBlock>
詳細代碼實現,可查看Github源碼Demo