diff --git a/Gemfile b/Gemfile index d9f491e..4c87f3c 100644 --- a/Gemfile +++ b/Gemfile @@ -3,4 +3,5 @@ source 'https://rubygems.org' gem 'discordrb', git: 'https://github.com/shardlab/discordrb.git', branch: 'main' gem 'dotenv' -gem 'pg' \ No newline at end of file +gem 'pg' +gem 'i18n' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 5700f92..3f60663 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -17,6 +17,7 @@ GEM remote: https://rubygems.org/ specs: base64 (0.3.0) + concurrent-ruby (1.3.6) domain_name (0.6.20240107) dotenv (3.2.0) event_emitter (0.2.6) @@ -34,6 +35,8 @@ GEM http-accept (1.7.0) http-cookie (1.1.0) domain_name (~> 0.5) + i18n (1.14.8) + concurrent-ruby (~> 1.0) logger (1.7.0) mime-types (3.7.0) logger @@ -78,10 +81,12 @@ PLATFORMS DEPENDENCIES discordrb! dotenv + i18n pg CHECKSUMS base64 (0.3.0) sha256=27337aeabad6ffae05c265c450490628ef3ebd4b67be58257393227588f5a97b + concurrent-ruby (1.3.6) sha256=6b56837e1e7e5292f9864f34b69c5a2cbc75c0cf5338f1ce9903d10fa762d5ab discordrb (3.7.2) discordrb-webhooks (3.7.2) domain_name (0.6.20240107) sha256=5f693b2215708476517479bf2b3802e49068ad82167bcd2286f899536a17d933 @@ -100,6 +105,7 @@ CHECKSUMS ffi (1.17.3-x86_64-linux-musl) sha256=086b221c3a68320b7564066f46fed23449a44f7a1935f1fe5a245bd89d9aea56 http-accept (1.7.0) sha256=c626860682bfbb3b46462f8c39cd470fd7b0584f61b3cc9df5b2e9eb9972a126 http-cookie (1.1.0) sha256=38a5e60d1527eebc396831b8c4b9455440509881219273a6c99943d29eadbb19 + i18n (1.14.8) sha256=285778639134865c5e0f6269e0b818256017e8cde89993fdfcbfb64d088824a5 logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203 mime-types (3.7.0) sha256=dcebf61c246f08e15a4de34e386ebe8233791e868564a470c3fe77c00eed5e56 mime-types-data (3.2025.0924) sha256=f276bca15e59f35767cbcf2bc10e023e9200b30bd6a572c1daf7f4cc24994728 diff --git a/src/bot.rb b/src/bot.rb index 56b38dc..3a4bf7c 100644 --- a/src/bot.rb +++ b/src/bot.rb @@ -15,10 +15,22 @@ # along with this program. If not, see . require 'discordrb' +require 'i18n' require_relative 'database' +require_relative 'utils/locales_helper' class FrugalityBot def initialize + + I18n.config.enforce_available_locales = false + + locales_path = File.join(File.dirname(__dir__), 'locales') + I18n.load_path += Dir["#{locales_path}/*.yml"] + + I18n.backend.load_translations + I18n.default_locale = :en + + @bot = Discordrb::Bot.new( token: ENV['BOT_TOKEN'], intents: [:servers, :server_messages] diff --git a/src/commands/add.rb b/src/commands/add.rb index 56aa3dc..fd8c5f4 100644 --- a/src/commands/add.rb +++ b/src/commands/add.rb @@ -14,25 +14,40 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +require 'i18n' + module Commands - module Add - extend self + module Add + extend self + + def register(bot, db) + command_key = :add + arg_amount_key = :amount + arg_reason_key = :reason + + cmd_desc = I18n.t('commands.add.description', locale: :en) + amount_desc = I18n.t('commands.add.args.amount_desc', locale: :en) + reason_desc = I18n.t('commands.add.args.reason_desc', locale: :en) + + bot.register_application_command(command_key, cmd_desc, server_id: ENV['TEST_SERVER_ID']) do |cmd| + cmd.integer(arg_amount_key, amount_desc, required: true) + cmd.string(arg_reason_key, reason_desc, required: false) + end + + bot.application_command(command_key) do |event| + db_lang = db.get_language(event.user.id) + discord_lang = event.locale.to_s[0..1] + I18n.locale = db_lang || (I18n.available_locales.include?(discord_lang.to_sym) ? discord_lang : :en) + + user_id = event.user.id + amount = event.options['amount'] + reason = event.options['reason'] || 'income' - def register(bot, db) - bot.register_application_command(:add, 'Adds money to the wallet.', server_id: ENV['TEST_SERVER_ID']) do |cmd| - cmd.integer('amount', 'The amount you want to add.', required: true) - cmd.string('reason', "Reason you're adding money to the wallet. Leave empty for default.", required: false) - end + db.update_balance(user_id, amount, reason) - bot.application_command(:add) do |event| - user_id = event.user.id - amount = event.options['amount'] - reason = event.options['reason'] ||= 'transaction' - - db.update_balance(user_id, amount, reason) - - event.respond(content: "Added: #{amount} to the wallet.\nReason: #{reason}") - end - end + msg = I18n.t('responses.add.success', amount: amount, reason: reason, default: "Added #{amount} (Reason: #{reason})") + event.respond(content: msg) + end end + end end \ No newline at end of file diff --git a/src/commands/currency.rb b/src/commands/balance.rb similarity index 85% rename from src/commands/currency.rb rename to src/commands/balance.rb index a156e23..a9a6594 100644 --- a/src/commands/currency.rb +++ b/src/commands/balance.rb @@ -15,13 +15,13 @@ # along with this program. If not, see . module Commands - module Currency + module Balance extend self def register(bot, db) - bot.register_application_command(:currency, 'Get your currency', server_id: ENV['TEST_SERVER_ID']) + bot.register_application_command(:balance, 'Get your currency', server_id: ENV['TEST_SERVER_ID']) - bot.application_command(:currency) do |event| + bot.application_command(:balance) do |event| # 1. Get the User ID from the event user_id = event.user.id diff --git a/src/database.rb b/src/database.rb index b25a0d0..2f2eaf4 100644 --- a/src/database.rb +++ b/src/database.rb @@ -50,19 +50,23 @@ class Database @conn.exec(sql_wallet) @conn.exec(sql_ledger) @conn.exec(sql_index) + + begin + @conn.exec("ALTER TABLE wallets ADD COLUMN IF NOT EXISTS locale VARCHAR(5) DEFAULT 'en'") + rescue PG::Error => e + puts "Migration note: #{e.message}" + end + puts "Database tables have been initialized." end - # We pass the user_id def get_currency(user_id) - # 1. Run the query using parameters ($1) to prevent SQL injection + # Run the query using parameters ($1) to prevent SQL injection result = @conn.exec_params("SELECT amount FROM wallets WHERE user_id = $1", [user_id]) - # 2. Check if the user exists if result.num_tuples.zero? return 0 # User has no money/row yet else - # 3. Return the value (don't print it) return result[0]['amount'].to_i end end @@ -106,4 +110,23 @@ class Database net: row['net_change'].to_i } end + + def get_language(user_id) + result = @conn.exec("SELECT locale FROM wallets WHERE user_id = $1", [user_id]) + + return nil if result.num_tuples.zero? + + return result[0]['locale'] + end + + def set_language(user_id, locale) + sql = <<~SQL + INSERT INTO wallets(user_id, amount, locale) + VALUES ($1, 0, $2) + ON CONFLICT (user_id) + DO UPDATE SET locale = $2 + SQL + + @conn.exec(sql, [user_id, locale]) + end end \ No newline at end of file diff --git a/src/locales/en.yml b/src/locales/en.yml new file mode 100644 index 0000000..148b559 --- /dev/null +++ b/src/locales/en.yml @@ -0,0 +1,19 @@ +en: + commands: + add: + name: "add" + description: "Add money to the wallet." + args: + amount: "amount" + amount_desc: "How much money you're adding to the wallet." + reason: "reason" + reason_desc: "Reason you're adding money. Leave blank for deafult." + balance: + name: "balance" + description: "Check your wallet." + + responses: + add: + success: "Added **%{amount}** coins to the wallet. Reason: **%{reason}**" + balance: + view: "You have **%{balance}** coins." \ No newline at end of file diff --git a/src/locales/es.yml b/src/locales/es.yml new file mode 100644 index 0000000..fcbfba3 --- /dev/null +++ b/src/locales/es.yml @@ -0,0 +1,19 @@ +es: + commands: + add: + name: "añadir" + description: "Añade monedas a la billetera." + args: + amount: "cantidad" + amount_desc: "La cantidad de monedas que añades." + reason: "motivo" + reason_desc: "El motivo por el cual añades monedas. Déjalo vacío para default." + balance: + name: "saldo" + description: "Revisa tu billetera." + + responses: + add: + success: "Se añadieron **%{amount}** monedas a la billetera. Motivo: **%{reason}**" + balance: + view: "Tienes **%{balance}** monedas." \ No newline at end of file diff --git a/src/utils/locales_helper.rb b/src/utils/locales_helper.rb new file mode 100644 index 0000000..309dc46 --- /dev/null +++ b/src/utils/locales_helper.rb @@ -0,0 +1,41 @@ +# FrugalityBot +# Copyright (C) 2026 Eri (csxkdv/nxkdv) nxkdv@thenight.club +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +require 'i18n' + +module LocalesHelper + def self.generate(key_path) + locales_map = {} + + discord_map = { + :en => 'en-US', + :es => 'es-ES' + } + + I18n.available_locales.each do |lang| + next if lang == :en + + text = I18n.t(key_path, locale: lang, default: nil) + + if text && text != 'nil' + discord_code = discord_map[lang] || lang.to_s + locales_map[discord_code] = text + end + end + + return locales_map + end +end \ No newline at end of file