查看: 6984|回复: 6

[已经解决] 如何给游戏制作语言包

[复制链接]
头像被屏蔽

国主

梦石
29
星屑
5204
在线时间
1205 小时
注册时间
2015-6-12
回帖
761

短篇十战斗者组别亚军

发表于 2015-12-2 05:09:39 | 显示全部楼层 |阅读模式
提示: 作者被禁止或删除 内容自动屏蔽
签名被屏蔽
梦石
0
星屑
50
在线时间
35 小时
注册时间
2015-5-2
回帖
19
发表于 2015-12-2 07:56:50 | 显示全部楼层
就如汉化版那样,制作英译版本吧,OVER

点评

= = 然而steam上只允许提供一组文件,如果只支持英文的话,那么国内玩家咋办  发表于 2015-12-2 12:39
回复

使用道具 举报

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2015-12-2 08:00:33 | 显示全部楼层

点评

谢啦,虽然全英文看起来很累,我慢慢看XD  发表于 2015-12-2 12:35
我男票卖得一手好萌  发表于 2015-12-2 08:25

评分

参与人数 1星屑 +30 收起 理由
夜$神 + 30 塞糖

查看全部评分

回复

使用道具 举报

梦石
1
星屑
23236
在线时间
9564 小时
注册时间
2012-6-19
回帖
7018

开拓者短篇九导演组冠军

发表于 2015-12-2 08:33:33 | 显示全部楼层

点评

我越来越爱喵呜喵了(》~《)~~~从配置环境打包开始就是看的您汉化的F1  发表于 2015-12-2 12:48
看起来好棒!我摸索一下=。=  发表于 2015-12-2 12:32

评分

参与人数 2星屑 +60 梦石 +1 收起 理由
余烬之中 + 1 我越来越爱喵呜喵了
夜$神 + 60 大师球!!!

查看全部评分

回复

使用道具 举报

梦石
0
星屑
22879
在线时间
8598 小时
注册时间
2011-12-31
回帖
3270
发表于 2015-12-2 09:45:28 | 显示全部楼层
本帖最后由 tseyik 于 2015-12-2 15:05 编辑

Iavra Localization(原来和3楼一様是來自I18N)
http://forums.rpgmakerweb.com/in ... iavra-localization/
http://pastebin.com/xRa0Ar8u
[fold]       

    /*:
     * @plugindesc Allows to store all text content in an external file and switch between languages at runtime.
     * <Iavra Localization>
     * @author Iavra
     *
     * @param Supported Languages
     * @desc Comma-separated list of all supported game languages. The first entry will be treated as default.
     * @default
     *
     * @param File Path
     * @desc Where to load localization files from. "{lang}" will be replaced with the languages specified above.
     * @default i18n/{lang}.json
     *
     * @param Escape Code
     * @desc Code used to insert localized text in game messages. Is used with an additional key parameter.
     * @default :
     *
     * @param Add Menu Entry
     * @desc If set to true, adds a new entry in the options menu, that can be used to change the language.
     * @default false
     *
     * @help
     * To first export your current text entries and to create a template of a language file, set the parameter
     * "Supported Languages" to empty and execute this following script:
     *
     * IAVRA.I18N.exportJson();
     *
     * This will open a new window containing the current data. Save this file under "i18n/{lang}.json", where {lang}
     * is the language this file stands for. You can copy it any number of times and save different versions to
     * support different languages. You also need to extend the category "options" to contain the labels for all the
     * languages you just added. So, if you are supporting german ("de") and english ("en"), your "options" entry in
     * "i18n/en.json" would look like this:
     *
     * "options": {
     *     "option": "Game Language",
     *     "en": "English",
     *     "de": "Deutsch"
     * }
     *
     * "option" is the text that will be shown in the options menu, if you set the parameter "Add Menu Entry" to true.
     * I advise not to translate the language labels, because it might be hard for non english speaking users to find
     * their own language.
     *
     * When you are finished editing the files, change the parameter "Supported Languages" to contain all of your
     * languages, separated by a comma. So in this case that would be "en, de". Note that the first language will be
     * treated as the default if no config file could be found.
     *
     * To change the current language, there are 3 options. The first 2 are actually the same and allow you to temporarily
     * change the current language. To do this, execute one of these script calls:
     *
     * IAVRA.I18N.changeLanguage("de");
     * ConfigManager.language = "de";
     *
     * However, this change will only last for as long as the game is running and will revert to the default, afterwards.
     * If you want to persistently change the language set the parameter "Add Menu Entry" to true and have the user go
     * to the options menu. There will be a new entry for changing the current language, which will be saved in the option
     * file.
     *
     * If you want to localize text messages, you can save them under the "text" category of the language file, which has
     * been created for you when you exported the current text data. So, if you want to create a welcome message for the
     * user, you can do it like this:
     *
     * "text: {
     *     "welcome": "Hello, User"  
     * }
     *
     * If you want to use this in a message, you need the escape code you can define by setting "Escape Code". Assuming
     * you left it at the default value ":", your message would contain this tag:
     *
     * \:[welcome]
     *
     * You are free to use any escape codes inside language files, but note that you might need to double backslashes. So
     * if you want to display the variable #1, you'd write "\\V[1]" instead of "\V[1]". Also, it's possible to recursively
     * use our own escape code, so if you would change your "text" category to this:
     *
     * "text: {
     *     "welcome": "Hello, \\:[user]",
     *     "user": "User"
     * }
     *
     * Your "\:[welcome"] would still be resolved to "Hello, User". This is handy if you have certain text entries, that
     * might be subject to change, but are used at multiple places (like town names) and allows you to keep them in a central
     * spot.
     */
     
    var Imported = Imported || {};
    Imported.iavra_localization = true;
     
    //=============================================================================
    // namespace IAVRA
    //=============================================================================
     
    var IAVRA = IAVRA || {};
     
    (function() {
        "use strict";
      
        /**
         * Since PluginManager.parameters() breaks when the plugin file is renamed, we are using our own solution.
         */
        var _params = (function($) {
            return {
                languages: $['Supported Languages'].split(/\s*,\s*/).filter(function(value) { return !!value; }),
                filePath: $['File Path'],
                textRegex: new RegExp('\\\\' + $['Escape Code'] + '\\[(.+)\\]', 'g'),
                menuEntry: $['Add Menu Entry'].toLowerCase() === 'true'
            };
        })($plugins.filter(function(p) { return p.description.contains('<Iavra Localization>'); })[0].parameters);
      
        /**
         * Mappings for indizes to keys or for which attributes to export/import. Please don't change this, unless
         * you really know what you're doing.
         */
        var _mappings = {
            /**
             * $dataSystem.terms.basic, the order is important!
             */
            basic: ['level', 'levelA', 'hp', 'hpA', 'mp', 'mpA', 'tp', 'tpA', 'exp', 'expA'],
            /**
             * $dataSystem.terms.params, the order is important!
             */
            params: ['maxHP', 'maxMP', 'attack', 'defense', 'mAttack', 'mDefense', 'agility', 'luck', 'hitRate', 'evasion'],
            /**
             * $dataSystem.terms.commands, both order and null values are important!
             */
            commands: ['fight', 'escape', 'attack', 'guard', 'item', 'skill', 'equip', 'status', 'formation', 'save',
                      'gameEnd', 'options', 'weapon', 'armor', 'keyItem', 'equip2', 'optimize', 'clear', 'newGame',
                      'continue', null, 'toTitle', 'cancel', null, 'buy', 'sell'],
            /**
             * $dataSystem.terms.messages.
             */
            messages: ['alwaysDash', 'commandRemember', 'bgmVolume', 'bgsVolume', 'meVolume', 'seVolume', 'possession',
                      'expTotal', 'expNext', 'saveMessage', 'loadMessage', 'file', 'partyName', 'emerge', 'preemptive',
                      'surprise', 'escapeStart', 'escapeFailure', 'victory', 'defeat', 'obtainExp', 'obtainGold',
                      'obtainItem', 'levelUp', 'obtainSkill', 'useItem', 'criticalToEnemy', 'criticalToActor',
                      'actorDamage', 'actorRecovery', 'actorGain', 'actorLoss', 'actorDrain', 'actorNoDamage', 'actorNoHit',
                      'enemyDamage', 'enemyRecovery', 'enemyGain', 'enemyLoss', 'enemyDrain', 'enemyNoDamage', 'enemyNoHit',
                      'evasion', 'magicEvasion', 'magicReflection', 'counterAttack', 'substitute', 'buffAdd', 'debuffAdd',
                      'buffRemove', 'actionFailure'],
            /**
             * $dataActors
             */
            actors: ['name', 'nickname', 'profile'],
            /**
             * $dataClasses
             */
            classes: ['name'],
            /**
             * $dataSkills
             */
            skills: ['name', 'description', 'message1', 'message2'],
            /**
             * $dataItems
             */
            items: ['name', 'description'],
            /**
             * $dataWeapons
             */
            weapons: ['name', 'description'],
            /**
             * $dataArmors
             */
            armors: ['name', 'description'],
            /**
             * $dataEnemies
             */
            enemies: ['name'],
            /**
             * $dataStates
             */
            states: ['name', 'message1', 'message2', 'message3', 'message4'],
            /**
             * Placeholder for this plugin's entry to the options menu.
             */
            options: undefined,
            /**
             * Placeholder for localized game messages.
             */
            text: undefined
        };
      
        /**
         * Some categories are handled in the same way and can be grouped together, so the filesize of this plugin
         * doesn't get bloated.
         */
        var _categoryGroups = {
            system: ['gameTitle', 'currencyUnit'],
            terms: ['basic', 'params', 'commands'],
            types: ['elements', 'skillTypes', 'weaponTypes', 'armorTypes', 'equipTypes'],
            data: ['actors', 'classes', 'skills', 'items', 'weapons', 'armors', 'enemies', 'states']
        };
      
        /**
         * Contains all localized text.
         */
        var _data = {};
      
        /**
         * The current language.
         */
        var _lang;
      
        /**
         * Loads all language files and put their contents in our data variable. We also sanitize missing entries,
         * sp the plugin doesn't just crash.
         */
        var loadDatabase = function() {
            _params.languages.forEach(function(lang) {
                loadFile(_params.filePath.replace('{lang}', lang), function(data) {
                    Object.keys(_mappings).forEach(function(category) { data[category] || (data[category] = {}); });
                    _data[lang] = data;
                });
            });
            // This serves as fallback, when no languages are specified and can be used for exporting.
            _data[undefined] = Object.keys(_mappings).reduce(function(map, category) { map[category] = {}; return map; }, {});
        };
      
        /**
         * Helper function to async load a file and execute a given callback after the request finishes.
         */
        var loadFile = function(url, callback) {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', url);
            xhr.overrideMimeType('application/json');
            xhr.onload = function() { callback(JSON.parse(xhr.responseText)); };
            xhr.onerror = function() { throw new Error("There was an error loading the file '" + url + "'."); };
            xhr.send();
        };
      
        /**
         * Used to determine if all async calls have been completed.
         */
        var isDatabaseLoaded = function() {
            return _params.languages.every(function(lang) { return _data[lang] !== undefined; });
        };
      
        /**
         * Actors save their name, nickname and profile and don't dynamically read them from $dataActors, like every other
         * data type does, so they need special treatment. Also this needs to be called when loading a savegame or otherwise
         * the user could change the language and load a game and these changes wouldn't carry over.
         */
        var fixGameActors = function() {
            $gameActors._data.forEach(function(actor, index) {
                if(!actor || !$dataActors[index]) { return; }
                actor._name = $dataActors[index].name;
                actor._nickname = $dataActors[index].nickname;
                actor._profile = $dataActors[index].profile;
            });
        };
      
        //=============================================================================
        // module IAVRA.I18N
        //=============================================================================
      
        IAVRA.I18N = {
            /**
             * Can be used to export all text entries in the game, except messages. Still a whole lot of stuff. Opens
             * a new window containing the created JSON data.
             */
            exportJson: function() {
                var data = {};
                _categoryGroups.system.forEach(function(key) { data[key] = $dataSystem[key]; });
                _categoryGroups.terms.forEach(function(category) {
                    data[category] = _mappings[category].reduce(function(map, key, index) { !key || (map[key] = $dataSystem.terms[category][index]); return map; }, {});
                });
                data.messages = _mappings.messages.reduce(function(map, key) { !key || (map[key] = $dataSystem.terms.messages[key]); return map; }, {});
                _categoryGroups.types.forEach(function(category) {
                    data[category] = $dataSystem[category].reduce(function(map, value, index) { !value || (map[index] = value); return map;  }, {});
                });
                _categoryGroups.data.forEach(function(category) {
                    data[category] = window['$data' + category[0].toUpperCase() + category.slice(1)].reduce(function(map, value, index) {
                        !value || (map[index] = _mappings[category].reduce(function(map, key) { map[key] = value[key]; return map; }, {})); return map;
                    }, {});
                });
                data.options = {option: TextManager._text('options', 'option') || 'Change game language'};
                _params.languages.forEach(function(lang) { data.options[lang] = TextManager._text('options', lang) || lang; });
                data.text = {};
                window.open(encodeURI('data:text/json;charset=utf-8,' + JSON.stringify(data, null, '\t')));
            },
            /**
             * Changes the current language. Note that direct calls to this function will only temporarily change the
             * language and it will revert to its former value after a reload. If you want to persistently change the
             * language, use the ConfigManager, instead.
             */
            changeLanguage: function(lang) {
                // If no language was given or the given language is not supported, we do nothing.
                if(!lang || !_data[lang]) { return; }
                _lang = lang;
                // Setting system data.
                _categoryGroups.system.forEach(function(key) { $dataSystem[key] = _data[_lang][key] || ''; });
                // Setting terms on $dataSystem.
                _categoryGroups.terms.forEach(function(category) {
                    $dataSystem.terms[category].forEach(function(term, index) {
                        !term || ($dataSystem.terms[category][index] = (_data[_lang][category] || {})[_mappings[category][index]] || '');
                    });
                });
                Object.keys($dataSystem.terms.messages).forEach(function(key) {
                    $dataSystem.terms.messages[key] = _data[_lang].messages[key] || '';
                });
                // Setting types on $dataSystem.
                _categoryGroups.types.forEach(function(category) {
                    $dataSystem[category].forEach(function(type, index) {
                        !type || ($dataSystem[category][index] = (_data[_lang][category] || {})[index] || '');
                    });
                });
                // Setting a lot of stuff on $data<...> arrays.
                _categoryGroups.data.forEach(function(category) {
                    window['$data' + category[0].toUpperCase() + category.slice(1)].forEach(function(element, index) {
                        !element || _mappings[category].forEach(function(key) {
                            element[key] = (_data[_lang][category][index] || {})[key] || '';
                        });
                    });
                });
                // Fixing $gameActors, if they exist.
                !$gameActors || fixGameActors();
            },
            /**
             * Returns the current language.
             */
            currentLanguage: function() { return _lang; }
        };
      
        //=============================================================================
        // module TextManager
        //=============================================================================
      
        (function($) {
           
            /**
             * Can be used to retrieve text from any category, including custom ones.
             */
            $._text = function(category, key) {
                return (_data[_lang][category] || {})[key] || '';
            };
           
        })(TextManager);
      
        //=============================================================================
        // module ConfigManager
        //=============================================================================
      
        (function($) {
           
            /**
             * Returns the current language and can be used to set the current language. Note, that changes done in
             * the ConfigManager aren't persisted until ConfigManager.save() has been called, which is automatically
             * done when Scene_Options is terminated.
             */
            Object.defineProperty($, 'language', {
                get: function() { return _lang; },
                set: function(value) { IAVRA.I18N.changeLanguage(value || _params.languages[0]); },
                configurable: true
            });
     
            /**
             * Include the current language in the options savefile.
             */
            var _alias_makeData = $.makeData;      
            $.makeData = function() {
                var config = _alias_makeData.call(this);
                config.language = this.language;
                return config;
            };
           
            /**
             * Load the current language from the options savefile.
             */
            var _alias_applyData = $.applyData;
            $.applyData = function(config) {
                _alias_applyData.call(this, config);
                this.language = config.language;
            };
           
        })(ConfigManager);
      
        //=============================================================================
        // module DataManager
        //=============================================================================
      
        (function($) {
           
            /**
             * Fixing $gameActors, when they get created.
             */
            var _alias_createGameObjects = $.createGameObjects;
            $.createGameObjects = function() {
                _alias_createGameObjects.call(this);
                fixGameActors();
            };
           
            /**
             * Fixing $gameActors after a save has been loaded, in case the language was changed in the meantime.
             */
            var _alias_extractSaveContents = $.extractSaveContents;
            $.extractSaveContents = function(contents) {
                _alias_extractSaveContents.apply(this, arguments);
                fixGameActors();
            };
           
        })(DataManager);
      
        //=============================================================================
        // class Scene_Boot
        //=============================================================================
     
        (function($) {
           
            /**
             * Loading our database on game startup.
             */
            var _alias_create = $.prototype.create;
            $.prototype.create = function() {
                loadDatabase();
                _alias_create.call(this);
            };
           
            /**
             * We are waiting for out localization files to be loaded. This way, we are free to use async loading,
             * which is more flexible than sync loading and doesn't throw a warning in browsers. Sadly, we have to
             * call ConfigManager.load() a second time, after our database has been loaded, because it's called
             * too early for us. So this basically means, that we are loading the config file twice, but the only
             * alternative would be to rewrite Scene_Boot.create without extending it, which is kind of ugly, because
             * it means that this plugin would always have to be at the top of the plugin list.
             */
            var _alias_isReady = $.prototype.isReady;
            $.prototype.isReady = function() {
                var ready = isDatabaseLoaded() && _alias_isReady.call(this);
                if(ready) { ConfigManager.load(); }
                return ready;
            };
           
        })(Scene_Boot);
      
        //=============================================================================
        // class Window_Base
        //=============================================================================
      
        (function($) {
           
            /**
             * Replaces all occurences of the given escape character with the localized text or "", if the key could
             * not be found. This is done recursively, so it's possible to specify the escape character in localized
             * text and specify subjects to change in central places (like city names). Also, this is done before
             * other escape characters are replaced, so it's possible to use other escape characters in localized
             * text, too.
             */
            var replace = function(text) {
                if(_params.textRegex.test(text)) {
                    return replace(text.replace(_params.textRegex, function(match, group) {
                        return _data[_lang].text[group] || "";
                    }));
                }
                return text;
            };
           
            /**
             * Before converting escape characters, we first replace our own character with localized text, so it's
             * possible to use escape characters in there.
             */
            var _alias_convertEscapeCharacters = $.prototype.convertEscapeCharacters;
            $.prototype.convertEscapeCharacters = function(text) {
                return _alias_convertEscapeCharacters.call(this, replace(text));
            };
           
            /**
             * Replaces our escape character in calls to drawText, which makes it work with other plugins.
             */
            var _alias_drawText = $.prototype.drawText;
            $.prototype.drawText = function(text, x, y, maxWidth, align) {
                _alias_drawText.call(this, replace(text), x, y, maxWidth, align);
            };
           
        })(Window_Base);
      
        //=============================================================================
        // class Window_Options
        //=============================================================================
      
        if(_params.menuEntry) {
            (function($) {
               
                /**
                 * Returns the previous language in the list or either the same language (if the list has only one
                 * element) or undefined (if the list is empty).
                 */
                var getPrevLanguage = function(lang) {
                    var prevIndex = _params.languages.indexOf(lang) - 1;
                    return _params.languages[prevIndex < 0 ? _params.languages.length - 1 : prevIndex];
                };
               
                /**
                 * Returns the next language in the list or either the same language (if the list has only one element)
                 * or undefined (if the list is empty).
                 */
                var getNextLanguage = function(lang) {
                    var nextIndex = _params.languages.indexOf(lang) + 1;
                    return _params.languages[nextIndex > _params.languages.length ? 0 : nextIndex];
                };
               
                /**
                 * Add our own command at the top, since it makes kind of sense.
                 */
                var _alias_makeCommandList = $.prototype.makeCommandList;
                $.prototype.makeCommandList = function() {
                    this.addCommand(TextManager._text('options', 'option'), 'language');
                    _alias_makeCommandList.call(this);
                };
               
                /**
                 * The basic values are either ON/OFF or a percentage value, but we want something else.
                 */
                var _alias_statusText = $.prototype.statusText;
                $.prototype.statusText = function(index) {
                    var symbol = this.commandSymbol(index);
                    if(symbol === 'language') {
                        return TextManager._text('options', this.getConfigValue(symbol));
                    } else {
                        return _alias_statusText.call(this, index);
                    }
                };
               
                /**
                 * On Ok, switch to the next language.
                 */
                var _alias_processOk = $.prototype.processOk;
                $.prototype.processOk = function() {
                    var symbol = this.commandSymbol(this.index());
                    if(symbol === 'language') {
                        this.changeValue(symbol, getNextLanguage(this.getConfigValue(symbol)))
                    } else {
                        _alias_processOk.call(this);
                    }
                };
               
                /**
                 * On right, switch to the next language.
                 */
                var _alias_cursorRight = $.prototype.cursorRight;
                Window_Options.prototype.cursorRight = function(wrap) {
                    var symbol = this.commandSymbol(this.index());
                    if(symbol === 'language') {
                        this.changeValue(symbol, getNextLanguage(this.getConfigValue(symbol)))
                    } else {
                        _alias_cursorRight.call(this, wrap);
                    }
                };
               
                /**
                 * On left, switch to the next language.
                 */
                var _alias_cursorLeft = $.prototype.cursorLeft;
                Window_Options.prototype.cursorLeft = function(wrap) {
                    var symbol = this.commandSymbol(this.index());
                    if(symbol === 'language') {
                        this.changeValue(symbol, getPrevLanguage(this.getConfigValue(symbol)))
                    } else {
                        _alias_cursorLeft.call(this, wrap);
                    }
                };
               
            })(Window_Options);
        }
      
    })();

[/fold]

点评

Woooo,虽然第二个没开vpn打不开,但是第一个看起来不错。先谢过了~  发表于 2015-12-2 12:36

评分

参与人数 2星屑 +30 梦石 +1 收起 理由
余烬之中 + 1 先谢过了~
夜$神 + 30 塞糖

查看全部评分

回复

使用道具 举报

梦石
0
星屑
48
在线时间
784 小时
注册时间
2013-1-4
回帖
1057
发表于 2015-12-2 14:42:11 | 显示全部楼层

点评

预祝绿光成功!  发表于 2015-12-3 00:20
好棒! 已收藏!可惜没糖了_(:3」∠)_  发表于 2015-12-3 00:11
RM-GUI延期。。。最近被黑心老板压迫T_T
二次元少女的shitake,长着长脸,身高165,蓝色卷双马尾,FCUP,瞳色黑色,病气和御宅属性,是天才少女。
回复

使用道具 举报

…あたしは天

梦石
0
星屑
2308
在线时间
4033 小时
注册时间
2010-10-4
回帖
10548

开拓者贵宾

发表于 2015-12-3 14:39:29 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部