Web应用程序中的文本管理和本地化

美好的一天,habravchane!


在本文中,我将讨论一个简单的解决方案,用于解决Web应用程序中的文本和本地化问题,您可以实现自己或使用现成的解决方案。



我长期以来一直想分享自己的想法和经验,当然,也可以终身交流。


背景知识

显然,已经存在用于管理文本和本地化的解决方案,但是由于种种原因它们并不适合我:笨拙,使用不便,不合适,不符合我解决这个问题的愿景,缺乏功能。


另外,由于第三方库的增长趋势,我并不十分喜欢它(这是当我们只需要一小部分所有功能时)。


我工作的公司有自己的解决方案,但我认为这也不理想。 与旧版本的向后兼容性的需求使其变得不必要地复杂。


在某个时候,我想要一些简单,容易,可理解并且可以无限扩展以完成不同任务的东西。


问题陈述


这里的一切似乎都很清楚。 还是不行 让我们考虑一下我们想要什么。


我们需要以某种方式获取本地化文本。 文本可能包含变量。 变量也可以本地化吗? 从理论上讲,是的。 如果变量是日期或数字? 加上降价支持。 最后,一些解决方案,以防找不到文本。


实作


基础将是一个简单的对象,其中的键是文本代码,而值是您需要的实际文本,没有什么复杂的:


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'); 

关于按键名称的一点点

键的名称是一个单独的主题。 最好立即就一个选项达成共识,否则不同的键将“搅动” :)。 没有一种解决方案,选择您认为更方便且与项目更一致的内容。 就个人而言,我喜欢第一个:
'button.open.label'
'button.open.help_text'

'button.label.open'
'button.help_text.open'

'label.button.open'
'help_text.button.open'


接下来,我们需要一种机制,该机制能够在给出最终结果之前对文本执行某种操作,例如,插入参数。 然后我有了一个有趣的想法-如果我们使用中间件来操纵文本怎么办? 毕竟,我还没有看到过这样的决定……好吧,或者我看上去很糟:)。


我们决定对中间件的要求:在必要的操作之后,中间件将在输入时接受文本和参数,并给出结果文本。
第一个中间件将接收原始文本,随后的中间件将接收前一个中间件的文本。 让我们添加缺少的代码:


 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可以通过其代码输出文本。 还可以使用中间件对其进行扩展,这带来了许多可能性,例如:


  • 处理找不到文本的情况
  • 在文本中使用参数
  • 参数本地化
  • 使用降价
  • 文字屏蔽等

练习


我们将编写一些必要的中间件。 您将需要100%。


插入参数
允许在文本中使用参数。 例如,我们需要显示文本“ Hello {{username}}”。 以下中间件将提供此功能:


 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
如果找不到文本,则允许您返回文本代码,而不是undefined


 function UseCodeIfNoText(text, parameters, code) { return text ? text : code; } 

总计,我们获得以下用途:


 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') // 'nonexistent.code' textManager.getText('text.hello') // 'Hello' textManager.getText('text.hello_with_numeric_parameter', ['Vasya']) // 'Hello Vasya' textManager.getText('text.hello_with_named_parameter', { username: 'Petya' }) // 'Hello Petya' 

React应用示例


首先,在顶级TextManager初始化并添加文本。
我认为,最好从服务器中提取文本,但是为了简单起见,我不会这样做。


 const textsBundle = { 'text.hello': 'Hello {{username}}' } function TextManagerProvider({ children }) { const textManager = new TextManager(textsBundle, [InsertParams, UseCodeIfNoText]); return ( <TextManagerContext.Provider value={textManager}> {children} </TextManagerContext.Provider> ) } 

接下来,在组件中, textManager使用textManager ,例如,使用一个钩子,然后通过代码获得所需的文本。


 function SayHello({ username }) { const textManager = useContext(TextManagerContext); return ( <div> {textManager.getText('text.hello', { username })} </div> ) } 

本地化


您会问:“本地化与它有什么关系?”。
一切都很简单-更改语言时,创建TextManager的新实例,添加文本并立即获得结果。


倒数第二章:)


从示例中可以看到,使用非常简单,而且由于有了中间件,您可以无限扩展功能。


我将实现发布在github上,并计划进一步开发text-manager 。 使用并提供改进,就如他们所说,不客气! :)


总结


因此,我实现了我的daaaaavnee愿望-在Habr上写了一篇文章。 我真的希望这篇文章对您有所帮助,并能使社区满意。


谢谢您的关注。

Source: https://habr.com/ru/post/zh-CN458576/


All Articles