@HepkaPlay
JavaScript Junior.

Как сделать локализацию бота?

Как на абузя вот так:
if(guild.language == "Ru") {
// Functions for Rus
}
if(guild.language == "En") {
// Functions for Eng
}

Сделать нормальную локализацию?
  • Вопрос задан
  • 69 просмотров
Решения вопроса 3
@Azperin
Дилетант
Как вариант можно сделать так:
phrases: {
	sayHi: {
		ru: 'Привет',
		en: 'Hello',
		//... и тд
	},
}

.on('message', (m) => {
	let lang = m.guild.language;
	
	m.replay(phrases.sayHi[lang]);
});
Ответ написан
Kozack
@Kozack Куратор тега JavaScript
Thinking about a11y
lastuniverse
@lastuniverse
Всегда вокруг да около IT тем
я данную задачу решал самописным модулем.

сам модуль
const fs = require('fs');
const path = require('path');


class Messages {
	constructor ({localeName="ru_ru", dataPath="messages"}){
		console.log(localeName, dataPath);
		this.steDafaultLocale(localeName);
		this.dataPath = dataPath;
		
		this.messages =	{};

		if ( !fs.existsSync(this.dataPath) )
			throw "Каталога "+this.dataPath+" не существует";
		
		fs.readdirSync(this.dataPath).forEach(file => {
			if( !file.match(/\.json$/) )
				return {};

			const fileName = path.basename(file, ".json");
			const filePath = path.join( this.dataPath,  fileName+".json" ); 
			this.messages[fileName] = require(filePath);
		})


		this.localized = this.messages[this.defaultLocale];

	}
	

	steDafaultLocale(localeName="ru_ru"){
		this.defaultLocale = localeName;
	}

	/**
	 * [join description]
	 * @param  {[type]} message [description]
	 * @return {[type]}         [description]
	 */
	join(message){
		if( !message || typeof message === 'function')
			return "";

		if( typeof message === 'string' || typeof message === 'number' )
			return ""+message;

		if( typeof message === 'object' && Array.isArray(message) )
			message = message
			.map(o=>{
				return this.join(o);
			})
			.join("");

		if( typeof message === 'object' && !Array.isArray(message) )
			message = Object.values(message)
			.map(o=>{
				return this.join(o);
			})
			.join("");

		return message;
	}
	/**
	 * [join description]
	 * @param  {[type]} message [description]
	 * @return {[type]}         [description]
	 */
	joinToArray(message){
		let list = [];
		if( !message || typeof message === 'function')
			return list;

		if( typeof message === 'string' || typeof message === 'number' )
			return [""+message];

		if( typeof message === 'object' && Array.isArray(message) ){
			message
			.forEach(o=>{
				list = list.concat(this.joinToArray(o));
			});
		}

		if( typeof message === 'object' && !Array.isArray(message) ){
			Object.values(message)
			.forEach(o=>{
				list = list.concat(this.joinToArray(o));
			});
		}

		return list;
	}

	/**
	 * [collect description]
	 * @return {[type]} [description]
	 */
	collect(message, is_random){
		return this.join(message)
		.replace(/\$\{(.*?)\}/g, (str,key)=>{
			//console.log("Messages.collect","key",key);
			return this.getKey(key,this.localized,is_random);
		});
	}


	/**
	 * the function returns a message in the user's language (if there is a localization file for this language)
	 * @param {string} message   text, can contain special inserts of type "$ {complex .key}" which will be replaced with values from the localization file
	 * @param {object} keys      associative array with values
	 * @param {string} [locale]  permanently use localization
	 * @return {string} message in the user's language.
	 */
	getMessage(message, keys, locale) {
		const temp = this.localized;
		this.localized = this.messages[locale||this.defaultLocale];
		// заменить каждое вхождение ${key} на результат вызова функции
		const result = this.collect(message)
		.replace(/\$\{(.*?)\}/g, (str,key)=>{
			return this.getKey(key,keys||{});
		});
		this.localized = temp;
		return result;
	}
	/**
	 * the function returns a random message in the user's language (if there is a localization file for this language)
	 * @param {string} message   text, can contain special inserts of type "$ {complex .key}" which will be replaced with values from the localization file
	 * @param {object} keys      associative array with values
	 * @param {string} [locale]  permanently use localization
	 * @return {string} message in the user's language.
	 */	
	getRandMessage(message, keys, locale) {
		const temp = this.localized;
		// если задана локадизация используем ее, если нет то используем this.defaultLocale
		this.localized = this.messages[locale||this.defaultLocale];
		// заменить каждое вхождение ${key} на результат вызова функции
		const result = this.collect(message, true)
		.replace(/\$\{(.*?)\}/g, (str,key)=>{
			return this.getKey(key,keys||{});
		});
		this.localized = temp;
		return result;
	}

	getKeyData(key){
		if( key === undefined )
			return undefined;

		let path = key.split(/\./);
		let keys = this.localized;
		for(let i in path){
			let k=path[i];
			keys=keys[k];
			if( keys === undefined || typeof keys === "function" )
				return undefined;
		}
		if( keys === undefined )
			return undefined;

		return keys;
	}
	/**
	 * [getKey description]
	 * @param  {[type]} key  [description]
	 * @param  {[type]} keys [description]
	 * @return {[type]}      [description]
	 */
	getKey(key,keys,is_random){
		if( keys === undefined )
			return "";

		let path = key.split(/\./);
		for(let i in path){
			let k=path[i];
			keys=keys[k];
			
			//console.log("Messages.getKey 00", key, k, typeof keys, is_random);

			if( keys === undefined || typeof keys === "function" )
				return "";
		}
		if( typeof keys === "object" ){
			if(is_random){
				//console.log("Messages.getKey 01", key, typeof keys, is_random);
				keys = this.joinToArray(keys);
				//console.log("Messages.getKey 02", key, typeof keys, is_random, keys);
				keys = keys[ Math.floor( Math.random()*keys.length ) ];
			}else{
				//console.log("Messages.getKey 03", key, typeof keys, is_random);
				keys = this.join(keys);
			}
		}
		//console.log("Messages.getKey 04", key, typeof keys, is_random);
		if( keys === undefined )
			return "";
		return keys;
	}
}
module.exports = Messages;


типовые файлы локализации

./data/messages/events/en_en.json
{
	"welcome": {
		"first": "Hello ${name}, hello, we are glad to see you on our channel",
		"other": [
			"hi ${name}, why bother?",
			"${name}, get out from here!",
			"${name}, you are not welcome here!"
		]
	}
}


./data/messages/events/ru_ru.json
{
	"welcome": {
		"first": "Привет ${name}, мы рады видеть Вас на нашем канале",
		"other": [
			"Хай ${name}, что приперся?",
			"${name}, вали отсюда!",
			"${name}, тебе здесь не рады!"
		]
	}
}

./data/messages/battle/en_en.json
{
	"block": [
		"${name.from} placed a block and ${name.to} was too weak to break it",
		"${name.from} bounced aside and ${name.to} flew past without causing damage",
		"${name.from} bent down and as a result ${name.to} pounded the air for five minutes)"
	],
	"shot": [
		"${name.from} so loaded it into the jaw in this foolishness, ${name.to} got ${damage} of damage and was knocked out",
		"${name.from} dodged and stabbed in the crotch, inflicting ${damage} damage. ${name.to} subtly squeaks and rolls across the sand of the arena",
		"${name.from} jabbed his teeth in the eye, ${name.to} received ${damage} damage and whines quietly in the corner of the arena"
	]
}


./data/messages/battle/ru_ru.json
{
	"block": [
		"${name.from} поставил блок а ${name.to} был слишком слаб чтобы пробить его",
		"${name.from} отскочил в сторону и ${name.to} пролетел мимо не нанеся урона",
		"${name.from} пригнулся и в результате ${name.to} пять минут колотил воздух)"
	],
	"shot": [
		"${name.from} со в сей дури зарядил в челюсть, ${name.to} получив ${damage} урона был нокаутирован",
		"${name.from} извернувшись, нанес удар в промежность, нанеся ${damage} урона. ${name.to} тонко попискивая катается по песку арены",
		"${name.from} ткнул зубочиствой в глаз, ${name.to} получив ${damage} урона тихо поскуливает в углу арены"
	]
}



пример использования
const path = require('path');
const Messages = require('./modules/messages.js');

const eventsMsg	= new Messages({
	localeName: "ru_ru",
	dataPath: path.join( __dirname, "data/messages/events" )
});

const battleMsg	= new Messages({
	localeName: "ru_ru",
	dataPath: path.join( __dirname, "data/messages/battle" )
});


let msg = "";

// сообщение 
msg = eventsMsg.getMessage(
	"${welcome.first}", 
	{name: "Вася"}
);
console.log(msg); // Привет Вася, мы рады видеть Вас на нашем канале



// смешанное сообщение из файла локализации
msg = eventsMsg.getMessage(
	"aaaaa ${welcome.first} bbbbb ${welcome.other.1}", 
	{name: "Вася"}
);
console.log(msg); // aaaaa Привет Вася, мы рады видеть Вас на нашем канале bbbbb Вася, вали отсюда!

// сообщение с принудительной локализацией
msg = eventsMsg.getMessage(
	"${welcome.first}", 
	{name: "Вася"},
	"en_en"
);
console.log(msg); // Hello Вася, hello, we are glad to see you on our channel


// случайное сообщение из списка
for(var i=0; i<5; i++){
	msg = battleMsg.getRandMessage(
		"${shot}", 
		{
			name: {
				from: "Вася",
				to: "Петя"
			},
			damage: 99
		}
	);
	console.log(msg); 
	// Вася извернувшись, нанес удар в промежность, нанеся 99 урона. Петя тонко попискивая катается по песку арены
	// Вася ткнул зубочиствой в глаз, Петя получив 99 урона тихо поскуливает в углу арены
	// Вася со в сей дури зарядил в челюсть, Петя получив 99 урона был нокаутирован
	// Вася извернувшись, нанес удар в промежность, нанеся 99 урона. Петя тонко попискивая катается по песку арены
	// Вася ткнул зубочиствой в глаз, Петя получив 99 урона тихо поскуливает в углу арены
}


структура каталогов
5f8c72146fc85237972458.png
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы
23 окт. 2020, в 05:33
15000 руб./за проект
23 окт. 2020, в 03:00
1500 руб./за проект