Bom dia, habravchane!
Neste artigo, falarei sobre uma solução simples para o problema de gerenciar texto e localização em um aplicativo da Web, que você pode implementar por conta própria ou usar um já pronto.

Há muito tempo eu queria compartilhar meus próprios pensamentos e experiências ... e, é claro, conversar pela vida toda.
AntecedentesObviamente, já existem soluções para gerenciar texto e localização, mas elas não se adequaram a mim por vários motivos: complicado, inconveniente de usar, inadequado, não corresponde à minha visão de resolver esse problema, carece de funcionalidade.
Além disso, eu realmente não gosto de bibliotecas de terceiros devido à sua tendência a crescer (é quando precisamos apenas de uma pequena parte de toda a funcionalidade).
A empresa em que trabalho tem sua própria solução, mas, na minha opinião, também está longe de ser ideal. E a necessidade de compatibilidade com versões anteriores faz com que seja desnecessariamente complicado.
Em algum momento, eu queria algo simples, fácil, compreensível e infinitamente expansível para tarefas diferentes.
Declaração do problema
Tudo parece estar claro aqui. Ou não? Vamos pensar o que gostaríamos.
De alguma forma, precisamos obter textos localizados. Os textos podem conter variáveis. As variáveis também podem ser localizadas ?! Em teoria, sim. E se a variável for uma data ou um número ?! Além disso, suporte de remarcação. E, finalmente, alguma solução, caso o texto não seja encontrado.
Implementação
A base será um objeto simples, onde a chave é o código de texto e o valor é o texto real de que você precisa, 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');
Um pouco sobre o nome das chavesO nome das chaves é um tópico separado. É melhor concordar imediatamente com uma única opção, caso contrário, diferentes teclas serão ativadas :). Não há uma solução, escolha o que você acha mais conveniente e mais consistente com o projeto. Pessoalmente, eu gosto do primeiro:
'button.open.label'
'button.open.help_text'
ou
'button.label.open'
'button.help_text.open'
ou
'label.button.open'
'help_text.button.open'
Em seguida, precisamos de um mecanismo capaz de executar algum tipo de manipulação com o texto antes de fornecer o resultado final, por exemplo, inserir parâmetros. E então tive uma ideia interessante - e se usarmos o middleware para manipular o texto? Afinal, eu não vi essas decisões ... bem, ou pareci mal :).
Decidimos sobre os requisitos para o middleware: na entrada, o middleware aceitará texto e parâmetros e fornecerá o texto resultante, após as manipulações necessárias.
O primeiro middleware receberá o texto original e os subsequentes receberão o texto do middleware anterior. Vamos adicionar o código ausente:
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); }; }
O TextManager pode gerar texto por seu código. Também pode ser expandido usando middleware, o que abre muitas possibilidades, por exemplo:
- lidar com o caso quando o texto não for encontrado
- uso de parâmetros no texto
- localização de parâmetro
- use remarcação
- blindagem de texto etc.
Prática
Vamos escrever alguns middlewares necessários. Você precisará deles 100%.
InsertParams
Permite o uso de parâmetros em textos. Por exemplo, precisamos exibir o texto "Olá {{nome de usuário}}". O seguinte middleware fornecerá isso:
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
Permite retornar o código de texto, em vez de undefined
, se o texto não foi encontrado:
function UseCodeIfNoText(text, parameters, code) { return text ? text : code; }
Total que recebemos aproximadamente o seguinte 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')
Exemplo de aplicação de reagir
Primeiro, inicialize no TextManager
nível TextManager
e adicione textos.
Na minha opinião, é melhor extrair textos do servidor, mas, por simplicidade, não farei isso.
const textsBundle = { 'text.hello': 'Hello {{username}}' } function TextManagerProvider({ children }) { const textManager = new TextManager(textsBundle, [InsertParams, UseCodeIfNoText]); return ( <TextManagerContext.Provider value={textManager}> {children} </TextManagerContext.Provider> ) }
Em seguida, no componente, usamos o textManager
, por exemplo, usando um gancho, e obtemos o texto desejado por código.
function SayHello({ username }) { const textManager = useContext(TextManagerContext); return ( <div> {textManager.getText('text.hello', { username })} </div> ) }
Localização
Você pergunta: "O que a localização tem a ver com isso?".
Tudo é muito simples - ao alterar o idioma, crie uma nova instância do TextManager
, adicione textos e obtenha o resultado imediatamente.
O penúltimo capítulo :)
Como você pode ver nos exemplos, o uso é extremamente simples e, graças ao middleware, você pode expandir a funcionalidade indefinidamente.
Postei minha implementação no github e planejo desenvolver ainda mais o gerenciador de texto . Use, ofereça melhorias e, como dizem lá, de nada! :)
Em conclusão
Então, eu cumpri meu desejo daaaaavnee - escrevi um artigo sobre Habr. Eu realmente espero que este artigo seja útil e agrade a comunidade.
Obrigado pela atenção.