ローカライズ(多言語化)

cocos2dxでのローカライズ(多言語化)について

世界に向けてアプリを配信するのに欠かせないのがローカライズ。今回は特にアプリ内で使用するテキストを端末の言語に合わせて表示する方法をまとめた。
ちなみに、あまりローカライズする部分がない場合は以下の方法が役に立つ。tf.hateblo.jp

1,方向性

CSV形式で「"KEY","ENGLISH","JAPANESE"」のように保存したテキストデータをパースして連想配列に突っ込んでおく、という方向性にした。
突っ込む先はシングルトンクラスにすることでどこからでも呼び出せるようにした。

2,実装

LocalizeManager.h
#ifndef __LocalizeManager__
#define __LocalizeManager__

#include "cocos2d.h"
#include <unordered_map>

//短縮用のマクロ
#define TEXT(__KEY)(LocalizeManager::getInstance()->getStringForKey(__KEY))

USING_NS_CC;

class LocalizeManager
{
private:
    //コンストラクタ
    LocalizeManager();
    
    //自身のインスタンスを保存しておく
    static LocalizeManager* mLocalizeManager;
    
    //文字列を格納する連想配列
    std::unordered_map<std::string, std::string> stringMap;
    
    //初期化
    void initialize();
public:
    //インスタンスを返すスタティックメソッド
    static LocalizeManager* getInstance();
    
    //keyを使って文字列を読み出す
    std::string getStringForKey(std::string key);
};

#endif 
LocallizeManager.cpp
#include "LocalizeManager.h"

using namespace std;

LocalizeManager* LocalizeManager::mLocalizeManager = NULL;

//コンストラクタ
LocalizeManager::LocalizeManager()
{
    
}

//自身のインスタンスを返す、もしインスタンスが存在しない場合はコンストラクタを呼び出しnewする
LocalizeManager* LocalizeManager::getInstance()
{
    if (mLocalizeManager == NULL) {
        mLocalizeManager = new LocalizeManager();
        mLocalizeManager->initialize();
    }
    
    return mLocalizeManager;
}

//値の初期化、テキストファイルの読み込み
void LocalizeManager::initialize()
{
    //言語の取得
    LanguageType lang = Application::getInstance()->getCurrentLanguage();
    if (lang != LanguageType::JAPANESE) {
        //日本語以外は英語として扱う
        lang = LanguageType::ENGLISH;
    }
    
    //テキストデータを読み込む
    auto fileUtiles = FileUtils::getInstance();
    string data = fileUtiles->getStringFromFile("language.csv");
    if (data.length() == 0) {
        log("can't get string data");
        return;
    }
    
    
    //パースを行う
    istringstream is(data); //テキストデータから文字列ストリームを作成
    string csvLine; //行
    while (std::getline(is, csvLine)) { //一行ずつ読み込む
        istringstream csvStream(csvLine);
        string csvCol; //列の項目
        int cntCol = 1; //項目番号
        string key; //keyを一時保存しておく
        while (std::getline(csvStream, csvCol, ',')) { //一項目ずつ読み込む
            switch (cntCol) {
                case 1:
                    key = csvCol;
                    if (stringMap.count(key) != 0) {
                        log("key:\"%s\"が重複しています", key.c_str());
                    }
                    break;
                case 2:
                    if (lang == LanguageType::ENGLISH) {
                        stringMap[key] = csvCol;
                    }
                    break;
                case 3:
                    if (lang == LanguageType::JAPANESE) {
                        stringMap[key] = csvCol;
                    }
                    break;
                default:
                    break;
            }
            cntCol++; //項目番号のincrement
        }
    }
}

//keyを使って文字列を読み込む
string LocalizeManager::getStringForKey(std::string key)
{
    if (stringMap.count(key) != 0) {
        return stringMap.at(key);
    }else
    {
        log("指定されたキーが存在しません");
        return "";
    }
}

3,使い方

language.csv
hello,Hello,こんにちは
bye,See you,さようなら

をリソースに追加しておく。

hogeScene.cpp
#include "LocalizeManager.h"

void makeLabel()
{
    string text = LocalizeManager::getInstance()->getStringForKey("hello");
    auto hogeLabel = Label::createWithSystemFont(text, "FONT_NAME", font_size);
    this->addchild(hogeLabel);
}

いちいちLocalizeManager::getInstance()->getStringForKey("key")と打つのはめんどくさいので、.hで定義したマクロを使って

    string text = TEXT("hello");
    auto fugaLabel = Label::createWithSystemFont(TEXT("bye"), "FONT_NAME", font_size);

とかすると楽。

4.まとめ

  • keyについては重複しないように注意しなければならない。重複しているとlogにメッセージが表示されるので確認すること。
  • 少しいじれば、他のテキストファイルをload、unloadできるはず。
  • CSVファイルとパース部分に新しい言語を追加すれば簡単に対応言語を増やせるはず。