Buen dia habravchane!
En este artículo hablaré sobre una solución simple al problema de administrar texto y localización en una aplicación web, que puede implementar usted mismo o usar una lista para usar.

Hace tiempo que quería compartir mis propios pensamientos y experiencias ... y, por supuesto, hablar de por vida.
AntecedentesObviamente, ya existen soluciones para administrar el texto y la localización, pero no me convenían por varias razones: engorroso, incómodo de usar, no adecuado, no corresponde a mi visión de resolver este problema, carece de funcionalidad.
Además, realmente no me gustan las bibliotecas de terceros debido a su tendencia a crecer (esto es cuando solo necesitamos una pequeña parte de toda la funcionalidad).
La empresa en la que trabajo tiene su propia solución, pero, en mi opinión, también está lejos de ser ideal. Y la necesidad de compatibilidad con versiones anteriores hace que sea innecesariamente complicado.
En algún momento, quería algo simple, fácil, comprensible e infinitamente expandible para diferentes tareas.
Declaración del problema.
Todo parece estar claro aquí. O no? Pensemos lo que nos gustaría.
Necesitamos de alguna manera obtener textos localizados. Los textos pueden contener variables. ¿Se pueden localizar las variables también? En teoría sí. ¿Y si la variable es una fecha o un número? Más soporte de rebajas. Y finalmente, alguna solución en caso de que no se encuentre el texto.
Implementación
La base será un objeto simple, donde la clave es el código de texto y el valor es el texto real que necesita, nada complicado:
const textsBundle = { 'button.open': 'Open', 'button.save': 'Save', }; function TextManager(texts) { this.getText = function(code) { return texts[code]; }; } const textManager = new TextManager(textsBundle); textManager.getText('button.open');
Un poco sobre el nombre de las teclas.El nombre de las claves es un tema aparte. Es mejor acordar de inmediato una sola opción, de lo contrario, se "agitarán" diferentes teclas :). No hay una solución única, elija lo que considere más conveniente y más coherente con el proyecto. Personalmente, me gusta el primero:
'button.open.label'
'button.open.help_text'
o
'button.label.open'
'button.help_text.open'
o
'label.button.open'
'help_text.button.open'
A continuación, necesitamos un mecanismo que pueda realizar algún tipo de manipulación con el texto antes de que dé el resultado final, por ejemplo, insertar parámetros. Y luego tuve una idea interesante: ¿qué pasa si usamos middleware para manipular texto? Después de todo, no he visto tales decisiones ... bueno, o me he visto mal :)
Decidimos los requisitos para el middleware: en la entrada, el middleware aceptará texto y parámetros, y dará el texto resultante, después de las manipulaciones necesarias.
El primer middleware recibirá el texto original, y los siguientes recibirán el texto del middleware anterior. Agreguemos el código que falta:
function TextManager(texts, middleware) { function applyMiddleware(text, parameters, code) { if (!middleware) return text; return middleware.reduce((prevText, middlewareItem) => middlewareItem(prevText, parameters, code), text); } this.getText = function(code, parameters) { return applyMiddleware(texts[code], parameters, code); }; }
TextManager puede generar texto por su código. También se puede ampliar utilizando middleware, que abre muchas posibilidades, por ejemplo:
- manejar el caso cuando no se encuentra el texto
- uso de parámetros en el texto
- localización de parámetros
- usar rebajas
- protección de texto, etc.
Practica
Vamos a escribir un par de middleware necesario. Los necesitarás al 100%.
InsertParams
Permite el uso de parámetros en textos. Por ejemplo, debemos mostrar el texto "Hola {{nombre de usuario}}". El siguiente middleware proporcionará esto:
function InsertParams(text, parameters) { if (!text) return text; if (!parameters) return text; let nextText = text; for (let key in parameters) { if (parameters.hasOwnProperty(key)) { nextText = text.replace('{{' + key + '}}', parameters[key]); } } return nextText; }
UseCodeIfNoText
Le permite devolver el código de texto, en lugar de undefined
, si no se encontró el texto:
function UseCodeIfNoText(text, parameters, code) { return text ? text : code; }
Total recibimos aproximadamente el siguiente uso:
const textsBundle = { 'text.hello': 'Hello', 'text.hello_with_numeric_parameter': 'Hello {{0}}', 'text.hello_with_named_parameter': 'Hello {{username}}', }; const textManager = new TextManager(textsBundle, [InsertParams, UseCodeIfNoText]); textManager.getText('nonexistent.code')
Ejemplo de aplicación de reacción
Primero, inicialice el TextManager
nivel TextManager
y agregue textos.
En mi opinión, es mejor extraer textos del servidor, pero por simplicidad no haré esto.
const textsBundle = { 'text.hello': 'Hello {{username}}' } function TextManagerProvider({ children }) { const textManager = new TextManager(textsBundle, [InsertParams, UseCodeIfNoText]); return ( <TextManagerContext.Provider value={textManager}> {children} </TextManagerContext.Provider> ) }
Luego, en el componente, usamos textManager
, por ejemplo, usando un gancho, y obtenemos el texto deseado por código.
function SayHello({ username }) { const textManager = useContext(TextManagerContext); return ( <div> {textManager.getText('text.hello', { username })} </div> ) }
Localización
Usted pregunta: "¿Qué tiene que ver la localización con ella?".
Todo es muy simple: al cambiar el idioma, cree una nueva instancia de TextManager
, agregue textos e inmediatamente obtenga el resultado.
El penúltimo capítulo :)
Como puede ver en los ejemplos, el uso es extremadamente simple y, gracias al middleware, puede expandir la funcionalidad indefinidamente.
Publiqué mi implementación en github y planeo desarrollar aún más el administrador de texto . Utiliza, ofrece mejoras y, como dicen allí, ¡de nada! :)
En conclusión
Así que cumplí mi deseo de daaaaavnee: escribí un artículo sobre Habr. Realmente espero que este artículo sea útil y complazca a la comunidad.
Gracias por su atencion