Saltar al contenido

Globalización con propiedades adjuntas en WPF

Después de averiguar sobre las propiedades adjuntas, me propuse crear propiedades adjuntas que seleccionaran automáticamente el texto, el encabezado o la información sobre herramientas que coincidieran con el idioma actual de la aplicación.

Como ejemplo, mostraré cómo puedes usar las propiedades adjuntas con TextBlocks. Las propiedades adjuntas funcionan como métodos de extensión, aquí está el código para añadir el texto traducido a un TextBlock :

Globalización con propiedades adjuntas en WPF
Globalización con propiedades adjuntas en WPF
12345678910111213141516171819202122232425262728293031323334espacio de nombres AlgunosEspacio de nombres.Extensiones{clase públicaUiExtensiones{públicastáticasSóloDependenciaPropiedadTexto turcoPropiedad = DependenciaPropiedad. RegisterAttached("TurkishText",typeof(string),typeof(UiExtensions),newPropertyMetadata(default(string)));publicstaticreadonlyDependencyProperty EnglishTextProperty = DependencyProperty. RegisterAttached("EnglishText",typeof(string),typeof(UiExtensions),newPropertyMetadata(default(string)));publicstaticvoidSetTurkishText(UIElement element,stringvalue){ element.SetValue(TurkishTextProperty,value);}publicstaticstringGetTurkishText(UIElement element){return(string) element. GetValue(TurkishTextProperty);}publicstaticstringGetEnglishText(UIElement element,stringvalue){ element.SetValue(EnglishTextProperty,value);}publicstaticstringGetEnglishText(UIElement element){return(string) element.GetValue(EnglishTextProperty);}}

csharp

El código anterior es bastante simple. Primero, creamos 2 propiedades separadas para ambos idiomas, que se llaman TextoTurco y TextoInglés. Estas propiedades serán de tipo cadena . Luego definimos los getters y setters para estas propiedades.

Ahora que hemos definido las propiedades, podemos añadirlas a nuestro código XAML.

123456789<Windowxmlns:x="http://schemas.microsoft.com/winfx/2006/xaml "xmlns:d="http://schemas.microsoft.com/expression/blend/2008 "xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006 "xmlns:uiExtensions="clr-namespace:SomeNamespace.Extensions "mc:Ignorable="d "x:Class="SomeNamespace.MainWindow "Title="MainWindow"

xml

Así que ahora podemos usar nuestra recién creada extensión de esta manera:

123<TextBlockText="Example English Text "uiExtensions:UiExtensions.TurkishText="Örnek Türkçe Yazı "uiExtensions:UiExtensions.EnglishText="Example English Text"/>

xml

Sin embargo, al ejecutar la aplicación, vemos que el texto no cambia realmente. Todavía tenemos que decirle a la aplicación que queremos cambiar el lenguaje de alguna manera.

Podemos simplemente escribir una clase de cambio de idioma y unas cuantas clases de ayuda para hacer este trabajo por nosotros.

12345678namespace SomeNamespace.Globalization{publicstaticclassAppLanguages{publicstaticstring English ="English";publicstaticstring Turkish ="Türkçe";}}

csharp

12345678910111213141516171819202122232425namespace SomeNamespace.Utilities{publicstaticclassUiUtilities{publicstatic IEnumerable<T>GetChildren<T>(DependencyObject depObj)where T : DependencyObject {if(depObj !=null){for(int i =0; i < VisualTreeHelper. GetChildrenCount(depObj); i++){DependencyObject child = VisualTreeHelper.GetChild(depObj, i);if(child !=null&& child is T){yieldreturn(T)child;}foreach(T childOfChild inGetChildren<T>(child)){yieldreturn childOfChild;}}}}

csharp

12345678910111213141516171819202122232425262728293031323334namespace SomeNamespace. Globalización{clase públicaCambio de Idioma{lenguaje de lectura privadaUIElement _elemento;cadena de lectura privada _idioma;cambio de idioma público(elemento UIElement,lenguaje de cadena){ _elemento = elemento; _idioma = lenguaje;}publicvoidChange(){var textBlocks = Utilidades. GetChildren<TextBlock,_elemento;if(_language == AppLanguages.English){foreach(var textBlock in textBlocks){ textblock.Text = UiExtensions. GetEnglishText(textblock);}}elseif(_language == AppLanguages.Turkish){foreach(var textblock in textBlocks){ textblock.Text = UiExtensions.GetTurkishText(textblock);}}}

csharp

El código del Cambiador de Idioma debería permitir a nuestra WPF encontrar todos los Bloques de Texto y cambiar su idioma a cualquier configuración de idioma que decidamos.

Sin embargo, hay un gran problema aquí. Nuestra aplicación intentará cambiar TODOS los bloques de texto de nuestra XAML. Así que si no puede encontrar ningún texto en inglés o en turco, la aplicación por defecto vaciará las cadenas que no son muy deseables porque no queremos que ALL nuestros TextBlocks cambien, sólo los bloques que son de texto en inglés.

Para resolver este problema necesitamos una bandera para que la clase de Cambio de Idioma decida si la aplicación debe traducirse o no.

Para esto necesitamos otra propiedad adjunta:

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748espacio de nombres SomeNamespace.Extensiones{clase públicaUiExtensiones{públicastáticasSóloDependenciaPropiedadTexto turcoPropiedad = DependencyProperty. RegisterAttached("TurkishText",typeof(string),typeof(UiExtensions),newPropertyMetadata(default(string)));publicstaticreadonlyDependencyProperty EnglishTextProperty = DependencyProperty. RegisterAttached("EnglishText",typeof(string),typeof(UiExtensions),newPropertyMetadata(default(string)));publicstaticreadonlyDependencyProperty ChangeLanguageProperty = DependencyProperty. RegisterAttached("ChangeLanguage",typeof(bool),typeof(UiExtensions),newPropertyMetadata(default(bool)));publicstaticvoidSetTurkishText(UIElement element,stringvalue){ element. SetValue(TurkishTextProperty,value);}publicstaticstringGetTurkishText(UIElement element){ return(string) element.GetValue(TurkishTextProperty);}publicstaticvoidSetEnglishText(UIElement element,stringvalue){ element. SetValue(EnglishTextProperty,value);}publicstaticstringGetEnglishText(UIElement element){return(string) element.GetValue(EnglishTextProperty);}publicstaticvoidSetChangeLanguage(UIElement element,boolvalue){ element. SetValue(ChangeLanguageProperty,value);}publicstaticboolGetChangeLanguage(UIElement element){return(bool) element.GetValue(ChangeLanguageProperty);}}}

csharp

La propiedad que hemos añadido es de tipo bool y ayudará a LanguageChanger a saltarse este TextBlock o no.

También tenemos que cambiar nuestro código XAML en consecuencia y añadir nuestra nueva propiedad creada.

1234<TextBlockText="Example English Text "uiExtensions:UiExtensions.ChangeLanguage="True "uiExtensions:UiExtensions.TurkishText="Örnek Türkçe Yazı "uiExtensions:UiExtensions.EnglishText="Example English Text"/
xml

Cuando ChangeLanguage es verdadero, entonces procesará ese Bloque de Texto, si es falso, entonces lo omitirá.

Finalmente necesitamos editar nuestro LanguageChanger :

1234567891011121314151617181920212223242526272829303132333435363738394041namespace SomeNamespace. Globalización{clase públicaCambio de Idioma{lenguaje de lectura privadaUIElement _elemento;cadena de lectura privada _idioma;cambio de idioma público(elemento UIElement,lenguaje de cadena){ _elemento = elemento; _idioma = lenguaje;}publicvoidChange(){var textBlocks = Utilidades. GetChildren<TextBlock;;_elementos;if(_language == AppLanguages.English){foreach(var textBlock in textBlocks){if(UiExtensions.GetChangeLanguage(textblock)){ textblock.Text = UiExtensions. GetEnglishText(textblock);}}}elseif(_language == AppLanguages.Turkish){foreach(var textblock in textBlocks){if(UiExtensions.GetChangeLanguage(textblock)){ textblock.Text = UiExtensions.GetTurkishText(textblock);}}}

csharp

Ahora puedes usar tus propiedades personalizadas recién creadas para crear traducciones para cada bloque de texto de tu aplicación puramente en XAML.

¿Nos detenemos a traducir sólo los TextBlocks? ¡Claro que no!

Podemos usar las propiedades adjuntas en cada tipo de cadena que queramos traducir. Por ejemplo, cabeceras, menús contextuales, contenidos, etc. Simplemente crea algunas propiedades adjuntas, añádelas a tu LanguageChanger, o a cualquier clase que estés usando para la globalización, y edita tu código XAML como hicimos con TextBlocks.