新闻
你的位置:万博体育APP入口 > 新闻 >

万博max体育官网要信赖你的问题别东说念主齐早就际遇过了-万博体育APP入口

发布日期:2024-04-26 07:23    点击次数:166

前一阵子在作念新相貌标时候想了一下面前的相貌在土产货化文本不竭方面际遇的诸多问题,恰恰又碰到了一个新一又友来问这个问题,翻出了7年前我写的一篇博客,面前回头看的话嗅觉那时写的太苟简了,因此决定再行共享我的个东说念主训诫,在多话语文本不竭中际遇的问题,以及我残暴的科罚秩序。

中心化不竭:看起来很好意思

市面上最常见的多话语文本不竭的时刻是中心化的不竭时刻,即多话语文本完全脱离其所被使用的阵势,作为一个单独的表单或文献存在,任何需要显现文本的地点,齐以key为唯一的索引从这个文本中来得回对应的土产货化话语的文本。

在举一个具体的例子之前,咱们要明确一个不雅点:一个相貌中的文本主要分两种:UI文本和数据文本。UI文本指的是界面上多样控件显现的文本,数据文本则是需要筹办不竭的游戏数据的文本。除此以外还有第三种文本:工作器文本,这个属于相比非凡的情况,不不才面的例子中盘问,著述闭幕的地点会特意诠释。

假如咱们在作念一款RPG游戏,有硬汉和时刻两个表,最终导出了三个文献,那么一个典型的中心化不竭的多话语文本可能是这样遐想的文献结构:

hero.json

skill.json

text.json

咱们只看hero.json和text.json来诠释问题。

假定一个硬汉相等通俗,唯独两个属性:名字、时刻,那么硬汉的数据可能长这样:

hero_id = 1

hero_name = "text_hero_name_001"

hero_skill = [1,2,3]

本文重心善良的即是hero_name的部分,这是需要多话语不竭的部分。显著"text_hero_name_001"是一个key,其指向的真正文本储存于text.json中。

那么text.json长什么样?淌若咱们用合并个text.json来存储全部多话语的文本,那么可能长得类似这样(Dictionary/Object作风):

text_hero_name_001 =

"zh_CN" : "王老王",

"en_US" : "King Old King",

{

}

也可能是这样(CSV作风):

key,"zh_CN","en_US",

text_hero_name_001,"王老王","King Old King",

也可能是每个话语对应一个text.json文献,这种就不再例如赘述,但不论哪种,试验齐是一样的:文本脱离于其所被使用的环境,进行中心化不竭,而况在被使用的地点通过Key来索引。

这看起来莫得任何问题,亦然业界的主流作念法,但在我这些年游戏斥地的训诫中却以为这样作念的问题相等大,致使可以说这齐是秩序念念维的产物,能闭幕需求但却基本没谈判筹办和UI的珍摄本钱,底下就动手谨防的阐发这种时势的缺点。

问题一:脱离使用环境

假定你是一个UI同学,面前作念了一个通俗的弹出层,有标题、正文和驯顺按钮,你需要三个文本来姿色这个界面:

标题:阐明充值?

正文:作念游戏不赢利,等于交个一又友。阐明充值648钻?

按钮:阐明

那么按照上述的不竭时势,界面上可能是这样的:

标题:text_dialogue_title_iap_001

正文:text_dialogue_content_iap_001

按钮:text_dialogue_button_iap_001

一个UI同学在UI剪辑器或游戏引擎中永远的濒临这种不可读、不可排版的文本,旷日持久对心灵会产生什么样的打击显而易见——天然,这跟秩序不要紧,秩序也不在乎。

假如UI报怨的相等凶,要求秩序在剪辑环境中也要默许把这堆看不懂的key给显现成简体中语,而秩序勉为其难的也给作念了,那么至少科罚了UI同学的问题,但前文提过,UI文本仅仅一个相貌中的一部分,还有另外一个大头:数据文本。

照旧刚才的hero.json的例子,假如咱们这个RPG相貌有100个硬汉,那么咱们在hero.json中能看到的是什么呢?是任何一个硬汉你齐不知说念他的名字是什么,只可看到从text_hero_name_001到text_hero_name_100这种风趣不解的东西。

作为一个筹办,你不太可能铭记住一个硬汉的ID,反而记着他的名字要容易得多。那么面前你要去找一个硬汉的数据,你要何如办?你可能要去text.json中找到这个硬汉的名字,再看对应的key来识别他的ID,再去hero.json中找到这个硬汉的数据。

这时候假如有个筹办不那么庄重,没按照圭表去好好的给hero_name对应的文本建key,而况那时他偷摸就提交了,谁也不知说念,本来应该叫作念"text_hero_name_100",但这个筹办给起成了"text_hero_name_wanglaowang",那你找起来就会想杀东说念主了。

这时候还有更大的问题,淌若一个筹办想要知说念一个硬汉有什么时刻,那何如办?因为时刻内外亦然不带名字的,他就只可先想目的找到硬汉的ID,然后再找到时刻的ID,然后再去看时刻的名字。

这种套娃操作每多一层,筹办的神气齐会多一层崩溃。

除此以外,脱离使用环境还使得你的相貌需要翻译外包的时候看似容易,只须把text.json丢往时就行了,但因为翻译的东说念主员不知说念这个文本是用在那儿的,因此很容易出现翻译罢了集会险峻文风趣很是或UI的显现出现异常的情况。这部分的交流本钱亦然十分雄伟的。

问题二:单一职能原则

假定咱们照旧上头阿谁作念充值对话框的UI同学。这个相貌驯顺不啻这样一个对话框,是以咱们还会作念许多许多其他的对话框,比如购买多样东西的阐明对话框、多样危急操作的阐明对话框、需要遴选个数或者填写内容再提交的对话框等等。

作念多了之后咱们就会发现,这些对话框齐有一个驯顺按钮,而且按钮的文本内容可能齐一样,齐是“驯顺”,但却每次齐要起一个新的text的key。当这个UI同学大开了text.json后,发现存几十上百个不同key的文本齐叫“驯顺”的时候,他一定会怀疑这种作念法是不是有问题。

终末UI们计划了一下,决定所有的驯顺按钮齐用一个key,比如这个key叫作念“text_dialogue_button_confirm”。专家以为责任通俗多了,所有的驯顺按钮齐用这一个文本,不必再弄大齐肥美的文本了。

直到再过了一段时代,筹办提了一个需求,充值界面的阐明按钮不可只写“阐明”,要写“阐明,我家有矿”。筹办认为通俗的改文本就行,于是就把“text_dialogue_button_confirm”的内容给径直改了。

改罢了之后发现相貌出了大问题,所有的对话框的阐明按钮的文本齐形成了“阐明,我家有矿”。然后QA爸爸就提着刀过来了。

QA爸爸把这个问题捅到了相貌操纵那里,比及相貌操纵发现这个问题之后,决定查验一下所有的text.json里面的文本,要阐明下到底有哪条key是不啻被用了一次的,但却发现很难作念到这样,因为相貌进展到这个阶段,text.json里面可能也曾有上万条数据了,你既没法通俗的知说念里面有莫得完全没被援用试验上也曾冗余了的条件(比如删了一个时刻,但时刻的名字没删),也没法阐明里面的某一个条件有莫得被屡次援用(类似上头的阐明的问题,筹办和好意思术齐会有这个情况),从而导致篡改的时候激励意想以外的问题。

天然,你可以硬性的王法,但凡要复用的text齐放到合并个文献里(比如它叫general_text.json),但凡应该被用且应该只被援用一次的text齐放在text.json里,但毕竟只须key是东说念主为的手写的,就无法完全幸免这个问题,很快两个文献里面可能又会出现混乱——text.json里面出现了被援用屡次的key,而general_text.json里面出现了冗余的key。

假定这时候有一个秩序同学以为可以从用具上来动手科罚这个问题,于是他写了一个用具,从此text.json的key齐是自动不竭的了,筹办同学可以便捷的在各个数据表中添加、修改、删除文本,key的关联齐是自动完成的,或者说text.json的key完完全由这个用具自动不竭了,key致使对筹办来说是不可见的,从而从根本上幸免了筹办手误的问题。

这听起来很好意思好是吧?但其实并不是的,因为这个有野心依然有问题。

从原则上来说我个东说念主吵嘴常不残暴相貌在成例的斥地责任流中加入一些我方斥地的用具的,除非是在这方面有十分丰富训诫的斥地团队,或者这个用具自身豪阔通俗、不参加责任流(比如用了一次就不必了的“日抛型”用具)。原因有三点。

起首是这个用具的可珍摄性问题。这些用具在斥地之时仅仅为了尽快的科罚某些小问题,并莫得严格确看成念一款可以请托使用的产物来对待,因此短少文档,而况斥地的也相对搪塞(用户是里面斥地东说念主员而不是游戏玩家)。这个用具自身需要测试但短少测试,它的完整性和可靠性需要支付十分大的本钱,而这部分本钱本来是可以去斥地玩家可以体验到的功能的。这还仅仅短期的问题,淌若咱们从长经营的话,短期少作念点功能,把用具作念好,也没什么问题,但历久问题试验上更大。当这个用具被用了几个月致使几年之后,不出bug的概率险些等于0,而当初写这个用具的东说念主可能早已不在这个相貌组致使下野了,而由于短少文档且斥地搪塞,接办珍摄这个用具的东说念主可能完全无法上手,这种情况下相貌就堕入了一个两难的境地。还有很厚情况下,跟着责任流的养息或东说念主员的变化,冉冉的这个用具也会被赓续的迭代,但其迭代的速率不时是滞后于团队的变化的,致使最终成为拖后腿的卡点——你不得不必它,而你又明知说念它也曾不好用了。

其次是这个用具的可靠性问题。这些用具所依赖的斥地环境过于复杂,公司的一次停电、游戏引擎的一次升级、一个脏数据的写入、一个筹办不小心的误操作(比如把ID填肖似了),齐有可能产生大齐的问题,这些问题是最早作念用具的同学所意想不到的(专家齐知说念,秩序员是乐不雅的),而为了科罚这些问题所有的筹办齐不得不停工,而况问题科罚的代价和效用也不知所以(比如可能导致json中的所有排序齐变了,天然试验上没变化因为json里面排序不紧要,但QA爸爸能看到的等于一个上万行的json文献的每一滑齐变了,而导致QA爸爸提着刀过来)。

终末一朝你动手依赖这种小用具后,不时会接二连三的作念一大堆用具,前边的两个问题很快会形成多个问题,很快就会堕入按下葫芦起了瓢的情状,致使当出了问题之后你齐不知说念究竟是哪个小用具的锅,斥地用具的东说念主报怨使用用具的东说念主提的问题迂缓而不驯顺(致使怀疑是使用者我方的问题),使用用具的东说念主报怨斥地用具的东说念主作念的破玩意不靠谱,最终所有东说念主齐痛楚。

因此,淌若你必须要把某个用具加入责任流中,那么淌若有外部的、老成的、有历久珍摄的科罚有野心,尽量不要我方造轮子,宁可花点钱买科罚有野心,也比我方花元气心灵去作念这些事情要强,不然当你过了几个月致使几年后,一定会为当初我方的决定后悔——假如你还在这个相貌组的话。

要信赖你的问题别东说念主齐早就际遇过了,用别东说念主造好的轮子老是比我方造轮子强,东说念主类社会等于这样杰出的。

问题三:依赖性问题

假如你是一个筹办,也曾遐想好了一个新的硬汉,以及他的时刻,面前要动手配表了。

既然要加硬汉,那么理所天然的你大开了hero.json,然则当你加到一半的时候发现加不下去了,因为hero_name需要一个key,你必须先去text.json里面建树好这个文本,再填回到hero.json中来武艺完成建树。提交的时候你必须同期提交这两个文献,不然硬汉的名字就会显现很是,显著这是会被QA爸爸暴揍的。

等你搞罢了之后又发现这个硬汉要加时刻,那必须又先去配时刻表。而配时刻表的时候又发现了必须要去先去text.json里面写好时刻的名字。

而现实情况中这个套娃的情况不时更严重,以我面前的相貌为例,我需要新加一个宝箱,这个宝箱有【名字】有【姿色】,这个宝箱有一个对应的说念具ID,说念具有【名字】有【姿色】,这个宝箱里面是一件新时装,这个时装有【名字】有【姿色】,这个新时装有对应的说念具ID, 说念具有【名字】有【姿色】,这个新时装有对应的时装碎屑,这个碎屑有【名字】有【姿色】,这个碎屑有对应的说念具 ID , 说念具有【名字】有【姿色】。等这一套折腾完,你会发现最耗尽元气心灵的不是宝箱->时装->碎屑的套娃,而是不论你干啥齐需要去text.json里面加名字,而这对于筹办来说也吵嘴常横祸的。

天然,在删除建树的时候筹办也会濒临不异的恶梦,要删一个东西就要删大齐对应的text,而这种删除操作的危急性在上头的一个问题中也曾提到过了,因此最终不时会演形成“冗余就冗余,只加不减就好了, 这样至少不会出错”的情况。这会导致外包本钱急剧增多,因为你也不知说念哪些文本灵验,哪些文本没用的。

更严重的是这会让你的相貌很屎,而这屎不是喂给玩家的,是喂给筹办的。专家齐知说念这里面充满了屎,但谁也没法认出来究竟哪些是屎。一个敢喂我方屎的筹办,对玩家能作念出何等丧心病狂的决策齐是有可能的。

当一个东西变得反直观的时候,约略率有更好的有野心可以去替代它。

问题四:冲破问题

极点的情况下,不论你改客户端的什么表,齐需要同期的去改text.json。而text.json唯唯独个,所有筹办共用,因此冲破的几率极高,同期类似SVN的版块不竭用具对json文献的比对守旧的也不是极端好(你可能需要特意的json语意比对用具),于是筹办的功课形成了一场恶梦,你仅仅想把我方改的东西提交上去汉典,但却发现这果然如斯艰难。

而更大的问题是,你不仅仅提交就完事了,你还需要合并呢,合并的时候更是一场恶梦。

天然靠培训每个东说念主齐要学会提交、合并、科罚冲破可以来克服这个艰难,但毕竟这个艰难试验上……有可能根柢就不存在,而仅仅因为一动手遐想的偷懒导致的没必要的艰难。你退秩序把所有代码齐写在一个文献里他们天然不干,那为什么筹办和UI的所有文本齐在一个文献里他们就干了呢?——因为不必他们珍摄,这是个屁股决定脑袋的问题。

问题五:唯一性问题

由于大齐的文本齐堆在一个文献里,为了保握key的可读性和唯一性,定名就成了一浩劫题,其艰难进度致使忘形术同学谈判好意思术资源的定名还艰难,因为好意思术资源可以分文献夹,但key齐堆在沿路。

想找到一套完好的可以姿色所有东西的key的秩序不是不行,但这种结果约略率会让key变得相等冗长。比如好意思术可能谈判把界面的名字或者prefab的名字加进去,筹办则要把是哪个表的哪个id的哪个字段用到的加进去。很快你的相貌就会出现一个神奇的风光:大部分的字符串的key致使比其自身的内容还要长的多的多,所有这个词text.json文献奇大无比,但“三斤鸭子两斤嘴”,肉没几许。这种情况的体验就像是专家上班的时候相互不叫昵称也不叫姓名,而是相互喊身份证号的完整号码来相互交流一样,显得相等蠢。

那何如办?

科罚秩序我以为很通俗,去中心化,径直言简意该,需要完成以下几个需求:

文本不再中心化全放在沿路,而是散布开来,凭证各个模块散布到各个文献中,而况把秩序遐想成只可造访我方联系模块的文本。这样即能科罚一个大文献经营相互冲破的问题,也能科罚滥用key的援用导致无法跟踪每个key齐被那儿用到了问题。要而论之,把text从全局的改本钱地的。

文本尽量靠拢其所被使用的阵势,致使可以完全免掉key是最佳的。这样既不必费力去给key取名字,也不必去琢磨key的冗余或被屡次援用的问题了,也不必去斥地劳什子自动关联key的用具了。

于是hero.json会形成什么神气?约略会形成这样:

hero_id = 1

hero_name =

"zh_CN" : "王老王"

"en_US" : "King Old King"

{

}

hero_skill = [1,2,3]

回头一看,这其实等于我七年前贴的著述中《炉石神话》的作念法。暴雪在《星际争霸2》中经受的照旧中心化的不竭目的,而《炉石神话》他们遴选了另外的作念法,我猜是他们吃屎吃够了。

淌若筹办用Excel来不竭多话语的话,需要写插件,不然一个格子里面写Dictonary/Object作风的东西会很蛋疼;或者筹办可以在多列中建树话语,但最终把多列导出成Dictionary/Object作风的内容。然则毕竟长痛不如短痛,总比搞好几个表往复贴key要欢欣得多。

有东说念主可能说了,这样筹办要每次齐去写"zh_CN"和"en_US"这种文本,不很容易错吗?但你想想,是写这样固定的文本容易错,照旧每次齐要依照一个王法去想一个新的key更容易错呢?

还有东说念主可能会说,这样客户端不论现时话语是什么,齐会加载全部的话语文本,有点虚耗资源。但凭证我个东说念主的意会,占内存大头的恒久不会是文本文本,而是二进制文献,因此这方面的性能问题也可以忽略不计。反而这可能成为一个平正,即切换话语不需要重启客户端更容易闭幕了,但毕竟我不是专科的秩序,这里可能还触及到加载字体等问题,这里要视相貌领先的需求是否需要不重启客户端就能切换话语了。

好了,筹办的同学科罚罢了,那么UI同学何如办?

相比通俗的作念法是彭胀一个守旧多话语的控件,比如底本系统的文本控件只可输入一套文本,退秩序彭胀一下可以写多套文本即可,同期默许显现中语。比如一个驯顺按钮,本来UI拉上来一个button后径直在text里面写“驯顺”就行了,面前的话会有多行的text,其中第一滑是"zh_CN"的,UI同学要在这里写"驯顺",然后在第二行"en_US"里面写"Confirm"。同期还可以守旧切换预览多话语效用。试验上许多多话语插件齐是用类似的念念路去作念的,比如Unity的I2 Language(这里不是打告白,我没用过,但看demo嗅觉挺好用的,还守旧图片和音频的多话语,而且这亦然Unity Asset Store中最受宽待的土产货化插件)。

UI文原土产货化之后的一个问题等于外包的时候咱们照旧需要导出文本,因此在一动手遐想结构的时候需要尽量遐想一个不依赖于Key同期还可以便捷导出导入的结构,单独把每个界面prefab的文本导出,翻译完成后再导总结即可。上头提过的I2 Language貌似还守旧谷歌翻译以及导入导出功能(这插件试验上照旧中心化不竭文本的,仅仅界面上隐敝了),感好奇景仰好奇景仰的同学可以我方试试。

然则以上毕竟仅仅脑洞,我决定在新相貌中试一下用这种时势来不竭文本的试验效用怎样。因为齐是我一个东说念主作念的,是以UI的多话语文本我决定不写在控件上,而写在代码里,一个prefab的代码把需要用到的文本长入在一个地点以Dictonary/Object的作风来声明好,便捷背面调用。而筹办配表的部分,我决定在Excel中每个文本一列,再导出的时候把合并个key的文本合并成Dictonary/Object作风的变量。

这里试验也扩充出了另外两个对于UI闭幕问题。

第一个问题是Prefab这个东西不时是客户端秩序和UI同学齐要打交说念的,这里相等容易出现问题,比如UI同学一不小心把某个节点隐敝了,QA同学提了BUG,秩序同学索尽枯肠的去考察问题最终发现果然不是我方的锅。科罚有野心业内也有一些,有的相比笨的目的是由秩序同学来拼界面,这样幸免UI同学染指Prefab,但拼罢了不免坐标不合,UI同学要再养息一下;有的方王法是参考筹办的责任流,把UI的剪辑经由寂寞于游戏引擎以外,把界面看成念是资源文献导入到相貌中,从而闭幕了UI同学和秩序同学功课对象的分歧。也有其他的作念法,比如对UI遐想师和UI秩序员的要求更高,两边必须风雅的结对功课,而不是各自分属不同的部门。还有的作念法是UI在PhotoShop里面作念罢了责任后筹办来拼界面,把和秩序对接的责任交给了筹办,从而UI不必谈判上传SVN的问题。还有的作念法是逼着UI同学去学写代码,比如至少会用个蓝图啥的,从而幸免秩序同学染指Prefab。归正多样奇奇怪怪的作念法齐有,哪种是最佳的不好说,要视团队和相貌标具体情况而定。以上的各种秩序中我个东说念主最倾向的是哪种?淌若是UI阐扬十分紧要的游戏,那么提升对UI和秩序东说念主才教唆的要求,强制其结对功课共同对UI的结果负责,是相比好的科罚时刻,能够闭幕质料和性能齐相比出色的UI界面,但这样对东说念主才的要求很高(十分于半个TA),大部分的团队不一定能作念到,这种情况下另外一个遴选是退而求其次,将UI的遐想责任交给筹办,只保证功能性但不保证好意思不雅度,在东说念主力衣不蔽体的小公司/寂寞团队或功能无尽叨唠的大相貌中这亦然个可以的秩序。不论哪种,其试验齐是要合乎UI责任的非凡性,这不是一个可以通俗的“好意思术vs秩序”二元割裂的责任,而是必须有机的集会在沿路武艺完成的详细性责任,一切想着切割UI和秩序的责任流的有野心齐注定不是最优的。

第二个问题是界面的许多情状和内容应该是以资源驱动为主导照旧以代码驱动为主导?比如一个界面默许情状是应该隐敝的,那么是UI同学把隐敝给勾上相比好,照旧秩序同学在代码里运调换的部分写上强制隐敝好?按照我的倾向性的话,淌若不影响性能的前提下,我倾向于用代码来结果。UI资源自身毕竟是静态的,因此但凡动态的东西齐应该由代码来结果,这亦然为什么多话语文本我以为写在代码中比挂在界面上要好的原因,因为触及到多话语,自身就也曾不是静态的文本了。

祝我好运吧emmmm,远景未卜,不知说念还会踩到几许坑,但总比面前的情况欢欣。

(另外别问我为什么我不必I2 Language,因为Godot全国等一)

写在终末:对于工作器文本

所谓的工作器文本,即并排于UI文本和数据文本以外的第三类文本,这种文本常见的是停服公告、发给玩家的邮件、攻击珍摄见知赛马灯等各种由于具体写什么文本完全无法预估而只可在工作器端修复文本,客户端收到什么就显现什么的文本。这类文本大部分属于运营用具的领域。

那么这类文本怎样闭幕土产货化?

这起首要看游戏工作器的结构,是各个话语的用户齐混在一个工作器里面玩?照旧每个话语的用户我方有我方的工作器?淌若是后者的话那么很通俗,每个话语的工作器发对应话语的公告就好了(致使可能是完全不同的运营商),淌若是前者那么这触及到另外一个问题:客户端能否切换多话语?淌若能的话,比如我用英文客户端登录之后,系统发给我的邮件可能是英语写的,这时候我切换成中语客户端重登后,看到的这封邮件是英文的照旧中语的呢?驯顺了这个需求之后,武艺遐想工作器端文本的多话语是应该怎样处理的。

只须提前谈判好,秩序作念起来齐是很容易的。难的齐是也曾在线上跑了一阵子了又不得不改,这才是最痛楚的。