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

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

1、文字的翻译;

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

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

image

image

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

 

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);
    });
}
 
很方便也很简单:-)
posted @ 2014-10-24 14:52  meteoric_cry  阅读(876)  评论(0编辑  收藏  举报