游戏繁体化那些让人蛋疼的事儿

项目首先从境内开始做,然后跟中国台湾那边谈了合作,要发行台湾版本。这过程中遇到一些问题,特别的坑,特此记录一下

1、文字的翻译;

之前开发的一款页游项目,翻译的工作全部由台湾那边负责,他们还专门花钱请人做翻译,翻译的人员是按字收钱的。现在转手游了,首先代理费一般是没有的(即便有也是很低,低的可怜),汉字的翻译全部是我们自己消化了,今时不同往日啊,页游的日子一去不复返了,手游CPA导用户水分也是越来越大,伴随腾讯在IOS榜单阵地的猛烈攻势,小公司小团队投入市场的成本已经高的吓死人了,看这趋势,推广成本只会越来越高,门槛也是越来越高,是好事也是坏事,好事就是小团队、小公司的生存空间被挤压的不行,没钱推啊,好事就是能活下来的就是好样的,可以算B+甚至A级的产品了,对用户来讲是好事。

汉字的翻译,首先word,用google翻译(貌似要“翻”墙)会遇到的问题就是在网页上看是繁体,一复制就变简体了。word的“简转繁”还是挺强大的。不过也有坑,往下看

“冊”是一样,但注就不一样了。单独一个注它是不繁体化的,注册二个字就繁体化了,你说蛋疼不

2、图片的处理;

图片的处理也很疼蛋,美术同事提供的繁体字库,我们用GlyphDesigner生成字体(1.4 破解版,没花钱买正版,嗯,确实很无耻,我自己的MAC都是掏真金白银买正版)。

生成一张png、一份fnt格式的文件,但是那些字体库基本上都是缺胳膊少腿的,就拿二个简单的词汇来看:“注册”、“魅力”,有的“魅”能出来,“册”就出不来,有的“册”能出来,“魅”就出不来,蛋疼不

用黑体吧,看上去不协调,很突兀,好忧伤…

好吧,目前我就只能来二份字体

3、词汇的特殊处理,汉字的翻译也好,字体库的选择也好,这都是死的,麻烦的是有些术语得手工改,这里我就根据之前做台湾版,台湾同胞提供的一些对比信息,我列出一些系统中常用的语句

-------------------------------   我是可恶的分隔线 -------------------------------

哪里    那裡

显摆    誇耀

手链    手鍊

好闲    好閒

几率    機率

淩    凌

糊弄    唬弄

创建    建立

锻炼    鍛練

利索    利落

采回來    採回來

下麵(简体下面)    下面

找茬    找碴

太後(简体太后)    太后

待機(简体待机)    準備

流覽器(简体浏览器)    瀏覽器

信息    訊息

充值    儲值

設置    設定

內置    系統

全屏    全螢幕

連接斷開    連線中斷

連接    連結

登錄    登入

角色名    角色名稱

概率    機率

默認    預設

添加    增加

刷新    更新

剔除    踢除

掉線    斷線

滾屏    滾頻

添加好友    新增好友

刷屏    洗頻

其实繁体化是所有国际化中最为简单的,因为最为相近,之前我搞过越南文,界面都得跟着调整,最主要的是你还看不懂那段文字是什么意思,就更为蛋疼了

---------------------------------- 分隔线 ----------------------------------

cocos2d-x中是通过CCLabelBMFont::createFontChars()来创建文字的,其实就是读取.fnt文件中的char id=N

void CCLabelBMFont::createFontChars()
{
    int nextFontPositionX = 0;
    int nextFontPositionY = 0;
    unsigned short prev = -1;
    int kerningAmount = 0;

    CCSize tmpSize = CCSizeZero;

    int longestLine = 0;
    unsigned int totalHeight = 0;

    unsigned int quantityOfLines = 1;

    unsigned int stringLen = cc_wcslen(m_sString);
    if (stringLen == 0)
    {
        return;
    }

    for (unsigned int i = 0; i < stringLen - 1; ++i)
    {
        unsigned short c = m_sString[i];
        if (c == '\n')
        {
            quantityOfLines++;
        }
    }

    totalHeight = m_pConfiguration->m_nCommonHeight * quantityOfLines;
    nextFontPositionY = 0-(m_pConfiguration->m_nCommonHeight - m_pConfiguration->m_nCommonHeight * quantityOfLines);

    for (unsigned int i= 0; i < stringLen; i++)
    {
        unsigned short c = m_sString[i];

        if (c == '\n')
        {
            nextFontPositionX = 0;
            nextFontPositionY -= m_pConfiguration->m_nCommonHeight;
            continue;
        }

        tFontDefHashElement *element = NULL;

        // unichar is a short, and an int is needed on HASH_FIND_INT
        unsigned int key = c;
        HASH_FIND_INT(m_pConfiguration->m_pFontDefDictionary, &key, element);
       
        // 这里添加如果没有找到的判断,输出相应的key
        if(!element)
        {
            char str[100];
            sprintf(str, "font not found: %d", key);
            CCLuaLog(str);
            return;
        }

        //CCAssert(element, "FontDefinition could not be found!");

        ccBMFontDef fontDef = element->fontDef;

        CCRect rect = fontDef.rect;
        rect = CC_RECT_PIXELS_TO_POINTS(rect);

        rect.origin.x += m_tImageOffset.x;
        rect.origin.y += m_tImageOffset.y;

        CCSprite *fontChar;

        fontChar = (CCSprite*)(this->getChildByTag(i));
        if( ! fontChar )
        {
            fontChar = new CCSprite();
            fontChar->initWithTexture(m_pobTextureAtlas->getTexture(), rect);
            this->addChild(fontChar, 0, i);
            fontChar->release();
        }
        else
        {
            // reusing fonts
            fontChar->setTextureRect(rect, false, rect.size);

            // restore to default in case they were modified
            fontChar->setVisible(true);
            fontChar->setOpacity(255);
        }

        // See issue 1343. cast( signed short + unsigned integer ) == unsigned integer (sign is lost!)
        int yOffset = m_pConfiguration->m_nCommonHeight - fontDef.yOffset;
        CCPoint fontPos = ccp( (float)nextFontPositionX + fontDef.xOffset + fontDef.rect.size.width*0.5f + kerningAmount,
            (float)nextFontPositionY + yOffset - rect.size.height*0.5f * CC_CONTENT_SCALE_FACTOR() );
        fontChar->setPosition(CC_POINT_PIXELS_TO_POINTS(fontPos));

        // update kerning
        nextFontPositionX += fontDef.xAdvance + kerningAmount;
        prev = c;

        // Apply label properties
        fontChar->setOpacityModifyRGB(m_bIsOpacityModifyRGB);
        // Color MUST be set before opacity, since opacity might change color if OpacityModifyRGB is on
        fontChar->setColor(m_tColor);

        // only apply opaccity if it is different than 255 )
        // to prevent modifying the color too (issue #610)
        if( m_cOpacity != 255 )
        {
            fontChar->setOpacity(m_cOpacity);
        }

        if (longestLine < nextFontPositionX)
        {
            longestLine = nextFontPositionX;
        }
    }

    tmpSize.width  = (float) longestLine;
    tmpSize.height = (float) totalHeight;

    this->setContentSize(CC_SIZE_PIXELS_TO_POINTS(tmpSize));
    
}

通过调用JavaScript里的代码“String.fromCharCode(N)”很容易知道是什么字没有找到。我这里遇到的问题是,使用繁体字库时,输入的文字其实是简体,它自动转成繁体的,导致生成的fnt全部为简体字,对应的Unicode码也是简体的Unicode编码,我用node.js把.fnt文件转成最终可用的文字。步骤:

1、先用word将简体字翻译成繁体;

2、读取.fnt文件,替换char对应的id值,它的值由该行的letter获得;

char id=20445 x=203 y=117 width=29 height=29 xoffset=2 yoffset=-1 xadvance=31 page=0 chnl=0 letter="保"

function run(filePath) {
    fs.readFile(filePath, function(err, data) {
        if (err) throw err;        
        var str = data.toString()
        str = str.replace(/(char id=)(\d+)([^\"]+\")(.)(\")/g, function() {
            var arr = [];
            for (var i = 1, len = 5; i <= len; i++) {
                arr.push(arguments[i]);
            }
            arr[1] = arr[3].charCodeAt(0);
            return arr.join("");
        });
        fs.writeFileSync(filePath, str);
    });
}

很方便也很简单:-)

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏大神带我来搬砖

记一次高级软件架构师的铩羽而归

前几天女朋友笔记本电脑开机后进不了系统了,鉴于我天天告诉她要用宏来处理Excel,于是耳提面命,让我来修修。当时我想,这有何难,哪有程序员修不了电脑的?正如马谡...

3618
来自专栏黑泽君的专栏

壁挂式空调漏水怎么办?如何解决?

一:安装不牢固:室内机安装膨胀螺丝未打稳,安装不牢固影响平衡,导致排水管引出一侧位置偏高,造成排水困难,从而发生空调机机体滴水现象。

3064
来自专栏用户画像

快手[编程题]魔法深渊

前几个月放映的头号玩家简直火得不能再火了,作为一个探索终极AI的研究人员,月神自然去看了此神剧。

1212
来自专栏佳爷的后花媛

如何自制条形码扫描器

在文章之前要先感谢我的老师黄小平先生,在制作这个扫描器期间,给了我们很大的帮助和指导. 先说下这个条形码扫描器的预期功能: 如名称所示,主要达到的功能就是实...

5173
来自专栏睿哥杂货铺

我的2017年度盘点

https://www.gitbook.com/book/riboseyim/linux-perf-master/details

2188
来自专栏程序员互动联盟

【程序员故事】搞笑篇

1、我真想开个程序员餐厅了,我当老板娘,进门时先写代码再进,一楼餐厅分C包间、java包间、linux/unix包间。搞开源软件的就坐大厅里,搞Ruby的上二楼...

2793
来自专栏lonelydawn的前端猿区

echarts 进阶之同心扇形图多级联动

需求分析 前情提要 同心多扇形图,用于表示树形数据结构以及每一层级节点在该层总量中占比。 原始数据结构:  { "name": "师资队伍", "val...

4676
来自专栏智能大石头

MF前传——探索者一号简介

    MF让我们这些C#程序员能够把手伸到嵌入式行业,大大增强我们在各种项目中的竞争能力。无奈国内研究MF的人少之又少,为了加速MF技术的研究,我们团队采用少...

2129
来自专栏大数据挖掘DT机器学习

用python做NLP:中文文本预处理

一 得到原始文本内容 def FileRead(self,filePath): f = open(filePath) raw=f.r...

6495
来自专栏FreeBuf

记BCTF之旅—真假难辨

作者 ChandlerLeo 我也来凑个热闹,解析一道BCTF——真假难辨。 ? 首当其冲的便是一个偌大的you must login at host comp...

20910

扫码关注云+社区

领取腾讯云代金券