当才开始接触cocos2dx的来说,要实现中文的显示,那么他们就回到网上查,当然方法也很多。这里就总结几个,然后介绍怎么封装实现国际化。
先声明一个很重要的内容:
cocos2dx 的label之类(包括所有的字符串,比如CCLog)的创建,需要传入一个const char* 即string,这里期望的是以"UTF-8"的编码形式构成的字符串。也就是运行期间他的数据时UTF-8编码的。
所以很多人直接在vs里面写CClog(“中文”);的时候控制台输出其实是乱码的,因为vs默认不是使用utf8编码的形式,所以不能直接用的。
但是xCode是可以的,CClog(“中文”);在xCode里面输出的就是中文。因为xcode是使用utf8编码。
所以我们要显示中文,
解决方案1:把含有中文的文件另存为utf8格式,即可解决(这个我没测试过);
但是就很麻烦,当然可以把所有的文字定义成变量,放到一个头文件里面,那么要改编码的就只有一个头文件了,这样看起来稍微优雅了点。但是还是很不爽,不能实现国际化。
其实直接把文字写在代码里面是一件很不值得推崇的方式(当然图简便还是可以的,但你需要知道他以后会带来的麻烦会很大),我们应该把文字独立出来,不跟我们的代码参合,就像Android的string.xml一样(是不是一下点醒了你?)。
于是解决方案2:
我们把所有的文字写到一个配置文件里面,我们程序直接根据key就获取到了utf8的文字,不管当前的源文件是不是utf8的格式的,因为他们不再相干了。请慢慢往下面看。
对于配置文件,我选择json格式(为什么选择json,没原因,就喜欢json,干净利落)。
下面给出例子:
我的json的中文配置文档:
里面就是简单的json格式的配置文档(关于不懂json的,我后面会写一篇json的解析的文章,目前先不管,或者你们也可以用其他的格式,比如xml,这样cocos2dx已经有解析方案了,原理是一样的)。
下面就是我们json解析和使用的代码了(LFString.h和cpp):
#pragma once
#include <string>
#include "json/json.h"
#include "LFFileUtiles.h"
#include <map>
using namespace std;
/**
* 字符串工具,是中文字符的键值对
*/
class LFStrings
{
public:
static bool init();
static string getValue(string _key);
static bool haveValue(string _key);
private:
static bool parseFile(string relativePath);
static map<string,string> data;
};
------cpp
#include "LFStrings.h"
#define ROOT_PATH "config/"
#define FILE_MAIN "strings.txt"
// 所支持的标签
#define LABLE_KEY "key"
#define LABLE_VALUE "value"
#define LABLE_INCLUDE "include"
map<string,string> LFStrings::data;
// 用于缓存已经解析了的文件
static map<string,int> paresedFile;
bool LFStrings::init()
{
data.clear();
paresedFile.clear();
return parseFile(FILE_MAIN);
}
bool LFStrings::parseFile(string relativePath)
{
// 看是否已经解析过了
if (paresedFile.find(relativePath) != paresedFile.end())
{
CCLog("Waring : %s --> file[%s] is pared over before or is in parsing now ,do you include it again???",__FUNCTION__,relativePath.c_str());
return true;
}
paresedFile.insert(pair<string, int>(relativePath,0));
string path = string(ROOT_PATH)+relativePath;
CCLog("%s parsing file [%s] ....",__FUNCTION__,path.c_str());
Json::Reader reader;
Json::Value root;
unsigned long size;
const char* doc = LFFileUtiles::getLFFileUtiles()->readResourceFile(path,&size);
if (size == 0)
{
CCLog("%s ----> file [%s] have no content.",__FUNCTION__,path.c_str());
return true;
}
if (doc == NULL)
{
CCLog("%s ----> doc is NULL , open Error!",__FUNCTION__,path.c_str());
return false;
}
if (!reader.parse(doc,root))
{
CCLog("%s ----> reader.parse failed! [%s]",__FUNCTION__,path.c_str());
CCLog(doc);
delete [] doc;
CCAssert(false,"");
return false;
}
//CCLog(doc);
Json::Value _strings= root["strings"];
if (!_strings.isNull() && _strings.isArray())
{
int _stringNum = _strings.size();
for (int i=0;i<_stringNum;i++)
{
Json::Value onePair = _strings[i];
// 校验
if(!onePair[LABLE_KEY].isNull() && onePair[LABLE_VALUE].isNull())
{
CCLog("Error : %s there is no %s for %s [%s]",__FUNCTION__,LABLE_VALUE,LABLE_KEY,onePair[LABLE_KEY].asCString());
CCAssert(false,"key 和 value 没有配对");
continue;
}
if(!onePair[LABLE_VALUE].isNull() && onePair[LABLE_KEY].isNull())
{
CCLog("Error : %s there is no %s for %s [%s]",__FUNCTION__,LABLE_KEY,LABLE_VALUE,onePair[LABLE_VALUE].asCString());
CCAssert(false,"key 和 value 没有配对");
continue;
}
//有include
if (!onePair[LABLE_INCLUDE].isNull())
{
string file = onePair[LABLE_INCLUDE].asString();
if (!parseFile(file))
{
CCLog("Error : %s parse file %s faild",__FUNCTION__,file.c_str());
return false;
}
}
// 解析键值对
if (!onePair[LABLE_KEY].isNull() && !onePair[LABLE_VALUE].isNull())
{
string _key = onePair[LABLE_KEY].asString();
string _value = onePair[LABLE_VALUE].asString();
if (haveValue(_key))
{
CCLog("Waring : %s --> the key [%s] in file[%s] is already used before,we will ignore this key and value[%s]!",__FUNCTION__,_key.c_str(),path.c_str(),_value.c_str());
continue;
}
data.insert(pair<string, string>(_key,_value));
}
}
}
return true;
}
string LFStrings::getValue(string _key)
{
map<string, string>::iterator iter;
//如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器;
iter = data.find(_key);
if(iter != data.end())
{
return iter->second;
}
CCLog("Waring : LFStrings::getValue --> _key[%s] is not found!",_key.c_str());
return "";
}
bool LFStrings::haveValue(string _key)
{
map<string, string>::iterator iter;
//如果map中没有要查找的数据,它返回的迭代器等于end函数返回的迭代器;
iter = data.find(_key);
return iter != data.end();
}
使用方法很简单,游戏启动的时候调用:
// 初始化
LFStrings::init();
他就会找Resource下面的config下面的string.txt文件,进行初始化。
每次要用中文的时候直接:LFStrings::getValue(“biaoti”);// 取得标题字符串
即可。这样就轻松实现中文了,以后直接配置,修改就是了。
最后一个问题,怎么实现国际化:
需呀稍微修改下LFStrings类,直接让他解析不同的配置文件就是了,其他的所有代码就不用改。就可以实现语言的动态切换了。
明白了吧?