diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml
index 52e083d..3020579 100644
--- a/.github/workflows/deploy.yml
+++ b/.github/workflows/deploy.yml
@@ -17,6 +17,6 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./docs/src/.vuepress/dist
commit_message: ${{ github.event.head_commit.message }}
- cname: harmony.mod.land
+ cname: harmony-korean.mod.land
keep_files: true
enable_jekyll: false
diff --git a/CNAME b/CNAME
index 9a40703..dda44bc 100644
--- a/CNAME
+++ b/CNAME
@@ -1 +1 @@
-harmony.mod.land
+harmony-korean.mod.land
diff --git a/package.json b/package.json
index 9874812..f4052c4 100644
--- a/package.json
+++ b/package.json
@@ -4,8 +4,7 @@
"description": "An easy to use, advanced Discord API library, for Deno.",
"main": "index.js",
"authors": {
- "name": "DjDeveloperr",
- "email": "djdeveloperr@gmail.com"
+ "name": "Harmony org"
},
"repository": "guide/harmony-guide",
"scripts": {
@@ -14,11 +13,10 @@
},
"license": "MIT",
"devDependencies": {
- "vuepress": "^1.5.3",
- "vuepress-theme-yuu": "^2.3.0"
+ "vuepress": "^1.5.3"
},
"dependencies": {
- "vuepress-theme-default-prefers-color-scheme": "^2.0.0",
- "vuepress-theme-yuu": "^2.3.0"
+ "vuepress-theme-yuu": "^2.3.0",
+ "vuepress-theme-default-prefers-color-scheme": "^2.0.0"
}
}
diff --git a/src/.vuepress/config.js b/src/.vuepress/config.js
index 7f23587..e37b550 100644
--- a/src/.vuepress/config.js
+++ b/src/.vuepress/config.js
@@ -1,14 +1,24 @@
const { description } = require('../../package')
module.exports = {
- /**
- * Ref:https://v1.vuepress.vuejs.org/config/#title
- */
- title: 'Harmony',
- /**
- * Ref:https://v1.vuepress.vuejs.org/config/#description
- */
- description: description,
+ locales: {
+ '/': {
+ lang: 'en-US',
+ /**
+ * Ref:https://v1.vuepress.vuejs.org/config/#title
+ */
+ title: 'Harmony',
+ /**
+ * Ref:https://v1.vuepress.vuejs.org/config/#description
+ */
+ description: description,
+ },
+ '/ko/': {
+ lang: 'ko-KR',
+ title: 'Harmony',
+ description: 'Deno를 위한, 사용하기 쉬우면서, 매우 고급지고, 조화로운 Discord API 라이브러리입니다.'
+ }
+ },
/**
* Extra tags to be injected to the page HTML `
`
@@ -27,52 +37,111 @@ module.exports = {
* ref:https://v1.vuepress.vuejs.org/theme/default-theme-config.html
*/
themeConfig: {
- repo: 'https://github.com/harmonyland/harmonyland.github.io',
- editLinks: true,
- docsDir: 'src',
- docsBranch: 'main',
- editLinkText: 'Edit this page',
- lastUpdated: true,
- nav: [
- {
- text: 'Guide',
- link: '/guide/',
- },
- {
- text: 'Documentation',
- link: 'https://doc.deno.land/https/deno.land/x/harmony/mod.ts',
+ locales: {
+ '/': {
+ selectText: 'Languages',
+ label: 'English',
+ ariaLabel: 'Languages',
+ algolia: {},
+ repo: 'https://github.com/harmonyland/harmonyland.github.io',
+ editLinks: true,
+ docsDir: 'src',
+ docsBranch: 'main',
+ editLinkText: 'Edit this page',
+ lastUpdated: true,
+ nav: [
+ {
+ text: 'Guide',
+ link: '/guide/',
+ },
+ {
+ text: 'Documentation',
+ link: 'https://doc.deno.land/https/deno.land/x/harmony/mod.ts',
+ },
+ {
+ text: 'Discord',
+ link: 'https://discord.gg/harmony'
+ }
+ ],
+ sidebar: {
+ '/guide/': [
+ {
+ title: 'Home',
+ collapsable: false,
+ children: [
+ '',
+ 'setup'
+ ]
+ },
+ {
+ title: 'Beginner',
+ collapsable: false,
+ children: [
+ 'beginner/basic_bot',
+ ]
+ },
+ {
+ title: 'Slash Commands',
+ collapsable: false,
+ children: [
+ 'slash_commands/tag_bot'
+ ]
+ }
+ ],
+ }
},
- {
- text: 'Discord',
- link: 'https://discord.gg/WVN2JF2FRv'
- }
- ],
- sidebar: {
- '/guide/': [
- {
- title: 'Home',
- collapsable: false,
- children: [
- '',
- 'setup'
- ]
- },
- {
- title: 'Beginner',
- collapsable: false,
- children: [
- 'beginner/basic_bot',
- ]
- },
- {
- title: 'Slash Commands',
- collapsable: false,
- children: [
- 'slash_commands/tag_bot'
- ]
+ '/ko/': {
+ selectText: '언어',
+ label: '한국어',
+ algolia: {},
+ repo: 'https://github.com/harmonyland/harmonyland.github.io',
+ editLinks: true,
+ docsDir: 'src/ko',
+ docsBranch: 'main',
+ editLinkText: '이 페이지를 편집하기',
+ lastUpdated: true,
+ nav: [
+ {
+ text: '가이드',
+ link: '/ko/guide/',
+ },
+ {
+ text: '문서',
+ link: 'https://doc.deno.land/https/deno.land/x/harmony/mod.ts',
+ },
+ {
+ text: '디스코드',
+ link: 'https://discord.gg/harmony'
+ }
+ ],
+ sidebar: {
+ '/ko/guide/': [
+ {
+ title: '홈',
+ collapsable: false,
+ children: [
+ '',
+ 'setup'
+ ]
+ },
+ {
+ title: '초보자',
+ collapsable: false,
+ children: [
+ 'beginner/basic_bot',
+ ]
+ },
+ {
+ title: '슬래시 커맨드',
+ collapsable: false,
+ children: [
+ 'slash_commands/tag_bot'
+ ]
+ }
+ ],
}
- ],
- }
+ }
+ },
},
theme: 'yuu',
diff --git a/src/ko/guide/README.md b/src/ko/guide/README.md
new file mode 100644
index 0000000..da41402
--- /dev/null
+++ b/src/ko/guide/README.md
@@ -0,0 +1,33 @@
+# 소개
+
+
+
+If you're reading this, you probably want to create Discord bots! Who doesn't agree these bots can do cool stuff, but hey - how exactly do we go about making these? It's simple, or maybe not! Depends on how you take it. Many people start programming with Discord bots - and me too, honestly. First off, if you already know a language which is not JavaScript/TypeScript, you should consider using the library for that language, yes for real. It would be easier for you to get started, else, this guide is absolutely for you!
+
+Here's a list of [libraries for Discord API](https://discord.com/developers/docs/topics/community-resources#libraries-discord-libraries). If you couldn't find one for you, let's continue! JavaScript (or TypeScript) aren't hard to learn.
+
+What exactly is Harmony? It's an easy to use, and advanced Discord API Library, for Deno. It's designed to be easy to use, as well as to offer everything an advanced developer may need. If you don't know about [Deno](https://deno.land) yet, in a nutshell, it's a secure JavaScript/TypeScript runtime made in Rust. *You can call it new, or better Node.*
+
+In this guide, you'll learn about various concepts, but here's an overview
+- How to get a bot up and running from scratch
+- How to keep your code organized
+- Learn about best practices
+- More advanced concepts
+- ... and much more.
+
+## 시작하기 전에...
+
+It's possible that you want to get started with bot development, but don't know any programming language. However, we recommend you to learn basics else you'll be tackling with problems with are actually so small! It doesn't take much time, here are some good resources to get started with JavaScript...
+
+- [모던 JavaScript ](https://javascript.info/)
+- [MDN's JavaScript guide and Documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript)
+- [CodeCademy JavaScript course](https://www.codecademy.com/learn/learn-javascript)
+- And honestly, [Stack Overflow](https://stackoverflow.com) will be solving many problems for you
+
+However, it's worth considering that Harmony is made using [TypeScript](https://www.typescriptlang.org/), which is a subset of JavaScript, but strongly-typed, and we are also using **TypeScript** throughout the guide for code examples. It helps you write more concise, less error prone code, and also adds on some new features! At the end, it compiles (transpiles!) to normal JavaScript. We recommend using TypeScript for its great features and Deno's built-in TypeScript! Here are some resources,
+
+- [TypeScript's Docs for Beginners](https://www.typescriptlang.org/docs/handbook/typescript-from-scratch.html)
+- [TypeScript's Docs for JS Programmers](https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html)
+- [Educative's TypeScript tutorial](https://www.educative.io/blog/typescript-tutorial)
+
+If you have never used [Deno](https://deno.land) before, you might want to consider reading [Deno Manual](https://deno.land/manual) and a gentle introduction to the runtime and it's features.
diff --git a/src/ko/guide/beginner/basic_bot.md b/src/ko/guide/beginner/basic_bot.md
new file mode 100644
index 0000000..0e02c99
--- /dev/null
+++ b/src/ko/guide/beginner/basic_bot.md
@@ -0,0 +1,169 @@
+# 기본적인 봇 만들기
+
+## 애플리케이션 만들기
+
+First, you need to create a bot in Discord's Developer Applications page. Head to [Applications Page](https://discord.com/developers/applications) and hit `New Application` button. A modal will appear asking you for name, enter the bot name you want and hit `Create`!
+
+
+
+Navigate to `Bot` tab on left-pane, then click on `Add Bot`. It will ask you for confirmation, just click on `Yes, do it!`
+
+
+
+Aaand your bot now has a life! Yes, a life! It has successfully become a Discord User.
+Now you can go ahead and invite the bot to your server. Now navigate to `OAuth2` tab and scroll down a bit; then select `bot` scope. And optionally, below there you can select permissions to give to bot!
+
+
+
+Copy the link from there and paste in a new tab, select server and `Authorize`! Bot will be in your own server!
+
+Uh oh- bot is offline!? Don't worry! We'll wake up this bot!
+
+## 봇의 토큰 얻기
+
+What's a token? It acts like a **password** for bots to *login*! Never share this to anyone! **Anyone**!
+
+On the `Bot` page itself, there is a `Copy Token` button - go ahead and click on it! Token will be on your clipboard. Alternatively, you can `Click to Reveal Token`.
+
+
+
+::: warning
+Token should **NEVER** be shared with **ANYONE**! Token gives **complete**, yes complete access over bot and can destroy it *badly*.
+:::
+
+::: tip
+In case you really lost it, best way is to reset it using `Regenerate` button on the same page, this will invalidate any previous token.
+:::
+
+## 코드 작성하기
+
+Let's *actually* start writing code! If you still haven't done your setup, it's easy! Just head to [Setup](../setup.md) section.
+
+Assuming you have a `deps.ts` file in your project directory, go ahead and make a `mod.ts` file (`bot.ts` or any other name would work too!)
+
+```ts
+// Importing Client and Intents class from Harmony
+import { Client, Intents } from './deps.ts'
+
+// Creating client (or bot!)
+const client = new Client()
+
+// Listen for when bot is connected to Discord (i.e. logged in)
+client.on('ready', () => {
+ console.log('Ready!')
+})
+
+// Proceed with connecting to Discord (login)
+client.connect('super secret token comes here', Intents.None)
+```
+
+Pretty simple! Try running `deno run --allow-net mod.ts` (replace mod.ts with your file name if not same). Aaaand you'll see your bot online! That's pretty cool - but uh bot does nothing! Let's add a simple ping-pong command.
+
+It's worth noticing that we're putting `client.connect` at end because we're adding listeners to our client, to make sure bot doesn't login before listening to events. Weird case though!
+
+::: tip
+Haven't code deps.ts till now? here's the code (again)
+```ts
+export * from 'https://deno.land/x/harmony@v0.9.3/mod.ts'
+```
+:::
+
+## 핑-퐁!
+
+Let's proceed with adding a simple command, ping! For that, your bot will listen to a event called `messageCreate` - which is fired whenever a message is created (i.e. sent).
+
+```ts
+// Importing required classes from Harmony
+import { Client, Intents, Message } from './deps.ts'
+
+// ... rest of the code
+
+// Listen for an event which is fired when a Message is sent
+client.on('messageCreate', (message: Message) => {
+ // All the message data is inside `Message` here.
+ // For now, we just need the text of the Message, that is called `content`.
+ // Content of Message can be accessed using `.content`; here message.content
+ // Let's compare that to a string "!ping", and reply back with "Pong!"
+ if (message.content == '!ping') {
+ message.reply('Pong!')
+ }
+})
+
+client.connect('super secret token comes here', Intents.None)
+```
+
+Yes! That's it! We got our own ping command. Now try running the bot and send `!ping`!
+
+Got stuck? This is our resulting code,
+
+```ts
+import { Client, Intents } from './deps.ts'
+
+const client = new Client()
+
+client.on('ready', () => {
+ console.log('Ready!')
+})
+
+client.on('messageCreate', (message: Message) => {
+ if (message.content == '!ping') {
+ message.reply('Pong!')
+ }
+})
+
+// Proceed with connecting to Discord (login)
+client.connect('super secret token comes here', Intents.None)
+```
+
+## 커맨드 클라이언트 사용하기
+
+But that's quite not how Commands actually work! With Harmony, you can create a Client with additional features - such as Commands and Extensions! It's the `CommandClient`! A built-in framework to make commands very easily.
+
+Let's look into making same command - but with Command Client!
+
+```ts
+import { CommandClient, Command, Intents, CommandContext } from './deps.ts'
+
+// Initialize our Command Client with prefix "!".
+// Fact, you can put multiple prefixes here using array!
+// Example: prefix: [ '!', '.' ]
+const client = new CommandClient({
+ prefix: '!'
+})
+
+client.on('ready', () => {
+ console.log('Ready!')
+})
+
+// Make a class extending Command (inheriting everything from Command)
+class PingCommand extends Command {
+ name = 'ping'
+ execute(ctx: CommandContext) {
+ ctx.message.reply('Pong!')
+ }
+}
+
+// Register the Command
+client.commands.add(PingCommand)
+
+// Connect the client to Discord
+client.connect('token comes here', Intents.None)
+```
+
+This looks cleaner! Moreover, there are many more options to customize commands, such as limiting command to certain users, channels, guilds, or making Command guild only or DM only! A lot more!
+
+Not familiar with classes or just don't like them? Don't worry! You can import `CommandBuilder` from `./deps.ts` and use it like this:
+
+```ts
+const myCommand = new CommandBuilder()
+ .setName("ping")
+ .onExecute((ctx: CommandContext) => {
+ ctx.message.reply('Pong!')
+ })
+```
+
+Command Builder can do everything same as class based commands.
+
+::: tip
+Read more about classes [here](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) and more specifically for TypeScript [here](https://www.typescriptlang.org/docs/handbook/classes.html).
+:::
diff --git a/src/ko/guide/setup.md b/src/ko/guide/setup.md
new file mode 100644
index 0000000..89d3e94
--- /dev/null
+++ b/src/ko/guide/setup.md
@@ -0,0 +1,34 @@
+# 프로젝트 설정하기
+
+## Deno 설치하기
+
+Haven't installed Deno yet? Head to the [website](https://deno.land), its just about running a single command!
+
+Well, there isn't anything else you'll need except Deno. But it's good to have an IDE, or just Editor, and in this case, [VS Code](https://code.visualstudio.com/) serves very well. Though JetBrains IDE support Deno with a Plugin too.
+
+## VS Code 설정하기
+
+If you are using VS Code (recommended), go ahead and install "VSCode Deno" extension for complete Deno support.
+Open VS Code in your project directory, and add a new directory `.vscode` with a file `settings.json` in it.
+Write the following contents into the file,
+
+```json
+{
+ "deno.enable": true
+}
+```
+
+And boom! Deno enabled in your directory! If you are having issues, try reloading VS Code.
+
+If you come from a [Node.js](https://nodejs.org) background, you're probably used to `index.js` or `main.js` file names, but here in Deno, the convention of `mod.ts` (ts here is for TypeScript, you may use `.js`) is used.
+And since there's no `package.json` in Deno, you might find it better to have a `deps.ts` file to export your third party modules! Here's an example how to export Harmony from there,
+
+```ts
+export * from 'https://deno.land/x/harmony/mod.ts'
+```
+
+and you can just import Harmony lib exports from local `deps.ts`! It's a good way to maintain the third party modules you're using.
+
+Now you're good to go! Let's start writing a simple bot in the next section.
+
+Note that the import above has no version and a warning will be thrown the first time you import it. You can add a version such as `https://deno.land/x/harmony@v0.9.3/mod.ts`.
diff --git a/src/ko/guide/slash_commands/tag_bot.md b/src/ko/guide/slash_commands/tag_bot.md
new file mode 100644
index 0000000..22af8ed
--- /dev/null
+++ b/src/ko/guide/slash_commands/tag_bot.md
@@ -0,0 +1,534 @@
+# 태그 봇
+
+## 소개
+
+Let's make some cool Slash Commands! What exactly are Slash Commands? These are just commands - but visible on Discord Client when you start typing `/` and also provide auto-completion and many other features!
+
+## 시작하기
+
+Ahead from here, I assume that you already have made an Application and Bot User. If not, follow [this part](../beginner/basic_bot).
+
+::: tip
+Slash Commands actually don't require making a bot user! But with a bot user you get a lot more functionality than just commands. For the sake of simplicity, we're using bot user way, that uses Gateway for receiving interactions.
+:::
+
+Now go to OAuth2 page, and select `bot` and `applications.commands` scopes, then copy invite.
+
+If you are confused with this, here's a template link: `https://discord.com/api/oauth2/authorize?client_id=YOUR_APPLICATION_ID&permissions=0&scope=bot%20applications.commands` and make sure to replace `YOUR_APPLICATION_ID` with yours!
+
+Aaaand then just open the link and add the bot (and Slash Commands Integration) to your server!
+
+## 기본적인 구조
+
+In this guide, we'll use SQLite database using [this](https://deno.land/x/sqlite@v2.3.2) Deno module. Our project will be in two parts - database and bot. Database module will handle tags database, like get a tag, get user's tags, get all tags, delete tag, add tag, etc., and bot module will handle incoming slash commands!
+
+Our `deps.ts` will have these two modules:
+```ts
+export { DB } from "https://deno.land/x/sqlite/mod.ts"
+export * from "https://deno.land/x/harmony/mod.ts"
+```
+
+Let's create two more files - `bot.ts` and `db.ts`! I already mentioned what these two different modules are going to do above.
+
+## 봇 모듈
+
+We'll start off with the bot module. What do we need now? A basic bot structure! For Slash Commands here, we'll use a class-based Client to use decorators, which is an experimental feature, but it really makes things easy and clean!
+
+```ts
+// bot.ts
+import {
+ Client,
+ slash,
+ event,
+ SlashCommandPartial,
+ Interaction,
+ InteractionResponseType,
+ SlashCommandOptionType
+} from "./deps.ts"
+
+class TagBot extends Client {
+
+}
+
+const bot = new TagBot();
+bot.connect('token comes here', Intents.None);
+```
+
+Don't get confused with the imports! I'll explain what are these.
+
+- Client you already know.
+- SlashCommandPartial is an interface which is basically a "map" or "structure" of our Command objects.
+- Interaction is a class of which object is passed to our Slash Commands. We use this to respond to Slash Commands!
+- InteractionResponseType is an enum, i.e. enumerated value. It specifies which type of response we are sending. Below is the list.
+ - `PONG`, it means nothing here, ignore it.
+ - `ACKNOWLEDGE` means bot has recognized the command and silently execute i.e. with no result.
+ - `CHANNEL_MESSAGE means` bot will just Message in response to the Slash Command.
+ - `CHANNEL_MESSAGE_WITH_SOURCE` means bot will do above thing AND a message showing ` used / with `.
+ - `ACK_WITH_SOURCE` means bot will not respond and silently execute, but send the above mentioned "User used Command" message.
+ - ... and you can access these in `InteractionResponseType` such as `InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE`.
+- SlashCommandOptionType is also an enumerated value. It allows us to specify what type of option we need! There are types like String, Number, User, Role, etc. which are already parsed for us when someone uses Slash Commands.
+- `event` is a decorator. It adds on an easy way to listen for events.
+- `slash` is a decorator too. It will add a Slash Command handler.
+
+Let's add a `ready` event. For that, we'll use `event` decorator here.
+
+```ts
+class TagBot extends Client {
+ @event()
+ ready() {
+ console.log("Ready!")
+ }
+}
+```
+
+Now try running `bot.ts` using `deno run --allow-net bot.ts` and there will be a log in console showing up when bot is connected to Discord!
+
+Let's proceed with adding Commands. How are we going to add them? At the moment Discord only provided us with API-way to create/modify Slash Commands. But don't worry! Harmony makes it all easy by providing simple way to create commands through code.
+
+A Slash Command has three properties:
+- `name`: Simply the name of the Slash Command.
+- `description`: Something about the Slash Command.
+- `options`: Options the Slash Command accepts - can be an empty Array, `[]`, too.
+ - This property contains Array (List) of Option objects, which in turn have a structure too.
+ - `name`: Name of the option
+ - `description`: Description of the option
+ - `required`: Whether the option is required or not
+ - `type`: Type of the option. Here somes the `SlashCommandOptionType` enum into use.
+ - `options`: (Optional) for nested sub-commands or sub command groups
+
+For example, we want a command named `tag`, which will send a tag's contents. It will accept an option `name` which is name of the Tag to send. Structure for it would look like this,
+
+```ts
+{
+ name: "tag",
+ description: "Send a tag's contents.",
+ options: [
+ {
+ name: 'name',
+ description: 'Name of the tag.',
+ required: true,
+ type: SlashCommandOptionType.STRING
+ }
+ ]
+}
+```
+
+That's it! We made our first Slash Command object. We need some more commands to complete this bot! All commands we need are: `tag`, `addtag`, `deletetag`, `updatetag`, `mytags`, and `alltags`.
+
+Here are the rest of Slash Command objects. I've kept them in an Array so we can sync them! Since this is pretty large data, let's keep it in a different file - `commands.ts`! Here's how it looks like:
+
+```ts
+// Now you can remove these two imports in bot.ts!
+import { SlashCommandPartial, SlashCommandOptionType } from "./dep.ts"
+
+export const commands: SlashCommandPartial[] = [
+ {
+ name: "mytags",
+ description: "See a list of tags made by you!",
+ options: [],
+ },
+ {
+ name: "alltags",
+ description: "See a list of tags in this server!",
+ options: [],
+ },
+ {
+ name: "addtag",
+ description: "Create a new tag in this server!",
+ options: [
+ {
+ name: "name",
+ description: "Name of the tag.",
+ required: true,
+ type: SlashCommandOptionType.STRING,
+ },
+ {
+ name: "content",
+ description: "New content of the tag.",
+ required: true,
+ type: SlashCommandOptionType.STRING,
+ },
+ ],
+ },
+ {
+ name: "updatetag",
+ description: "Update your tag's response.",
+ options: [
+ {
+ name: "name",
+ description: "Name of the tag.",
+ required: true,
+ type: SlashCommandOptionType.STRING,
+ },
+ {
+ name: "content",
+ description: "New content of the tag.",
+ required: true,
+ type: SlashCommandOptionType.STRING,
+ },
+ ],
+ },
+ {
+ name: "deletetag",
+ description: "Delete a tag of yours.",
+ options: [
+ {
+ name: "name",
+ description: "Name of the tag.",
+ required: true,
+ type: SlashCommandOptionType.STRING,
+ },
+ ],
+ },
+ {
+ name: "tag",
+ description: "Send a tag's contents.",
+ options: [
+ {
+ name: "name",
+ description: "Name of the tag.",
+ required: true,
+ type: SlashCommandOptionType.STRING,
+ },
+ ],
+ },
+];
+```
+
+Note the `export` keyword - I'm exporting it so it can be used in `bot.ts`!
+Coming back to `bot.ts`, let's import commands there. Add this line somewhere on top.
+
+```ts
+import { commands } from "./commands.ts"
+```
+
+And boom! We got our commands. Let's now actually "create" them. For that, we use `.slash.commands.create()`. But since here we are using class-based Client, `` can be replaced with `this` inside the `ready` event.
+
+Let's add code in ready event to create out Slash Commands.
+
+```ts
+class TagBot extends Client {
+ @event()
+ ready() {
+ console.log("Ready!")
+ commands.forEach(command => {
+ // If you want to create command globally, just remove 'Your Server/Guild ID' part
+ // I recommend making it for only one guild for now because Global Slash Commands can take max 1 hour to come live.
+ this.slash.commands.create(command, 'Your Server/Guild ID')
+ .then((cmd) => console.log(`Created Slash Command ${cmd.name}!`))
+ .catch(() => console.log(`Failed to create ${command.name} command!`));
+ })
+ }
+}
+```
+
+Now run your bot, you should see logs coming up about creation of commands. If something fails, recheck your code!
+After creating, you can now remove this code. Try out typing `/` in your server, bot's commands will show up in the menu, something like this:
+
+
+
+If you try using commands now, nothing will happen. Because we are not handling them yet!
+
+Let's add code to handle `mytags` command. We'll use `slash` decorator we imported earlier.
+
+```ts
+class TagBot extends Client {
+ // ...
+
+ @slash()
+ mytags(i: Interaction) {
+
+ }
+}
+```
+
+We just added a new function `mytags` and "decorated" it with `slash` decorator to make it a Slash Command Handler.
+If you want to name function something else, you can do something like this:
+
+```ts
+@slash('mytags')
+mytagsCommand(i: Interaction) { }
+```
+
+Okay, now let's make it respond to our command with `You have no tags.`
+
+```ts
+class TagBot extends Client {
+ // ...
+
+ @slash()
+ mytags(i: Interaction) {
+ i.respond({
+ content: 'You have no tags.'
+ })
+ }
+}
+```
+
+Now restart your bot, and try typing `/mytags` and press Enter when it appears.
+You'll see bot saying "You have no tags." That's it! We made our very own first Slash Command!
+
+Let's add handlers for all the Slash Commands, but empty for now.
+
+```ts
+class TagBot extends Client {
+ // ...
+
+ @slash()
+ mytags(i: Interaction) { }
+
+ @slash()
+ alltags(i: Interaction) { }
+
+ @slash()
+ addtag(i: Interaction) { }
+
+ @slash()
+ updatetag(i: Interaction) { }
+
+ @slash()
+ deletetag(i: Interaction) { }
+
+ @slash()
+ tag(i: Interaction) { }
+}
+```
+
+Now we'll move on to our database module so that we have something to get/add/delete/update tags!
+
+## 데이터베이스 모듈
+
+We won't go in much depth here. We need following methods for our commands: `getUserTags`, `getGuildTags`, `getTag`, `addTag`, `editTag`.
+
+Let's initialize our database,
+
+```ts
+// db.ts
+import { DB } from "./deps.ts"
+
+export const db = new DB("./tags.sqlite");
+```
+
+Add the following code to the file,
+
+```ts
+export function init() {
+ db.query(`CREATE TABLE IF NOT EXISTS tags(id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, guild TEXT, name TEXT, uname TEXT, content TEXT, created TEXT)`)
+}
+
+init();
+
+export function getUserTags(guild: string, user: string) {
+ return [...db.query(`SELECT * FROM tags WHERE user = ? AND guild = ?`, [user, guild]).asObjects()]
+}
+
+export function getGuildTags(guild: string) {
+ return [...db.query(`SELECT * FROM tags WHERE guild = ?`, [guild]).asObjects()]
+}
+
+export function getTag(guild: string, name: string) {
+ return [...db.query(`SELECT * FROM tags WHERE guild = ? AND uname = ?`, [guild, name.toLowerCase()]).asObjects()][0]
+}
+
+export function deleteTag(guild: string, name: string): boolean {
+ if (!getTag(guild, name)) return false
+ db.query(`DELETE FROM tags WHERE guild = ? AND uname = ?`, [guild, name.toLowerCase()])
+ return true
+}
+
+export function editTag(guild: string, name: string, update: string) {
+ if (!getTag(guild, name)) return false
+ db.query(`UPDATE tags SET content = ? WHERE guild = ? AND uname = ?`, [update, guild, name.toLowerCase()])
+ return getTag(guild, name)
+}
+
+export function addTag(guild: string, user: string, name: string, content: string) {
+ if (getTag(guild, name)) return null
+ db.query(`INSERT INTO tags (user, guild, uname, name, content, created) VALUES (?, ?, ?, ?, ?, ?)`, [user, guild, name.toLowerCase(), name, content, new Date().getTime()])
+ return getTag(guild, name)
+}
+```
+
+Since this guide is focussed on usage of Harmony, we aren't going in depth of these queries/methods.
+
+### Bot Module - 2
+
+Let's import these in our `bot.ts`
+
+```ts
+// ...
+import { getUserTags, getGuildTags, getTag, addTag, editTag, deleteTag } from "./db.ts"
+// ...
+```
+
+Let's start adding code to our Slash Command handlers.
+
+- `tag`
+```ts
+// Get the tag name from command arguments (options)
+const name = i.options.find((e) => e.name == "name")?.value as string;
+// Get the tag from database
+const tag = getTag(i.guild.id, name);
+
+// Respond if tag not found.
+if (!tag)
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Tag with name \`${name.replace(
+ /`/g,
+ "`"
+ )}\` could not be found.`,
+ // Note this temp option. This makes message visible only to User who used command and also can be dismissed!
+ temp: true,
+ });
+// Else respond with tag's content.
+else
+ i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE_WITH_SOURCE,
+ content: tag.content
+ });
+```
+- `mytags`
+```ts
+// Get all tags of the User
+const tags = getUserTags(i.guild.id, i.user.id);
+
+if (tags.length == 0)
+ return i.respond({
+ content: `You have no tags in this server yet.`,
+ temp: true,
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ });
+else {
+ i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ temp: true,
+ content: `**Your Tags:** ${tags.map((e) => e.name).join(", ")}`,
+ });
+}
+```
+- `alltags`
+```ts
+// Get all Tags in current Server/Guild
+const tags = getGuildTags(i.guild.id);
+
+if (tags.length == 0)
+ return i.respond({
+ content: `This server has no tags yet.`,
+ temp: true,
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ });
+else {
+ i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ temp: true,
+ content: `**All Tags:** ${tags.map((e) => e.name).join(", ")}`,
+ });
+}
+```
+- `addtag`
+```ts
+const tags = getUserTags(i.guild.id, i.user.id);
+
+// Let's keep max number of tags of a user 10
+if (tags.length >= 10)
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `You have reached maximum number of tags!`,
+ temp: true,
+ });
+
+const name = i.options.find((e) => e.name == "name")?.value as string;
+const content = i.options.find((e) => e.name == "content")?.value as string;
+
+if (content.length > 2000)
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Tag content length must be between 1-2000 characters.`,
+ temp: true,
+ });
+
+const added = addTag(i.guild.id, i.user.id, name, content);
+
+if (added == null) {
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Tag with name \`${name.replace(/`/g, "`")}\` already exists.`,
+ temp: true,
+ });
+} else
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Added new tag: \`${name.replace(/`/g, "`")}\`!`,
+ temp: true,
+ });
+```
+- `deletetag`
+```ts
+const name = i.options.find((e) => e.name == "name")?.value as string;
+const tag = getTag(i.guild.id, name);
+
+if (!tag)
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Tag with name \`${name.replace(/`/g, "`")}\` could not be found.`,
+ temp: true,
+ });
+
+if (tag.user != d.user.id)
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Tag with name \`${name.replace(/`/g, "`")}\` is not your!`,
+ temp: true,
+ });
+
+deleteTag(i.guild.id, name);
+
+i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Delete tag: \`${name.replace(/`/g, "`")}\`!`,
+ temp: true,
+});
+```
+- `updatetag`
+```ts
+const name = i.options.find((e) => e.name == "name")?.value as string;
+const content = i.options.find((e) => e.name == "content")?.value as string;
+
+if (content.length > 2000)
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Tag content length must be between 1-2000 characters.`,
+ temp: true,
+ });
+
+const tag = getTag(i.guild.id, name);
+if (!tag)
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Tag with name \`${name.replace(/`/g,"`")}\` could not be found.`,
+ temp: true,
+ });
+if (tag.user != d.user.id)
+ return i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Tag with name \`${name.replace(/`/g, "`")}\` is not your!`,
+ temp: true,
+ });
+
+editTag(i.guild.id, name, content);
+i.respond({
+ type: InteractionResponseType.CHANNEL_MESSAGE,
+ content: `Updated tag: \`${name.replace(/`/g, "`")}\`!`,
+ temp: true,
+});
+```
+
+And now our tag bot using Slash Commands is ready! Try playing around it. Here's your homework, try implementing these features.
+- Allow Moderators to delete tags
+- A taginfo command to see who created tag and when
+- Add suggestions for tag name when user spelled it wrong
+
+## 결과 코드
+
+If you got stuck somewhere, resulting code of this guide can be found [here](https://github.com/DjDeveloperr/tag-bot). It has a little more than we did here.
diff --git a/src/ko/index.md b/src/ko/index.md
new file mode 100644
index 0000000..bc51cfd
--- /dev/null
+++ b/src/ko/index.md
@@ -0,0 +1,15 @@
+---
+home: true
+heroImage: https://cdn.discordapp.com/emojis/783321055456002110.png?v=1
+tagline: Deno를 위한, 사용하기 쉬우면서, 매우 고급지고, 조화로운 Discord API 라이브러리입니다.
+actionText: 시작하기 →
+actionLink: /ko/guide/
+features:
+- title: 사용하기 쉬움.
+ details: 할모니와 함께라면, 몇 초 내에 봇을 설정할 수 있습니다.
+- title: 맞춤형.
+ details: 하모니는 커스텀 캐싱을 포함하여 많은 사용자 정의들을 제공합니다.
+- title: 명령어.
+ details: 내장되어 있는 기능들이 풍부한 명령어 프레임 워크가 있습니다.
+footer: ❤️ 와 Harmony 조직이 만듬
+---