Compare commits
No commits in common. "dev" and "stable" have entirely different histories.
30
README.md
30
README.md
|
|
@ -1,24 +1,6 @@
|
||||||
# Discord Bot Template
|
# Discord Bot Template
|
||||||
|
|
||||||
Translate command for Another Child Spring server
|
Discord Bot Template for Another Child Spring server
|
||||||
|
|
||||||
## Command Usage
|
|
||||||
|
|
||||||
### Name
|
|
||||||
|
|
||||||
translate - Translate a message into the selected language
|
|
||||||
|
|
||||||
### Syntax
|
|
||||||
|
|
||||||
translate [lang] [message]
|
|
||||||
|
|
||||||
### Description
|
|
||||||
|
|
||||||
The translate command will call the Deepl API to translate the message into the chosen lang. The lang parameter can simply be the destination language (source language is automatically detected) but if the user wants to specify the source language it can be formatted like so: `src->dst`
|
|
||||||
|
|
||||||
## Limitation
|
|
||||||
|
|
||||||
- Deepl API limit to 500.000 characters/month for the free version
|
|
||||||
|
|
||||||
## Requirement
|
## Requirement
|
||||||
|
|
||||||
|
|
@ -27,13 +9,6 @@ The translate command will call the Deepl API to translate the message into the
|
||||||
|
|
||||||
## How to install
|
## How to install
|
||||||
|
|
||||||
### DeeplAPI
|
|
||||||
|
|
||||||
1. Create an account on [Deepl API](https://www.deepl.com/pro-api)
|
|
||||||
2. Generate a token
|
|
||||||
|
|
||||||
### Project
|
|
||||||
|
|
||||||
1. Clone the repo
|
1. Clone the repo
|
||||||
2. Copy the `config.exemple.toml` and rename it `config.toml`
|
2. Copy the `config.exemple.toml` and rename it `config.toml`
|
||||||
3. Launch the docker container with `make start` or `docker-compose up -d`
|
3. Launch the docker container with `make start` or `docker-compose up -d`
|
||||||
|
|
@ -44,8 +19,7 @@ The translate command will call the Deepl API to translate the message into the
|
||||||
## Notes
|
## Notes
|
||||||
|
|
||||||
- Configuration file format is [TOML](https://toml.io/en/). It is a minimal configuration file format that's easy to read due to obvious semantics. TOML is designed to map unambiguously to a hash table. TOML should be easy to parse into data structures in a wide variety of languages. Read `src/config.ts` to see all possibilities.
|
- Configuration file format is [TOML](https://toml.io/en/). It is a minimal configuration file format that's easy to read due to obvious semantics. TOML is designed to map unambiguously to a hash table. TOML should be easy to parse into data structures in a wide variety of languages. Read `src/config.ts` to see all possibilities.
|
||||||
- Project use [Inhibitor](https://sheweny.js.org/guide/inhibitors/Inhibitor.html) from `Sheweny`. Inhibitor is a kind of middleware for command. Inhibitors allow you to limit the use of a command, an event, or an interaction.
|
|
||||||
|
|
||||||
## Contributions/License
|
## Contributions/License
|
||||||
|
|
||||||
This project has an AGPLv3 license. This project use the `Sheweny` framework with `discord.js` underlying and `BinaryMuse/toml-node` for configuration parsing. To communicate with DeeplAPI, project use the [offical javascript wrapper](https://www.npmjs.com/package/deepl-node).
|
This project has an AGPLv3 license. This project use the `Sheweny` framework with `discord.js` underlying and `BinaryMuse/toml-node` for configuration parsing.
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1 @@
|
||||||
token = "DISCORD TOKEN"
|
token = "DISCORD TOKEN"
|
||||||
|
|
||||||
[deepl]
|
|
||||||
token = "DEEPL TOKEN"
|
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "AGPL-3.0-only",
|
"license": "AGPL-3.0-only",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"deepl-node": "^1.3.1",
|
|
||||||
"discord.js": "^13.8.1",
|
"discord.js": "^13.8.1",
|
||||||
"sheweny": "^3.4.3",
|
"sheweny": "^3.4.3",
|
||||||
"toml": "^3.0.0"
|
"toml": "^3.0.0"
|
||||||
|
|
|
||||||
|
|
@ -1,67 +0,0 @@
|
||||||
import { Command } from "sheweny";
|
|
||||||
import { TextResult, Translator } from "deepl-node";
|
|
||||||
import type { ShewenyClient } from "sheweny";
|
|
||||||
import type { AutocompleteInteraction, CommandInteraction } from "discord.js";
|
|
||||||
import { Container } from "../container";
|
|
||||||
import { isTargetLanguageCode, targetLanguageCode, targetLanguageName } from "../utils/deepl";
|
|
||||||
|
|
||||||
export class TranslateCommand extends Command {
|
|
||||||
constructor(client: ShewenyClient) {
|
|
||||||
super(client, {
|
|
||||||
name: "translate",
|
|
||||||
description: "Translate a message into the selected language",
|
|
||||||
type: "SLASH_COMMAND",
|
|
||||||
options: [
|
|
||||||
{
|
|
||||||
name: "lang",
|
|
||||||
description: "Destination language",
|
|
||||||
type: "STRING",
|
|
||||||
required: true,
|
|
||||||
autocomplete: true,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "message",
|
|
||||||
description: "Message to be translated",
|
|
||||||
type: "STRING",
|
|
||||||
required: true
|
|
||||||
},
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async execute(interaction: CommandInteraction) {
|
|
||||||
const lang = interaction.options.get("lang")?.value
|
|
||||||
const message = interaction.options.get("message")?.value
|
|
||||||
|
|
||||||
if (typeof lang != "string" || typeof message != "string") {
|
|
||||||
throw new Error("plop")
|
|
||||||
}
|
|
||||||
|
|
||||||
const translator = Container.container.get<Translator>("translator")
|
|
||||||
|
|
||||||
if (!isTargetLanguageCode(lang)) {
|
|
||||||
interaction.reply({ content: "Invalid language", ephemeral: true })
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const result: TextResult = await translator.translateText(message, null, lang)
|
|
||||||
|
|
||||||
interaction.reply({ content: result.text });
|
|
||||||
}
|
|
||||||
|
|
||||||
onAutocomplete(interaction: AutocompleteInteraction) {
|
|
||||||
const userInput = interaction.options.getFocused(true).value
|
|
||||||
|
|
||||||
const choices: [string, string][] = Object.entries(
|
|
||||||
targetLanguageName.reduce((obj, key, index) => ({ ...obj, [key]: targetLanguageCode[index] }), {})
|
|
||||||
)
|
|
||||||
|
|
||||||
const filtered = choices
|
|
||||||
.filter(([key, _]) => key.startsWith(userInput))
|
|
||||||
.sort()
|
|
||||||
.slice(0, 25)
|
|
||||||
.map(([name, code]) => ({ name: name, value: code }))
|
|
||||||
|
|
||||||
interaction.respond(filtered)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,8 +1,3 @@
|
||||||
export interface Config {
|
export interface Config {
|
||||||
token: string
|
token: string
|
||||||
deepl: DeeplSection
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DeeplSection {
|
|
||||||
token: string,
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
10
src/index.ts
10
src/index.ts
|
|
@ -1,5 +1,4 @@
|
||||||
import { ShewenyClient } from "sheweny";
|
import { ShewenyClient } from "sheweny";
|
||||||
import {Translator} from "deepl-node";
|
|
||||||
import {Container} from "./container";
|
import {Container} from "./container";
|
||||||
import {Config} from "./config";
|
import {Config} from "./config";
|
||||||
import * as TOML from "toml";
|
import * as TOML from "toml";
|
||||||
|
|
@ -8,21 +7,12 @@ import * as fs from "fs";
|
||||||
const configurationFile = fs.readFileSync("./config.toml").toString()
|
const configurationFile = fs.readFileSync("./config.toml").toString()
|
||||||
const configuration = TOML.parse(configurationFile) as Config
|
const configuration = TOML.parse(configurationFile) as Config
|
||||||
|
|
||||||
const translator = new Translator(configuration.deepl.token)
|
|
||||||
|
|
||||||
const container = new Container()
|
const container = new Container()
|
||||||
container.set("config", configuration)
|
container.set("config", configuration)
|
||||||
container.set("translator", translator)
|
|
||||||
Container.container = container
|
Container.container = container
|
||||||
|
|
||||||
const client = new ShewenyClient({
|
const client = new ShewenyClient({
|
||||||
intents: ["GUILDS", "GUILD_MEMBERS", "GUILD_MESSAGES"],
|
intents: ["GUILDS", "GUILD_MEMBERS", "GUILD_MESSAGES"],
|
||||||
managers: {
|
|
||||||
commands: {
|
|
||||||
directory: "commands/",
|
|
||||||
loadAll: true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
client.login(configuration.token)
|
client.login(configuration.token)
|
||||||
|
|
|
||||||
|
|
@ -1,19 +0,0 @@
|
||||||
import {SourceLanguageCode, TargetLanguageCode} from "deepl-node";
|
|
||||||
|
|
||||||
export const commonLanguageCode = ["bg", "cs", "da", "de", "el", "es", "et", "fi", "fr", "hu", "id", "it", "ja", "lt", "lv", "nl", "pl", "ro", "ru", "sk", "sl", "sv", "tr", "zh"]
|
|
||||||
export const commomLanguageName = ["Bulgarian", "Czech", "Danish", "German", "Greek", "Spanish", "Estonian", "Finnish", "French", "Hungarian", "Indonesian", "Italian", "Japanese",
|
|
||||||
"Lithuanian", "Latvian", "Dutch", "Polish", "Romanian", "Russian", "Slovak", "Slovenian", "Swedish", "Turkish", "Chinese"]
|
|
||||||
|
|
||||||
export const sourceLanguageCode = [...commonLanguageCode, "en", "pt"]
|
|
||||||
export const sourceLanguageName = [...commomLanguageName, "English", "Portugese"]
|
|
||||||
|
|
||||||
export const targetLanguageCode = [...commonLanguageCode, "en-GB", 'en-US', 'pt-BR', 'pt-PT']
|
|
||||||
export const targetLanguageName = [...commomLanguageName, "English (UK)", "English (US)", "Portuguese (Brazil)", "Portuguese (Portugal)"]
|
|
||||||
|
|
||||||
export function isSourceLanguageCode(code: string): code is SourceLanguageCode {
|
|
||||||
return sourceLanguageCode.includes(code)
|
|
||||||
}
|
|
||||||
|
|
||||||
export function isTargetLanguageCode(code: string): code is TargetLanguageCode {
|
|
||||||
return targetLanguageCode.includes(code)
|
|
||||||
}
|
|
||||||
30
yarn.lock
30
yarn.lock
|
|
@ -47,7 +47,7 @@
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
form-data "^3.0.0"
|
form-data "^3.0.0"
|
||||||
|
|
||||||
"@types/node@*", "@types/node@>=12.0":
|
"@types/node@*":
|
||||||
version "18.0.1"
|
version "18.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.1.tgz#e91bd73239b338557a84d1f67f7b9e0f25643870"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.1.tgz#e91bd73239b338557a84d1f67f7b9e0f25643870"
|
||||||
integrity sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==
|
integrity sha512-CmR8+Tsy95hhwtZBKJBs0/FFq4XX7sDZHlGGf+0q+BRZfMbOTkzkj0AFAuTyXbObDIoanaBBW0+KEW+m3N16Wg==
|
||||||
|
|
@ -87,14 +87,6 @@ asynckit@^0.4.0:
|
||||||
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
|
||||||
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
|
||||||
|
|
||||||
axios@>=0.21.2:
|
|
||||||
version "0.27.2"
|
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
|
|
||||||
integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
|
|
||||||
dependencies:
|
|
||||||
follow-redirects "^1.14.9"
|
|
||||||
form-data "^4.0.0"
|
|
||||||
|
|
||||||
balanced-match@^1.0.0:
|
balanced-match@^1.0.0:
|
||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
|
||||||
|
|
@ -157,16 +149,6 @@ create-require@^1.1.0:
|
||||||
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
|
||||||
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
|
||||||
|
|
||||||
deepl-node@^1.3.1:
|
|
||||||
version "1.3.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/deepl-node/-/deepl-node-1.3.1.tgz#1cc05affdc3af12fb393e295c5333cdcc2b10c22"
|
|
||||||
integrity sha512-Q41JzD/nxDhDZcJ5RqQfQY8hphX/ZadO/khH4H0WsAGdEwwpZ9By+dqD2si338Qajj7a9ePYYVGmCl9nIxx+wA==
|
|
||||||
dependencies:
|
|
||||||
"@types/node" ">=12.0"
|
|
||||||
axios ">=0.21.2"
|
|
||||||
form-data "^3.0.0"
|
|
||||||
loglevel ">=1.6.2"
|
|
||||||
|
|
||||||
delayed-stream@~1.0.0:
|
delayed-stream@~1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
|
||||||
|
|
@ -216,11 +198,6 @@ fill-range@^7.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
to-regex-range "^5.0.1"
|
to-regex-range "^5.0.1"
|
||||||
|
|
||||||
follow-redirects@^1.14.9:
|
|
||||||
version "1.15.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
|
|
||||||
integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
|
|
||||||
|
|
||||||
form-data@^3.0.0:
|
form-data@^3.0.0:
|
||||||
version "3.0.1"
|
version "3.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.1.tgz#ebd53791b78356a99af9a300d4282c4d5eb9755f"
|
||||||
|
|
@ -324,11 +301,6 @@ is-number@^7.0.0:
|
||||||
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
|
||||||
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
|
||||||
|
|
||||||
loglevel@>=1.6.2:
|
|
||||||
version "1.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.0.tgz#e7ec73a57e1e7b419cb6c6ac06bf050b67356114"
|
|
||||||
integrity sha512-G6A/nJLRgWOuuwdNuA6koovfEV1YpqqAG4pRUlFaz3jj2QNZ8M4vBqnVA+HBTmU/AMNUtlOsMmSpF6NyOjztbA==
|
|
||||||
|
|
||||||
make-error@^1.1.1:
|
make-error@^1.1.1:
|
||||||
version "1.3.6"
|
version "1.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue