Internacionalización impulsada por CSS en JavaScript

 

 

 

  • Patrones de diseño para interfaces de IA, con Vitaly Friedman
  • Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost

  • Índice
    1. Una solución típica al problema
      1. La :langpseudoclase
      2. Cambiar el contenido de un elemento con CSS
    2. Internacionalización impulsada por CSS: ¡mejorada!
    3. Creación de una API de alto nivel
    4. Ventajas de la internacionalización impulsada por CSS
      1. ¿Es discreto?
      2. ¿Es efectivo?
      3. ¿Es fácil de mantener?
    5. Limitaciones de la internacionalización impulsada por CSS
      1. javascript
      2. Pseudoelementos
    6. Resolver problemas de accesibilidad
    7. Conclusión
      1. Otras lecturas

    En este artículo, Maksim Chemerisuk describe su enfoque con Better-dom para resolver el problema de la internacionalización. Desde el último artículo sobre esto, "Escribir una mejor biblioteca de JavaScript para DOM", ha revisado el concepto para resolver los problemas planteados a través de los comentarios. Originalmente, la solución estaba destinada a ser un conjunto de API de internacionalización para complementos, extensiones, etc. No depende en gran medida de la biblioteca Better-Dom, por lo que podría adaptarse a cualquier biblioteca JavaScript existente.

     

    Escribir código front-end a menudo requiere que los desarrolladores aborden el problema de la internacionalización en algún nivel. A pesar del estándar actual , que introduce un montón de etiquetas nuevas, simplemente agregar soporte para diferentes idiomas en un complemento de JavaScript sigue siendo complicado. Como resultado, para cualquier proyecto nuevo, debe crear una solución desde cero o adaptar varias API existentes de otros complementos que utilice.

    En este artículo, describiré mi enfoque con Better-dom para resolver el problema de la internacionalización. Desde el último artículo sobre esto, " Escribir una mejor biblioteca de JavaScript para el DOM ", he revisado el concepto para resolver los problemas planteados a través de los comentarios.

    Originalmente, la solución estaba destinada a ser un conjunto de API de internacionalización para complementos, extensiones, etc. No depende en gran medida de la biblioteca Better-Dom, por lo que podría adaptarse a cualquier biblioteca JavaScript existente.

    Una solución típica al problema

    Existen diferentes API para cambiar de idioma en JavaScript. La mayoría de ellos contienen tres funciones principales:

    1. La primera función registra una cadena localizada por clave e idioma.
    2. El segundo establece una cadena localizada para un elemento en particular.
    3. El tercero se utiliza para cambiar el idioma actual.

    Veamos un ejemplo basado en el complemento Validator de la biblioteca jQuery Tools. El complemento admite la localización de errores de validación a través de JavaScript. Los mensajes de error predeterminados se almacenan en el $.tools.validator.messagesobjeto.

    Para las claves, el complemento utiliza selectores CSS (para simplificar el código). Si desea proporcionar mensajes de error en otros idiomas, deberá utilizar el $.tools.validator.localizemétodo siguiente:

    $.tools.validator.localize("fi", { ":email" : "Virheellinen sauml;hkouml;postiosoite", ":number" : "Arvon on oltava numeerinen", "[max]" : "Arvon on oltava pienempi, kuin $1", "[min]" : "Arvon on oltava suurempi, kuin $1", "[required]" : "Kentauml;n arvo on annettava"});

    Este método completa la localización finlandesa. El $.tools.validator.messagesobjeto se vería así:

    Ahora, si desea utilizar la localización finlandesa en su formulario, debe cambiar el idioma predeterminado (inglés) a través de la langopción de configuración:

    $("#myForm").validator({lang: "fi"});

    El complemento implementa la solución típica que tenemos actualmente. Después de analizar enfoques similares a este, encontré varias deficiencias comunes:

    1. Obtrusivo Debe agregar una llamada a función JavaScript si el idioma de la página actual es diferente del predeterminado (generalmente inglés) utilizado en un complemento.
    2. Ineficaz Para cambiar un idioma dinámicamente, debe llamar a una función particular y luego tocar el DOM de cada elemento relacionado para actualizarlo innerHTML, dependiendo del nuevo idioma.
    3. Difícil de mantener Cada complemento tiene su propio conjunto de API.

    La primera deficiencia es la más crítica. Si su proyecto tiene muchos componentes, será complicado cambiar al idioma no predeterminado al cargar la página inicial para cada complemento. Si el proyecto obtiene datos mediante llamadas AJAX, entonces también se deberán realizar los mismos pasos para el contenido futuro. Intentemos solucionar todas estas deficiencias. Primero, debemos repasar los aspectos técnicos.

     

    La :langpseudoclase

    ¿ Recuerdas la :langpseudoclase de CSS2? Rara vez se usa, pero cuando lo leí por primera vez en la especificación , sentí curiosidad por saber qué pretendían resolver los autores del estándar con él:

    "Si el idioma del documento especifica cómo se determina el lenguaje humano de un elemento, es posible escribir selectores en CSS que coincidan con un elemento según su idioma".

    Un ejemplo típico citado en la especificación es el símbolo de comillas. El símbolo varía según el idioma. Para abordar esto para el qelemento (que marca una cita breve, generalmente entre comillas), podemos usar la :langpseudoclase:

    :lang(fr) q { quotes: '« ' ' »' }:lang(de) q { quotes: '»' '«' '2039' '203A' }

    Una diferencia importante entre la :langpseudoclase y un selector de atributos simple [lang=fr]es que este último coincide solo con elementos que tienen el langatributo. Por lo tanto, la :langpseudoclase siempre es más segura que la variante de atributo porque funciona correctamente incluso si el :langatributo no se ha establecido en un elemento.

    El ejemplo anterior ilustra cómo cambiar la representación del contenido según el idioma actual usando CSS . Esto es importante porque nos permite poner la lógica relacionada con el cambio de idioma en CSS .

    El ejemplo del símbolo de las comillas es bueno, pero aborda una pequeña cantidad de casos y, por lo tanto, no se puede usar en escenarios típicos: las cadenas ordinarias suelen ser muy diferentes en diferentes idiomas. Necesitamos un truco que nos permita cambiar el contenido de un elemento por completo .

    Cambiar el contenido de un elemento con CSS

    Los navegadores que admiten la especificación CSS2 introdujeron pseudoelementos que, en lugar de describir un estado particular como las pseudoclases, nos permiten diseñar ciertas partes de un documento.

    Tenga en cuenta que Internet Explorer 8 tiene un problema conocido en su implementación, ya que no admite la sintaxis de dos puntos para definir pseudoelementos. El problema se solucionó en Internet Explorer 9, por lo que si necesita admitir la versión 8, asegúrese de utilizar la sintaxis de dos puntos para cualquier pseudoelemento.

    Las verdaderas joyas son ::beforey ::after, que te permiten agregar contenido adicional antes o después de un elemento innerHTML. Pueden parecer simples, pero tienen muchos casos de uso que resuelven problemas de una manera muy clara.

    Empecemos con lo básico. Ambos ::beforee ::afterintroducen una propiedad CSS, content. Esta nueva propiedad define qué contenido anteponer o agregar a un elemento innerHTML. El valor del contentatributo puede ser cualquiera de los siguientes:

     

    • cadena de texto (pero no una cadena HTML),
    • imagen,
    • encimera,
    • valor(es) de atributo.

    Nuestro principal interés es agregar una cadena de texto. Imaginemos que tenemos CSS como este:

    #hello::before { content: "Hello ";}

    Si el elemento con el ID de hellocontiene la cadena world, entonces el navegador mostrará Hello world.

    pworld/p

    Podríamos reescribir nuestro CSS usando la attrfunción:

    #hello::before { content: attr(id) " ";}

    Entonces, el elemento se mostraría hello worlden minúsculas, porque el idatributo tiene un valor de cadena en minúsculas.

    Ahora imagina que el helloelemento no tiene ningún contenido interno. Podríamos cambiar su representación completamente usando CSS. Esto resulta útil cuando usamos el truco en combinación con la :langpseudoclase:

    #hello::before { content: "Hello";}#hello:lang(de)::before { content: "Hallo";}#hello:lang(ru)::before { content: "Привет";}

    Nuestro elemento helloahora cambiará según el idioma de la página web actual; no es necesario llamar a ninguna función para cambiar su representación según el idioma de la página web actual. La localización se maneja mediante el valor del langatributo en el htmlelemento y varias reglas CSS adicionales. Esto es lo que yo llamo internacionalización impulsada por CSS .

    Internacionalización impulsada por CSS: ¡mejorada!

    Desde que publiqué la idea original, escuché a varias personas quejarse de que esas reglas podrían agregar mucho CSS. Debido a que mi objetivo inicial era usarlo para pequeños complementos de JavaScript, ni siquiera pensé que pudiera usarse ampliamente en la página. Sin embargo, la filosofía de CSS es contener la lógica de presentación, y estaba intentando usarla para almacenar varias cadenas multilingües, que en realidad pertenecen al contenido de la página web. No parecía correcto.

    Después de pensarlo un poco, desarrollé una versión mejorada que resuelve este problema. En lugar de poner cadenas de texto en CSS, uso la attrfunción para leer un atributo específico del idioma data-i18n-*que contiene una cadena localizada. Esto restringe la cantidad de reglas CSS que podemos agregar: una regla por nuevo idioma.

    Reescribamos la localización del helloelemento anterior con este método mejorado. Esta vez, vamos a darle a nuestra página web algo de CSS global para admitir alemán y ruso, además del inglés: Oye Quotes Lifestyle

    /* English (default language)*/[data-i18n]::before { content: attr(data-i18n);}/* German */[data-i18n-de]:lang(de)::before { content: attr(data-i18n-de);}/* Russian */[data-i18n-ru]:lang(ru)::before { content: attr(data-i18n-ru);}

    Tenga en cuenta que el código anterior no contiene ninguna cadena constante: las reglas CSS son genéricas.

     

    Ahora, en lugar de colocar cadenas de texto localizadas en CSS, agreguemos varios data-*atributos personalizados específicos del idioma que contengan los valores apropiados. Nuestro helloelemento debería verse como el siguiente, que mostrará contenido diferente según el idioma de la página web actual:

    p data-18n="Hello" data-i18n-de="Hallo" data-i18n-ru="Привет"p

    ¡Eso es todo! Nos queda un CSS adicional mínimo, que describe solo la lógica global para cambiar la representación de un elemento según el idioma actual, y nuestras cadenas localizadas son completamente HTML .

    Creación de una API de alto nivel

    En Better-dom, hay dos funciones para respaldar la internacionalización impulsada por CSS: $Element.prototype.i18ny DOM.importStrings. La primera función cambia la cadena localizada para un elemento en particular. Para hacerlo simple, normalmente uso las cadenas en inglés como claves y valores predeterminados. Hace que JavaScript sea más legible y fácil de entender. Por ejemplo:

    myelement.i18n("Hello");

    Esto establece una Hellocadena localizada como contenido interno de myelement, donde myelementhay una instancia de la $Elementclase, que resulta ser un tipo contenedor para un elemento DOM nativo en better-dom. La línea anterior hace varias cosas detrás de escena:

    • Determina el conjunto actual de idiomas registrados.
    • Para cada idioma, lee una cadena con la clave Helloen el almacenamiento interno de las localizaciones registradas y utiliza el valor para establecer un data-i18n-*atributo apropiado para el elemento.
    • Limpia los elementos innerHTMLpara evitar que se muestre un resultado extraño.

    Puedes ver el código fuente $Element.prototype.i18nen GitHub. El objetivo de este i18nmétodo es actualizar nuestros data-*atributos personalizados específicos del idioma. Por ejemplo:

    pp

    Después de la llamada, este elemento vacío pasaría a ser el siguiente, si hemos registrado todas las cadenas localizadas para alemán y ruso:

    p data-i18n="Hello" data-i18n-de="Hallo" data-i18n-ru="Привет"p

    Además, el i18nmétodo admite un segundo argumento opcional, un mapa clave-valor de las variables:

    // Use {varName} in the string template to define// various parts of a localized string.myelement.i18n("Hello {user}", {user: username});// Use array and {varNumber} to define a numeric// set of variables.myelement.i18n("Hello {0}", [username]);

    Para registrar una cadena localizada, utilice el método estático DOM.importStringspara pasar tres argumentos:

    • el idioma de destino,
    • la clave de cadena localizada (generalmente solo una cadena en inglés),
    • el valor de cadena localizado.

    Para el ejemplo anterior, antes de invocar el método i18n, necesitaríamos realizar las siguientes llamadas:

    DOM.importStrings("de", "Hello {user}", "Hallo {user}");DOM.importStrings("ru", "Hello {user}", "Привет {user}");DOM.importStrings("de", "Hello {0}", "Hallo {0}");DOM.importStrings("ru", "Hello {0}", "Привет {0}")

    Detrás de escena, DOM.importStringsse están dando un par de pasos. En primer lugar, comprueba si se ha registrado el idioma de destino. Si no, agrega una regla CSS global:

     

    [data-i18n-{lang}]:lang({lang})::before { content: attr(data-i18n-{lang});}

    Luego, guarda una cadena localizada, el par clave-valor, en el almacenamiento interno. Puedes ver el código fuente DOM.importStringsen GitHub.

    Con DOM.importStrings, también podemos anular cadenas en inglés existentes. Esto podría resultar útil si necesita adaptar cadenas a sus necesidades sin cambiar el código fuente:

    DOM.importStrings("en", "Hello {user}", "Hey {user}");DOM.importStrings("en", "Hello {0}", "Hey {0}");

    Como puede ver, estos ayudantes nos liberan de tener que escribir código repetitivo y nos permiten utilizar la internacionalización basada en CSS en nuestras páginas web muy fácilmente.

    Ventajas de la internacionalización impulsada por CSS

    Repasemos la lista de problemas identificados en la primera parte del artículo.

    ¿Es discreto?

    Con la solución original, dijimos que había que agregar una llamada de función de JavaScript si el idioma de la página actual era diferente del predeterminado (generalmente inglés) utilizado en el complemento. Una gran ventaja de la internacionalización impulsada por CSS es que utiliza :langpseudoclases para cambiar al idioma de destino. Esto significa que tener un valor apropiado del langatributo en el htmlelemento es suficiente para elegir la cadena localizada que necesita.

    Por lo tanto, con la internacionalización basada en CSS, no es necesario realizar ninguna llamada al cargar la página, incluso si el idioma de la página web es diferente del idioma predeterminado. Entonces, es discreto.

    ¿Es efectivo?

    Para cambiar un idioma dinámicamente, tenías que llamar a una función particular y luego tocar el DOM de cada elemento relacionado para actualizarlo innerHTML, dependiendo del nuevo idioma. Ahora, la representación de un elemento la maneja el ::beforepseudoelemento. Para cambiar a otro idioma de forma dinámica a nivel global, basta con cambiar el langatributo del htmlelemento (usando API nativas, por ejemplo). O, para localizar el cambio de idioma, simplemente cambie el langatributo de un subárbol en particular.

    Además, no es necesario actualizar innerHTMLtodos los elementos relacionados para cambiar el idioma actual de forma dinámica. Esto lo maneja CSS. Entonces, nuestro código ahora es más efectivo.

    ¿Es fácil de mantener?

    Originalmente, cada complemento tenía que tener su propio conjunto de API. Una solución sólida para la internacionalización debería ser parte de cada biblioteca seria que toque el DOM. La internacionalización impulsada por CSS ha sido parte de mi proyecto Better-dom desde el principio porque tenía que abordar este problema. Lo usé en una mejor validación de formularios para personalizar la información sobre herramientas de validación de formularios. Más tarde, lo usé en Better-dateinput-polyfill y Better-prettydate . Tener API para la internacionalización integradas en la biblioteca principal reduce mi código repetitivo y lo hace más consistente, estable y, lo adivinaste, más fácil de mantener.

     

    Limitaciones de la internacionalización impulsada por CSS

    ¿Qué pasa con las desventajas de la internacionalización impulsada por CSS?

    javascript

    Primero, la solución depende de JavaScript. Poner cadenas localizadas en data-*atributos en páginas web estáticas no es una buena idea porque el marcado se vería extraño, semánticamente hablando. Por lo tanto, recomendaría usar un conjunto de API de JavaScript (como las que se describen anteriormente) para que el concepto sea viable.

    Asegúrese de usarlo en partes de sus páginas que no sean críticas para el SEO, porque a los rastreadores de los motores de búsqueda les resultará difícil indexar correctamente el marcado resultante. Recuerde que esta solución se desarrolló originalmente como un conjunto de API de localización para complementos y extensiones de JavaScript.

    Pseudoelementos

    Algunas limitaciones también surgen del uso de los pseudoelementos ::beforey :::after

    1. La contentpropiedad no funciona con elementos vacíos ni con ciertos elementos de formulario, incluidos inputy select.
    2. La contentpropiedad no puede mostrar etiquetas HTML.
    3. No hay forma de localizar los valores de los atributos de un elemento HTML (como placeholdery title).

    En cuanto a la primera limitación, la falta de soporte para elementos vacíos no es un gran problema. Los elementos no contienen ningún contenido, por lo que no hay nada que localizar. Pero el problema se volvió real cuando estaba trabajando con el inputelemento en better-dateinput-polyfill. Para resolver esto, oculté el elemento original y agregué un spanelemento adicional como contenedor que contenía la cadena localizada que necesitaba mostrar. No muy elegante, pero funcionó.

    La segunda y tercera limitaciones son más fáciles de evitar por ahora. Tengo algunas ideas sobre cómo resolverlas, pero no tengo casos de uso para ellas. Por supuesto, una solución elegante es bienvenida.

    Resolver problemas de accesibilidad

    Actualización (24.06.2014) : varias personas han notado en la sección de comentarios a continuación que el uso de pseudoelementos para mostrar cadenas localizadas tiene importantes problemas de accesibilidad. El primer problema es que un contenido, generado a través de ::beforey ::afterno se puede seleccionar con el mouse. La segunda es que los lectores de pantalla pasan completamente por alto dicho contenido. Por lo tanto, he mejorado el concepto para abordar estos problemas y te invito a ver la demostración . Todavía no forma parte de las API de Better-dom, pero se agregará en la versión más cercana.

    La principal diferencia es que en lugar de pseudoelementos, el contenido se muestra dentro de spanelementos específicos del idioma. No es posible mostrar varios spanmensajes de correo electrónico al mismo tiempo porque spanlos mensajes del idioma no actual están ocultos mediante la display:noneregla. Los lectores de pantalla omiten esos elementos ocultos, que es exactamente lo que necesitamos.

    El uso de mensajes internos spanen lugar de pseudoelementos también soluciona la selección de texto mediante el mouse y la imposibilidad de usar etiquetas HTML dentro de cadenas localizadas. Sin embargo, todavía existen problemas con los elementos del formulario y la localización de los valores de los atributos.

    Conclusión

    Con suerte, pronto se agregará a la especificación una solución simple al problema de la internacionalización en JavaScript. Hasta entonces, los desarrolladores front-end tendremos que reinventar la rueda o adaptarnos unos a otros.

    Mientras construía esta solución de internacionalización basada en CSS, me inspiraron las ideas contenidas en la propia especificación CSS2. Quizás los autores ya lo tenían en mente. ¿Quién sabe?

    Después de varias iteraciones, la solución solidificó. Claro, todavía tiene limitaciones. Sin embargo, sus ventajas, como ser totalmente discreto, harán que su código sea sustancialmente más limpio y más fácil de mantener. Con suerte, este artículo te ha ayudado a comprender lo que hice detrás de escena para lograrlo.

    No dudes en compartir tus opiniones sobre la biblioteca de Better-dom en GitHub o en la sección de comentarios a continuación.

    Créditos de las imágenes de la portada: Dmitry Baranovskiy .

    Otras lecturas

    • No se pierda en la traducción: cómo realizar la localización de sitios web
    • ¿Debería preguntarle al usuario o a su navegador?
    • 12 mandamientos de la localización de software
    • Creación de diseños web para dispositivos plegables y de pantalla dual

    (al, il, mrn)Explora más en

    • Codificación
    • CSS
    • javascript
    • Técnicas





    Tal vez te puede interesar:

    1. ¿Deberían abrirse los enlaces en ventanas nuevas?
    2. 24 excelentes tutoriales de AJAX
    3. 70 técnicas nuevas y útiles de AJAX y JavaScript
    4. Más de 45 excelentes recursos y repositorios de fragmentos de código

    Internacionalización impulsada por CSS en JavaScript

    Internacionalización impulsada por CSS en JavaScript

    Patrones de diseño para interfaces de IA, con Vitaly Friedman Creación y mantenimiento de sistemas de diseño exitosos, con Brad Fost Índice

    programar

    es

    https://aprendeprogramando.es/static/images/programar-internacionalizacion-impulsada-por-css-en-javascript-849-0.jpg

    2024-05-20

     

    Internacionalización impulsada por CSS en JavaScript
    Internacionalización impulsada por CSS en JavaScript

    Si crees que alguno de los contenidos (texto, imagenes o multimedia) en esta página infringe tus derechos relativos a propiedad intelectual, marcas registradas o cualquier otro de tus derechos, por favor ponte en contacto con nosotros en el mail [email protected] y retiraremos este contenido inmediatamente

     

     

    Top 20