refactor: make changes according to @Slincnik comments

remove comment from config

feat: new function getLocalizedDesc

fix: commands updates not sended to discord (temp fix)
This commit is contained in:
Jonny_Bro 2025-03-08 14:49:45 +05:00
parent 5a7cb5d369
commit 8e075c8087
No known key found for this signature in database
GPG key ID: A18808B38428F7C4
9 changed files with 155 additions and 216 deletions

View file

@ -17,7 +17,6 @@
"owner": {
"id": "123456789098765432"
},
"_comment_paths": "Change './src' to './dist' for prod",
"paths": {
"commands": "./src/commands",
"events": "./src/events",

View file

@ -1,43 +1,25 @@
import { replyError, replySuccess } from "@/helpers/extenders.js";
import { getLocalizedDesc, replyError, replySuccess } from "@/helpers/extenders.js";
import { CommandData, SlashCommandProps } from "@/types.js";
import useClient from "@/utils/use-client.js";
import { ApplicationCommandOptionType, ApplicationIntegrationType, InteractionContextType, MessageFlags } from "discord.js";
const client = useClient();
export const data: CommandData = {
name: "addemoji",
description: client.i18n.translate("administration/addemoji:DESCRIPTION"),
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("administration/addemoji:DESCRIPTION", { lng: "ru-RU" }),
uk: client.i18n.translate("administration/addemoji:DESCRIPTION", { lng: "uk-UA" }),
},
...getLocalizedDesc("administration/addemoji:DESCRIPTION"),
// eslint-disable-next-line camelcase
integration_types: [ApplicationIntegrationType.GuildInstall],
contexts: [InteractionContextType.Guild],
options: [
{
name: "link",
description: client.i18n.translate("common:LINK"),
...getLocalizedDesc("common:LINK"),
type: ApplicationCommandOptionType.String,
required: true,
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("common:LINK", { lng: "ru-RU" }),
uk: client.i18n.translate("common:LINK", { lng: "uk-UA" }),
},
},
{
name: "name",
description: client.i18n.translate("common:NAME"),
...getLocalizedDesc("common:NAME"),
type: ApplicationCommandOptionType.String,
required: true,
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("common:NAME", { lng: "ru-RU" }),
uk: client.i18n.translate("common:NAME", { lng: "uk-UA" }),
},
},
],
};

View file

@ -1,4 +1,4 @@
import { replyError, translateContext } from "@/helpers/extenders.js";
import { getLocalizedDesc, replyError, translateContext } from "@/helpers/extenders.js";
import { CommandData, SlashCommandProps } from "@/types.js";
import { createEmbed } from "@/utils/create-embed.js";
import useClient from "@/utils/use-client.js";
@ -8,12 +8,7 @@ const client = useClient();
export const data: CommandData = {
name: "config",
description: client.i18n.translate("administration/config:DESCRIPTION"),
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("administration/config:DESCRIPTION", { lng: "ru-RU" }),
uk: client.i18n.translate("administration/config:DESCRIPTION", { lng: "uk-UA" }),
},
...getLocalizedDesc("administration/config:DESCRIPTION"),
// eslint-disable-next-line camelcase
integration_types: [ApplicationIntegrationType.GuildInstall],
contexts: [InteractionContextType.Guild],
@ -22,32 +17,17 @@ export const data: CommandData = {
options: [
{
name: "list",
description: client.i18n.translate("administration/config:LIST"),
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("administration/config:LIST", { lng: "ru-RU" }),
uk: client.i18n.translate("administration/config:LIST", { lng: "uk-UA" }),
},
...getLocalizedDesc("administration/config:LIST"),
type: ApplicationCommandOptionType.Subcommand,
},
{
name: "set",
description: client.i18n.translate("administration/config:SET"),
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("administration/config:SET", { lng: "ru-RU" }),
uk: client.i18n.translate("administration/config:SET", { lng: "uk-UA" }),
},
...getLocalizedDesc("administration/config:SET"),
type: ApplicationCommandOptionType.Subcommand,
options: [
{
name: "parameter",
description: client.i18n.translate("administration/config:PARAMETER"),
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("administration/config:PARAMETER", { lng: "ru-RU" }),
uk: client.i18n.translate("administration/config:PARAMETER", { lng: "uk-UA" }),
},
...getLocalizedDesc("administration/config:PARAMETER"),
type: ApplicationCommandOptionType.String,
required: true,
choices: [
@ -63,24 +43,14 @@ export const data: CommandData = {
],
},
{
name: "boolean",
description: client.i18n.translate("common:STATE"),
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("common:STATE", { lng: "ru-RU" }),
uk: client.i18n.translate("common:STATE", { lng: "uk-UA" }),
},
name: "state",
...getLocalizedDesc("common:STATE"),
type: ApplicationCommandOptionType.Boolean,
required: true,
},
{
name: "channel",
description: client.i18n.translate("common:CHANNEL"),
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate("common:CHANNEL", { lng: "ru-RU" }),
uk: client.i18n.translate("common:CHANNEL", { lng: "uk-UA" }),
},
...getLocalizedDesc("common:CHANNEL"),
type: ApplicationCommandOptionType.Channel,
required: false,
},
@ -98,132 +68,137 @@ export const run = async ({ interaction }: SlashCommandProps) => {
const command = interaction.options.getSubcommand();
if (command === "list") {
const fields = await generateFields(interaction, guildData);
const embed = createEmbed({
author: {
name: interaction.guild.name,
iconURL: interaction.guild.iconURL() || "",
},
fields: [
{
name: await translateContext(interaction, "administration/config:WELCOME_TITLE"),
value: guildData.plugins.welcome.enabled
? await translateContext(interaction, "administration/config:WELCOME_CONTENT", {
channel: `<#${guildData.plugins.welcome.channel}>`,
withImage: guildData.plugins.welcome.withImage ? await translateContext(interaction, "common:YES") : await translateContext(interaction, "common:NO"),
})
: await translateContext(interaction, "common:DISABLED"),
inline: true,
},
{
name: await translateContext(interaction, "administration/config:GOODBYE_TITLE"),
value: guildData.plugins.goodbye.enabled
? await translateContext(interaction, "administration/config:GOODBYE_CONTENT", {
channel: `<#${guildData.plugins.goodbye.channel}>`,
withImage: guildData.plugins.goodbye.withImage ? await translateContext(interaction, "common:YES") : await translateContext(interaction, "common:NO"),
})
: await translateContext(interaction, "common:DISABLED"),
inline: true,
},
{
name: await translateContext(interaction, "administration/config:MONITORING_CHANNELS"),
value:
`${await translateContext(interaction, "administration/config:MESSAGEUPDATE")}: ${guildData.plugins?.monitoring?.messageUpdate ? `<#${guildData.plugins?.monitoring?.messageUpdate}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n` +
`${await translateContext(interaction, "administration/config:MESSAGEDELETE")}: ${guildData.plugins?.monitoring?.messageDelete ? `<#${guildData.plugins?.monitoring?.messageDelete}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n`,
},
{
name: await translateContext(interaction, "administration/config:SPECIAL_CHANNELS"),
value:
`${await translateContext(interaction, "administration/config:BIRTHDAYS")}: ${guildData.plugins?.birthdays ? `<#${guildData.plugins.birthdays}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n` +
`${await translateContext(interaction, "administration/config:MODLOGS")}: ${guildData.plugins?.modlogs ? `<#${guildData.plugins.modlogs}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n` +
`${await translateContext(interaction, "administration/config:REPORTS")}: ${guildData.plugins?.reports ? `<#${guildData.plugins.reports}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n` +
`${await translateContext(interaction, "administration/config:SUGGESTIONS")}: ${guildData.plugins?.suggestions ? `<#${guildData.plugins.suggestions}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n` +
`${await translateContext(interaction, "administration/config:TICKETSCATEGORY")}: ${guildData.plugins?.tickets?.ticketsCategory ? `<#${guildData.plugins?.tickets?.ticketsCategory}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n` +
`${await translateContext(interaction, "administration/config:TICKETLOGS")}: ${guildData.plugins?.tickets?.ticketLogs ? `<#${guildData.plugins?.tickets?.ticketLogs}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n` +
`${await translateContext(interaction, "administration/config:TRANSCRIPTIONLOGS")}: ${guildData.plugins?.tickets?.transcriptionLogs ? `<#${guildData.plugins?.tickets?.transcriptionLogs}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`}\n`,
},
],
// TODO: тс даёт ошибку но работает ( я ещё учу тс ;( )
// Тип "({ name: string; value: string; inline: boolean; } | undefined)[]" не может быть назначен для типа "readonly APIEmbedField[]".
// @ts-ignore Type not assignable (for now)
fields,
});
return interaction.editReply({
embeds: [embed],
});
} else {
const parameter = interaction.options.getString("parameter", true),
state = interaction.options.getBoolean("state", true),
channel = interaction.options.getChannel("channel");
return interaction.editReply({ embeds: [embed] });
}
const parameter = interaction.options.getString("parameter", true);
const state = interaction.options.getBoolean("state", true);
const channel = interaction.options.getChannel("channel");
await changeSetting(interaction, guildData, parameter, state, channel);
}
};
async function changeSetting(interaction: ChatInputCommandInteraction, data: any, parameter: string, state: boolean, channel: any) { // TODO: Proper type for channel
const parameterSplitted = parameter.split(".");
async function generateFields(interaction: ChatInputCommandInteraction, guildData: any) {
const fieldsConfig = [
{
nameKey: "administration/config:WELCOME_TITLE",
valueKey: "administration/config:WELCOME_CONTENT",
plugin: guildData.plugins.welcome,
},
{
nameKey: "administration/config:GOODBYE_TITLE",
valueKey: "administration/config:GOODBYE_CONTENT",
plugin: guildData.plugins.goodbye,
},
{
nameKey: "administration/config:MONITORING_CHANNELS",
values: [
{ key: "administration/config:MESSAGEUPDATE", value: guildData.plugins?.monitoring?.messageUpdate },
{ key: "administration/config:MESSAGEDELETE", value: guildData.plugins?.monitoring?.messageDelete },
],
},
{
nameKey: "administration/config:SPECIAL_CHANNELS",
values: [
{ key: "administration/config:BIRTHDAYS", value: guildData.plugins?.birthdays },
{ key: "administration/config:MODLOGS", value: guildData.plugins?.modlogs },
{ key: "administration/config:REPORTS", value: guildData.plugins?.reports },
{ key: "administration/config:SUGGESTIONS", value: guildData.plugins?.suggestions },
{ key: "administration/config:TICKETSCATEGORY", value: guildData.plugins?.tickets?.ticketsCategory },
{ key: "administration/config:TICKETLOGS", value: guildData.plugins?.tickets?.ticketLogs },
{ key: "administration/config:TRANSCRIPTIONLOGS", value: guildData.plugins?.tickets?.transcriptionLogs },
],
},
];
if (parameterSplitted.length === 2) {
if (data.plugins[parameterSplitted[0]] === undefined) data.plugins[parameterSplitted[0]] = {};
const fields = await Promise.all(
fieldsConfig.map(async field => {
const name = await translateContext(interaction, field.nameKey);
if (!state) {
data.plugins[parameterSplitted[0]][parameterSplitted[1]] = null;
if (field.plugin) {
const value = field.plugin.enabled
? await translateContext(interaction, field.valueKey!, {
channel: `<#${field.plugin.channel}>`,
})
: await translateContext(interaction, "common:DISABLED");
data.markModified(`plugins.${parameter}`);
await data.save();
return interaction.reply({
content: `${await translateContext(interaction, `administration/config:${parameterSplitted.length === 2 ? parameterSplitted[1].toUpperCase() : parameter.toUpperCase()}`)}: **${await translateContext(interaction, "common:DISABLED")}**`,
ephemeral: true,
});
} else {
if (parameterSplitted[1] === "ticketsCategory" && channel?.type !== ChannelType.GuildCategory) return interaction.reply({ content: await translateContext(interaction, "administration/config:TICKETS_NOT_CATEGORY"), ephemeral: true });
if (channel) {
data.plugins[parameterSplitted[0]][parameterSplitted[1]] = channel.id;
data.markModified(`plugins.${parameter}`);
await data.save();
return interaction.reply({
content: `${await translateContext(interaction, `administration/config:${parameterSplitted.length === 2 ? parameterSplitted[1].toUpperCase() : parameter.toUpperCase()}`)}: **${await translateContext(interaction, "common:ENABLED")}** (${channel.toString()})`,
ephemeral: true,
});
} else {
return interaction.reply({
content: `${await translateContext(interaction, `administration/config:${parameterSplitted.length === 2 ? parameterSplitted[1].toUpperCase() : parameter.toUpperCase()}`)}: ${
data.plugins[parameter] ? `**${await translateContext(interaction, "common:ENABLED")}** (<#${data.plugins[parameter]}>)` : `**${await translateContext(interaction, "common:DISABLED")}**`
}`,
ephemeral: true,
});
return { name, value, inline: true };
}
};
} else {
if (!state) {
data.plugins[parameter] = null;
data.markModified(`plugins.${parameter}`);
await data.save();
if (field.values) {
const value = await Promise.all(
field.values.map(async ({ key, value }) => {
const translatedKey = await translateContext(interaction, key);
const translatedValue = value ? `<#${value}>` : `*${await translateContext(interaction, "common:NOT_DEFINED")}*`;
return interaction.reply({
content: `${client.i18n.translate(`administration/config:${parameter.toUpperCase()}`)}: **${client.i18n.translate("common:DISABLED")}**`,
ephemeral: true,
});
} else {
if (channel) {
data.plugins[parameter] = channel.id;
return `${translatedKey}: ${translatedValue}`;
}),
);
data.markModified(`plugins.${parameter}`);
await data.save();
return interaction.reply({
content: `${client.i18n.translate(`administration/config:${parameter.toUpperCase()}`)}: **${client.i18n.translate("common:ENABLED")}** (${channel.toString()})`,
ephemeral: true,
});
} else {
return interaction.reply({
content: `${client.i18n.translate(`administration/config:${parameter.toUpperCase()}`)}: ${
data.plugins[parameter] ? `**${client.i18n.translate("common:ENABLED")}** (<#${data.plugins[parameter]}>)` : `**${client.i18n.translate("common:DISABLED")}**`
}`,
ephemeral: true,
});
}
}
return { name, value: value.join("\n"), inline: false };
}
}),
);
return fields;
}
async function saveSettings(guildData: any, parameter: string, value: any) { // TODO: Proper type for `any`
guildData.plugins[parameter] = value;
guildData.markModified(`plugins.${parameter}`);
await guildData.save();
}
async function generateReply(interaction: ChatInputCommandInteraction, guildData: any, parameter: string, state: boolean, channel?: any) {
const translatedParam = await translateContext(interaction, `administration/config:${parameter.toUpperCase()}`);
const enabledText = await translateContext(interaction, "common:ENABLED");
const disabledText = await translateContext(interaction, "common:DISABLED");
if (channel) return `${translatedParam}: **${enabledText}** (${channel.toString()})`;
return `${translatedParam}: ${state ? `**${enabledText}** (<#${guildData.plugins[parameter]}>)` : `**${disabledText}**`}`;
}
async function changeSetting(interaction: ChatInputCommandInteraction, guildData: any, parameter: string, state: boolean, channel?: any) {
const parameterSplitted = parameter.split(".");
const isNested = parameterSplitted.length === 2;
if (isNested && guildData.plugins[parameterSplitted[0]] === undefined) {
guildData.plugins[parameterSplitted[0]] = {};
}
if (!state) {
await saveSettings(guildData, parameter, null);
return interaction.editReply({
content: await generateReply(interaction, guildData, parameterSplitted[isNested ? 1 : 0], state),
});
}
if (isNested && parameterSplitted[1] === "ticketsCategory" && channel?.type !== ChannelType.GuildCategory) {
return interaction.editReply({
content: await translateContext(interaction, "administration/config:TICKETS_NOT_CATEGORY"),
});
}
if (channel) {
await saveSettings(guildData, parameter, channel.id);
}
return interaction.editReply({
content: await generateReply(interaction, guildData, parameterSplitted[isNested ? 1 : 0], state, channel),
});
}

View file

@ -1,4 +1,4 @@
import { replyError, replySuccess } from "@/helpers/extenders.js";
import { getLocalizedDesc, replyError, replySuccess } from "@/helpers/extenders.js";
import { CommandData, SlashCommandProps } from "@/types.js";
import useClient from "@/utils/use-client.js";
import { ApplicationCommandOptionType, ApplicationIntegrationType, InteractionContextType, MessageFlags } from "discord.js";
@ -7,35 +7,20 @@ const client = useClient();
export const data: CommandData = {
name: "birthdate",
description: client.i18n.translate("economy/birthdate:DESCRIPTION"),
// eslint-disable-next-line camelcase
description_localizations: {
uk: client.i18n.translate("economy/birthdate:DESCRIPTION", { lng: "uk-UA" }),
ru: client.i18n.translate("economy/birthdate:DESCRIPTION", { lng: "ru-RU" }),
},
...getLocalizedDesc("economy/birthdate:DESCRIPTION"),
// eslint-disable-next-line camelcase
integration_types: [ApplicationIntegrationType.GuildInstall, ApplicationIntegrationType.UserInstall],
contexts: [InteractionContextType.BotDM, InteractionContextType.Guild, InteractionContextType.PrivateChannel],
options: [
{
name: "day",
description: client.i18n.translate("economy/birthdate:DAY"),
...getLocalizedDesc("economy/birthdate:DAY"),
type: ApplicationCommandOptionType.Integer,
// eslint-disable-next-line camelcase
description_localizations: {
uk: client.i18n.translate("economy/birthdate:DAY", { lng: "uk-UA" }),
ru: client.i18n.translate("economy/birthdate:DAY", { lng: "ru-RU" }),
},
},
{
name: "month",
description: client.i18n.translate("economy/birthdate:MONTH"),
...getLocalizedDesc("economy/birthdate:MONTH"),
type: ApplicationCommandOptionType.Integer,
// eslint-disable-next-line camelcase
description_localizations: {
uk: client.i18n.translate("economy/birthdate:MONTH", { lng: "uk-UA" }),
ru: client.i18n.translate("economy/birthdate:MONTH", { lng: "ru-RU" }),
},
choices: [
{ name: client.i18n.translate("misc:MONTHS:JANUARY"), value: 1 },
{ name: client.i18n.translate("misc:MONTHS:FEBRUARY"), value: 2 },
@ -53,33 +38,18 @@ export const data: CommandData = {
},
{
name: "year",
description: client.i18n.translate("economy/birthdate:YEAR"),
...getLocalizedDesc("economy/birthdate:YEAR"),
type: ApplicationCommandOptionType.Integer,
// eslint-disable-next-line camelcase
description_localizations: {
uk: client.i18n.translate("economy/birthdate:YEAR", { lng: "uk-UA" }),
ru: client.i18n.translate("economy/birthdate:YEAR", { lng: "ru-RU" }),
},
},
{
name: "clear",
type: ApplicationCommandOptionType.Boolean,
description: client.i18n.translate("economy/birthdate:CLEAR"),
// eslint-disable-next-line camelcase
description_localizations: {
uk: client.i18n.translate("economy/birthdate:CLEAR", { lng: "uk-UA" }),
ru: client.i18n.translate("economy/birthdate:CLEAR", { lng: "ru-RU" }),
},
...getLocalizedDesc("economy/birthdate:CLEAR"),
},
{
name: "ephemeral",
type: ApplicationCommandOptionType.Boolean,
description: client.i18n.translate("misc:EPHEMERAL_RESPONSE"),
// eslint-disable-next-line camelcase
description_localizations: {
uk: client.i18n.translate("misc:EPHEMERAL_RESPONSE", { lng: "uk-UA" }),
ru: client.i18n.translate("misc:EPHEMERAL_RESPONSE", { lng: "ru-RU" }),
},
...getLocalizedDesc("misc:EPHEMERAL_RESPONSE"),
},
],
};

View file

@ -31,7 +31,7 @@ const registerGlobalCommands = async (client: ExtendedClient, commands: CommandF
commands.map(async ({ data }) => {
const targetCommand = appCommandsManager.cache.find(cmd => cmd.name === data.name);
if (targetCommand && differentCommands(targetCommand, data)) {
if (targetCommand /*&& differentCommands(targetCommand, data) */) { // FIXME: differentCommands is always false
await targetCommand.edit(data as Partial<ApplicationCommandData>).catch(() => logger.error(`Failed to update command: ${data.name} globally`));
logger.log(`Edited command globally: ${data.name}`);

View file

@ -1,5 +1,5 @@
import { BaseInteraction, CacheType, Interaction, InteractionReplyOptions, Message, MessageFlags, User } from "discord.js";
import useClient from "@/utils/use-client.js";
import { BaseInteraction, CacheType, Interaction, InteractionReplyOptions, Message, MessageFlags, User } from "discord.js";
interface Options extends InteractionReplyOptions {
prefixEmoji?: string;
@ -15,6 +15,19 @@ export const getLocale = async (guildId: string) => {
return guild.language;
};
export const getLocalizedDesc = (key: string) => {
const client = useClient();
return {
description: client.i18n.translate(key),
// eslint-disable-next-line camelcase
description_localizations: {
ru: client.i18n.translate(key, { lng: "ru-RU" }),
uk: client.i18n.translate(key, { lng: "uk-UA" }),
},
};
};
const getAppEmojis = () => {
const client = useClient();

View file

@ -24,12 +24,12 @@
"BAN_CONTENT": "Ban: After **{{count}}** warnings",
"BAN_NOT_DEFINED": "Ban: Not set",
"GOODBYE_TITLE": "Farewell",
"GOODBYE_CONTENT": "Channel: {{channel}}\nCard: {{withImage}}",
"GOODBYE_CONTENT": "Channel: {{channel}}",
"KICK_CONTENT": "Kick: After **{{count}}** warnings",
"KICK_NOT_DEFINED": "Kick: Not set",
"LIST": "Display server settings",
"SET": "Modify server settings",
"PARAMETER": "Parameter",
"WELCOME_TITLE": "Welcome",
"WELCOME_CONTENT": "Channel: {{channel}}\nCard: {{withImage}}"
"WELCOME_CONTENT": "Channel: {{channel}}"
}

View file

@ -24,12 +24,12 @@
"BAN_CONTENT": "Бан: После **{{count}}** предупреждений",
"BAN_NOT_DEFINED": "Бан: Не назначено",
"GOODBYE_TITLE": "Прощание",
"GOODBYE_CONTENT": "Канал: {{channel}}\nКарточка: {{withImage}}",
"GOODBYE_CONTENT": "Канал: {{channel}}",
"KICK_CONTENT": "Кик: После **{{count}}** предупреждений",
"KICK_NOT_DEFINED": "Кик: Не назначено",
"LIST": "Показать настройки сервера",
"SET": "Изменить настройки сервера",
"PARAMETER": "Параметр",
"WELCOME_TITLE": "Приветствие",
"WELCOME_CONTENT": "Канал: {{channel}}\nКарточка: {{withImage}}"
"WELCOME_CONTENT": "Канал: {{channel}}"
}

View file

@ -24,12 +24,12 @@
"BAN_CONTENT": "Бан: Після **{{count}}** попереджень",
"BAN_NOT_DEFINED": "Бан: Не призначено",
"GOODBYE_TITLE": "Прощання",
"GOODBYE_CONTENT": "Канал: {{channel}}\nКартка: {{withImage}}",
"GOODBYE_CONTENT": "Канал: {{channel}}",
"KICK_CONTENT": "Кік: Після **{{count}}** попереджень",
"KICK_NOT_DEFINED": "Кік: Не призначено",
"LIST": "Показати налаштування серверу",
"SET": "Змінити налаштування серверу ",
"PARAMETER": "Параметр",
"WELCOME_TITLE": "Привітання",
"WELCOME_CONTENT": "Канал: {{channel}}\nКартка: {{withImage}}"
"WELCOME_CONTENT": "Канал: {{channel}}"
}