Skip to content

Instantly share code, notes, and snippets.

@KyoPanda
Last active August 22, 2017 00:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save KyoPanda/e511af688867188800987161147a951d to your computer and use it in GitHub Desktop.
Save KyoPanda/e511af688867188800987161147a951d to your computer and use it in GitHub Desktop.
/*:
* @plugindesc
* Allows you assign variables to items, weapons or armors quantity in the
* party inventory before you open the Gameus Quest System's menu.
*
* @author Kyo Panda
*
* @param exportOnInit
* @text Export translation on initialization
* @desc
* Defines if the translation source should be exported as the game starts.
* @type boolean
* @default true
*
* @param addCommandToOptions
* @text Add command to options menu
* @desc Defines if the I18N option should be added to the options menu.
* @type boolean
* @default true
*
* @param menuOptions
* @text Menu options
* @desc Defines the languages that appears on the option menu.
* @type struct<MenuOptions>[]
* @default ["{\"locale\":\"en_US\",\"label\":\"English\"}"]
*
* @param extra
* @text Extra
* @desc Extra texts to be added to the source file.
* @type text[]
* @default ["Language", "ON", "OFF"]
*
* @help
*
* MIT License
*
* Copyright (c) 2017 Kyo Panda
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
/*~struct~MenuOptions:
* @param locale
* @text Locale
* @desc
* The language identifier used as the filename.
* Example: pt_BR
* @type text
*
* @param label
* @text Label
* @desc
* The text that appears in the menu.
* Example: Português
* @type text
*/
(function() {
'use strict';
var Imported = window.Imported || {};
Imported.Kyo_I18N = true;
var Kyo = window.Kyo || {};
Kyo.I18N = {
version: '1.0.0-beta'
};
var $ = Kyo.I18N;
var _extends = function() {
var args = arguments;
var dest = args[0];
for (var i = 1; i < args.length; i++) {
for (var key in args[i]) {
var value = args[i][key];
if (value && value.constructor === Object) {
dest[key] = dest[key] || {};
_extends(dest[key], value);
} else {
dest[key] = value;
}
}
}
return dest;
};
var _objectify = function(arr) {
var obj = {};
arr.forEach(function(value) {
if (!value) {
return;
}
obj[value] = '';
});
return obj;
};
$.PARAMS = (function() {
var input = PluginManager.parameters('Kyo_I18N');
var params = {
extra: _objectify(JSON.parse(input.extra) || []),
exportOnInit: input.exportOnInit === 'true',
addCommandToOptions: input.addCommandToOptions === 'true',
formatter: input.formatter || 'gettext',
urls: {
install: input.install || 'lang'
},
menuOptions: [],
paths: {}
};
JSON.parse(input.menuOptions || '[]').reduce(function(arr, curr) {
arr.push(JSON.parse(curr));
return arr;
}, params.menuOptions);
if (Utils.isNwjs() && Utils.isOptionValid('test')) {
params.paths = (function() {
var path = require('path');
var base = path.dirname(process.mainModule.filename);
var install = path.join(base, params.urls.install);
var data = path.join(base, 'data');
return {
base: base,
install: install,
data: data
}
}());
}
return params;
}());
$.LanguageManager = function() {
throw new Error('Class can\'t be instantiated');
};
Object.defineProperty($.LanguageManager, 'formatter', {
get: function() { return this._formatter; },
set: function(formatter) { this._formatter = formatter; },
configurable: true
});
$.LanguageManager._registered = {};
$.LanguageManager.isBusy = function() {
return this._busy;
};
$.LanguageManager.set = function(lang) {
if (this.isBusy()) {
return;
}
$gameSystem.locale = lang;
if (lang === $dataSystem.locale) {
this._source = {};
return;
}
this._busy = true;
var xhr = new XMLHttpRequest();
var urls = $.PARAMS.urls;
var url = [urls.install, lang].join('/');
xhr.open('GET', [url, this._formatter.ext.main].join('.'));
xhr.onload = function() {
if (xhr.status < 400) {
this._source = this._formatter.decode(xhr.responseText);
}
this._busy = false;
}.bind(this);
xhr.onerror = function() {
this._busy = false;
}.bind(this);;
xhr.send();
};
$.LanguageManager.translate = function(text, domain) {
if (!this._source || !this._source[domain]) {
return text;
}
return this._source[domain][text] || text;
};
$.LanguageManager.register = function(domain, data) {
if (!this._registered[domain]) {
this._registered[domain] = {};
}
_extends(this._registered[domain], data);
};
$.LanguageManager.export = function() {
if (!Utils.isNwjs() || !Utils.isOptionValid('test')) {
return;
}
var database;
database = $.DataManager.import();
database = $.DataParser.parse(database);
database = _extends(
database, { Extra: $.PARAMS.extra }, $._registered
);
database = $.DataParser.clear(database);
database = this._formatter.encode(database);
$.DataManager.export(database);
};
$.GettextFormatter = function() {
throw new Error('Class can\'t be instantiated');
};
$.GettextFormatter.ext = {
source: 'pot',
main: 'po'
};
$.GettextFormatter.JSON_REGEXP = new RegExp([
'msgctxt "([^"]*)"',
'msgid "([^"]*)"',
'msgstr "([^"]*)"\\n'
].join('\\n'), 'gi');
$.GettextFormatter.encode = function(database) {
var text = [
'msgid ""',
'msgstr ""',
'"MIME-Version: 1.0\\n"',
'"Content-Type: text/plain; charset=UTF-8\\n"',
'"Content-Transfer-Encoding: 8bit\\n"',
'',
''
].join('\n');
for (var domain in database) {
var data = database[domain];
for (var key in data) {
text += [
'msgctxt ' + JSON.stringify(domain),
'msgid ' + JSON.stringify(key),
'msgstr ""\n',
''
].join('\n');
}
}
return text;
};
$.GettextFormatter.decode = function(database) {
var match;
var result = {};
while ((match = this.JSON_REGEXP.exec(database)) !== null) {
var domain = match[1];
var key = match[2];
var value = match[3];
result[domain] = result[domain] || {};
result[domain][key] = value;
}
return result;
};
$.JsonFormatter = function() {
throw new Error('Class can\'t be instantiated');
};
$.JsonFormatter.ext = {
source: 'json',
main: 'json'
};
$.JsonFormatter.encode = function(database) {
return JSON.stringify(database, null, 4);
};
$.JsonFormatter.decode = function(database) {
return JSON.parse(database);
};
$.DataParser = function() {
throw new Error('Class can\'t be instantiated');
};
$.DataParser.MAPFILE_REGEXP = /map\d+/i;
$.DataParser.parse = function(database) {
var result = {};
for (var domain in database) {
var data = database[domain];
switch (domain) {
case 'Armors':
_extends(result, this.items(data, domain)); break;
case 'Classes':
_extends(result, this.items(data, domain)); break;
case 'CommonEvents':
_extends(result, this.pages(data, domain)); break;
case 'Enemies':
_extends(result, this.enemies(data, domain)); break;
case 'Items':
_extends(result, this.items(data, domain)); break;
case 'MapInfos':
_extends(result, this.items(data, domain)); break;
case 'Skills':
_extends(result, this.skills(data, domain)); break;
case 'States':
_extends(result, this.states(data, domain)); break;
case 'Animations':
_extends(result, this.items(data, domain)); break;
case 'Weapons':
_extends(result, this.items(data, domain)); break;
case 'System':
_extends(result, this.system(data, domain)); break;
case 'Troops':
_extends(result, this.troops(data, domain)); break;
default:
if (this.MAPFILE_REGEXP.test(domain)) {
_extends(result, this.events(data.events, domain));
}
}
}
return result;
};
$.DataParser.clear = function(database) {
for (var domain in database) {
var data = database[domain];
for (var key in data) {
if (!key) {
delete data[key];
}
}
}
return database;
};
$.DataParser.events = function(data, domain) {
var result = {};
data.forEach(function(event) {
if (event === null) {
return;
}
_extends(result, this.pages(event.pages, domain));
}, this);
return result;
};
$.DataParser.pages = function(data, domain) {
var commands = [102, 401, 405];
var result = {};
result[domain] = {};
data.forEach(function(page) {
if (page === null) {
return;
}
page.list.forEach(function(command) {
if (commands.indexOf(command.code) === -1) {
return;
}
if (command.code === 102) {
command.parameters[0].forEach(function(param) {
result[domain][param] = '';
}, this);
return;
}
command.parameters.forEach(function(param) {
result[domain][param] = '';
});
}, this);
}, this);
return result;
};
$.DataParser.items = function(data, domain) {
var result = {};
result[domain] = {};
data.forEach(function(item) {
if (item === null) {
return;
}
result[domain][item.name] = '';
if (item.description) {
result[domain][item.description] = '';
}
}, this);
return result;
};
$.DataParser.enemies = function(data, domain) {
var result = {};
result[domain] = {};
data.forEach(function(enemy) {
if (enemy !== null) {
result[domain][enemy.battlerName] = '';
}
}, this);
return result;
};
$.DataParser.skills = function(data, domain) {
var result = this.items(data, domain);
data.forEach(function(skill) {
if (skill === null) {
return;
}
if (skill.message1) {
result[domain][skill.message1] = '';
}
if (skill.message2) {
result[domain][skill.message2] = '';
}
}, this);
return result;
};
$.DataParser.states = function(data, domain) {
var result = this.skills(data, domain);
data.forEach(function(state) {
if (state === null) {
return;
}
if (state.message3) {
result[domain][state.message3] = '';
}
if (state.message4) {
result[domain][state.message4] = '';
}
}, this);
return result;
};
$.DataParser.system = function(data, domain) {
var result = {};
result[domain + '_Types.Armors'] = _objectify(data.armorTypes);
result[domain + '_Types.Elements'] = _objectify(data.elements);
result[domain + '_Types.Equips'] = _objectify(data.equipTypes);
result[domain + '_Types.Skills'] = _objectify(data.skillTypes);
result[domain + '_Types.Weapons'] = _objectify(data.weaponTypes);
var terms = data.terms;
result[domain + '_Terms.Basic'] = _objectify(terms.basic);
result[domain + '_Terms.Commands'] = _objectify(terms.commands);
result[domain + '_Terms.Params'] = _objectify(terms.params);
result[domain + '_Terms.Messages'] = {};
for (var key in terms.messages) {
result[domain + '_Terms.Messages'][terms.messages[key]] = '';
}
return result;
};
$.DataParser.troops = function(data, domain) {
return _extends(
this.items(data, domain),
this.events(data, domain)
);
}
$.DataManager = function() {
throw new Error('Class can\'t be instantiated');
};
$.DataManager.import = function() {
var fs = require('fs');
var path = require('path');
var dir = $.PARAMS.paths.data;
return fs.readdirSync(dir).reduce(function(database, filename) {
var ext = path.extname(filename);
if (ext !== '.json') {
return database;
}
var contents = fs.readFileSync(path.join(dir, filename));
var basename = path.basename(filename, ext);
database[basename] = JSON.parse(contents);
return database;
}, {});
};
$.DataManager.export = function(data) {
var fs = require('fs');
var path = require('path');
var install = $.PARAMS.paths.install;
install.split(path.sep).reduce(function(base, dir) {
var curr = path.join(base, dir);
if (!fs.existsSync(curr)) {
fs.mkdirSync(curr);
}
return curr;
}, '');
var output = path.join($.PARAMS.paths.install, $dataSystem.locale);
var ext = $.LanguageManager.formatter.ext.source;
fs.writeFileSync([output, ext].join('.'), data);
};
var _Scene_Title_initialize = Scene_Title.prototype.initialize;
Scene_Title.prototype.initialize = function() {
switch ($.PARAMS.formatter) {
case 'json':
$.LanguageManager.formatter = $.JsonFormatter;
break;
default:
$.LanguageManager.formatter = $.GettextFormatter;
}
if ($.PARAMS.exportOnInit) {
$.LanguageManager.export();
}
_Scene_Title_initialize.apply(this, arguments);
};
var _Game_System_initialize = Game_System.prototype.initialize;
Game_System.prototype.initialize = function() {
this._locale = $dataSystem.locale;
_Game_System_initialize.apply(this, arguments);
};
Object.defineProperty(Game_System.prototype, 'locale', {
get: function() { return this._locale; },
set: function(locale) { this._locale = locale; },
configurable: true
});
if ($.PARAMS.addCommandToOptions) {
var _Window_Options_initialize = Window_Options.prototype.initialize;
Window_Options.prototype.initialize = function() {
this._languageIndex = 0;
this._languageOptions = $.PARAMS.menuOptions.reduce(
function(arr, curr, index) {
arr.push(curr.label);
if (curr.locale === $gameSystem.locale) {
this._languageIndex = index;
}
return arr;
}.bind(this), []
);
return _Window_Options_initialize.apply(this, arguments);
};
Window_Options.prototype.languageLocale = function() {
var label = this._languageOptions[this._languageIndex];
var locale = $gameSystem.locale;
for (var key in $.PARAMS.menuOptions) {
var data = $.PARAMS.menuOptions[key];
if (data.label === label) {
locale = data.locale;
break;
}
}
return locale;
};
Window_Options.prototype.isLanguageSymbol = function(symbol) {
return symbol === 'language';
};
var _Window_Options_makeCommandList =
Window_Options.prototype.makeCommandList
;
Window_Options.prototype.makeCommandList = function() {
_Window_Options_makeCommandList.apply(this, arguments);
var text = $.LanguageManager.translate('Language', 'Extra');
this.addCommand(text, 'language');
};
var _Window_Options_statusText = Window_Options.prototype.statusText;
Window_Options.prototype.statusText = function(index) {
var symbol = this.commandSymbol(index);
if (!this.isLanguageSymbol(symbol)) {
return _Window_Options_statusText.apply(this, arguments);
}
var index = this._languageIndex;
return this._languageOptions[index] || 'Default';
};
Window_Options.prototype.changeLanguage = function(increment) {
this._languageIndex += increment;
if (this._languageIndex >= this._languageOptions.length) {
this._languageIndex = 0;
} else if (this._languageIndex < 0) {
this._languageIndex = this._languageOptions.length - 1;
}
var symbol = this.commandSymbol(this.index());
this.redrawItem(this.findSymbol(symbol));
SoundManager.playCursor();
};
var _Window_Options_processOk = Window_Options.prototype.processOk;
Window_Options.prototype.processOk = function() {
var symbol = this.commandSymbol(this.index());
if (!this.isLanguageSymbol(symbol)) {
return _Window_Options_processOk.apply(this, arguments);
}
this.changeLanguage(1);
};
var _Window_Options_cursorRight = Window_Options.prototype.cursorRight;
Window_Options.prototype.cursorRight = function(wrap) {
var symbol = this.commandSymbol(this.index());
if (!this.isLanguageSymbol(symbol)) {
return _Window_Options_cursorRight.apply(this, arguments);
}
this.changeLanguage(1);
};
var _Window_Options_cursorLeft = Window_Options.prototype.cursorLeft;
Window_Options.prototype.cursorLeft = function(wrap) {
var symbol = this.commandSymbol(this.index());
if (!this.isLanguageSymbol(symbol)) {
return _Window_Options_cursorLeft.apply(this, arguments);
}
this.changeLanguage(-1);
};
var _Scene_Options_isBusy = Scene_Options.prototype.isBusy;
Scene_Options.prototype.isBusy = function() {
return (
$.LanguageManager.isBusy() ||
_Scene_Options_isBusy.apply(this, arguments)
);
};
var _Scene_Options_update = Scene_Options.prototype.update;
Scene_Options.prototype.update = function() {
if (Input.isRepeated('cancel')) {
var locale = this._optionsWindow.languageLocale();
if (locale !== $gameSystem.locale) {
$.LanguageManager.set(locale);
}
}
_Scene_Options_update.apply(this, arguments);
};
}
var _TextManager_basic = TextManager.basic;
TextManager.basic = function(basicId) {
var text = _TextManager_basic.apply(this, arguments);
return $.LanguageManager.translate(text, 'System_Terms.Basic');
};
var _TextManager_param = TextManager.param;
TextManager.param = function(paramId) {
var text = _TextManager_param.apply(this, arguments);
return $.LanguageManager.translate(text, 'System_Terms.Params');
};
var _TextManager_command = TextManager.command;
TextManager.command = function(commandId) {
var text = _TextManager_command.apply(this, arguments);
return $.LanguageManager.translate(text, 'System_Terms.Commands');
};
var _TextManager_message = TextManager.message;
TextManager.message = function(messageId) {
var text = _TextManager_message.apply(this, arguments);
return $.LanguageManager.translate(text, 'System_Terms.Messages');
};
var _Window_Options_booleanStatusText =
Window_Options.prototype.booleanStatusText
;
Window_Options.prototype.booleanStatusText = function(value) {
var text = _Window_Options_booleanStatusText.apply(this, arguments);
return $.LanguageManager.translate(text, 'Extra');
};
var _Game_Message_add = Game_Message.prototype.add;
Game_Message.prototype.add = function(text) {
var domain;
var newText = text;
var scene = SceneManager._scene;
if (scene instanceof Scene_Map) {
domain = 'Map%1'.format($gameMap.mapId().toString(16).padZero(3));
}
if (domain) {
newText = $.LanguageManager.translate(text, domain);
}
_Game_Message_add.call(this, newText);
};
window.Imported = Imported;
window.Kyo = Kyo;
}());
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment