marge inital template support
This commit is contained in:
parent
51902f5307
commit
8bc009dc19
10 changed files with 359 additions and 3 deletions
|
@ -177,6 +177,10 @@ app.use("/", async (req: Request, res: Response) => {
|
||||||
res.sendFile(path.join(__dirname, "webpage", "invite.html"));
|
res.sendFile(path.join(__dirname, "webpage", "invite.html"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (req.path.startsWith("/template/")) {
|
||||||
|
res.sendFile(path.join(__dirname, "webpage", "template.html"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
const filePath = await combinePath("/webpage/" + req.path);
|
const filePath = await combinePath("/webpage/" + req.path);
|
||||||
res.sendFile(filePath);
|
res.sendFile(filePath);
|
||||||
});
|
});
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
extendedProperties,
|
extendedProperties,
|
||||||
banObj,
|
banObj,
|
||||||
addInfoBan,
|
addInfoBan,
|
||||||
|
templateSkim,
|
||||||
} from "./jsontypes.js";
|
} from "./jsontypes.js";
|
||||||
import {User} from "./user.js";
|
import {User} from "./user.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
|
@ -24,6 +25,7 @@ import {webhookMenu} from "./webhooks.js";
|
||||||
import {createImg} from "./utils/utils.js";
|
import {createImg} from "./utils/utils.js";
|
||||||
import {Sticker} from "./sticker.js";
|
import {Sticker} from "./sticker.js";
|
||||||
import {ProgessiveDecodeJSON} from "./utils/progessiveLoad.js";
|
import {ProgessiveDecodeJSON} from "./utils/progessiveLoad.js";
|
||||||
|
import {getApiUrls} from "../utils.js";
|
||||||
|
|
||||||
class Guild extends SnowFlake {
|
class Guild extends SnowFlake {
|
||||||
owner!: Localuser;
|
owner!: Localuser;
|
||||||
|
@ -581,7 +583,89 @@ class Guild extends SnowFlake {
|
||||||
})();
|
})();
|
||||||
const webhooks = settings.addButton(I18n.webhooks.base());
|
const webhooks = settings.addButton(I18n.webhooks.base());
|
||||||
webhookMenu(this, this.info.api + `/guilds/${this.id}/webhooks`, webhooks);
|
webhookMenu(this, this.info.api + `/guilds/${this.id}/webhooks`, webhooks);
|
||||||
console.log(this.properties.features, this.properties.features.includes("COMMUNITY"));
|
const template = settings.addButton(I18n.guild.templates());
|
||||||
|
(async () => {
|
||||||
|
template.addText(I18n.guild.templcateMetaDesc());
|
||||||
|
const generateTemplateArea = (temp: templateSkim) => {
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.classList.add("flexltr", "templateMiniBox");
|
||||||
|
const code = document.createElement("span");
|
||||||
|
|
||||||
|
code.textContent = temp.code + ` (${temp.name})`;
|
||||||
|
|
||||||
|
const edit = document.createElement("button");
|
||||||
|
edit.textContent = I18n.edit();
|
||||||
|
edit.onclick = () => {
|
||||||
|
const form = template.addSubForm(
|
||||||
|
I18n.guild.editingTemplate(temp.name),
|
||||||
|
(tempy) => {
|
||||||
|
const template = tempy as templateSkim;
|
||||||
|
temp.name = template.name;
|
||||||
|
temp.description = template.description;
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fetchURL: this.info.api + "/guilds/" + this.id + "/templates/" + temp.code,
|
||||||
|
method: "PATCH",
|
||||||
|
headers: this.headers,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const search = new URLSearchParams([["instance", this.info.wellknown]]);
|
||||||
|
form.addMDText(
|
||||||
|
I18n.guild.templateURL(
|
||||||
|
window.location.origin + "/template/" + temp.code + "?" + search,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
const name = form.addTextInput(I18n.guild.templateName(), "name", {
|
||||||
|
initText: temp.name,
|
||||||
|
});
|
||||||
|
form.addMDInput(I18n.guild.templateDesc(), "description", {
|
||||||
|
initText: temp.description,
|
||||||
|
});
|
||||||
|
User.resolve(temp.creator_id, this.localuser).then((_) => {
|
||||||
|
form.addText(I18n.guild.tempCreatedBy());
|
||||||
|
form.addHTMLArea(_.createWidget(this));
|
||||||
|
});
|
||||||
|
form.addText(I18n.guild.tempUseCount((temp.usage_count || 0) + ""));
|
||||||
|
form.addPreprocessor(() => {
|
||||||
|
if (name.value.length < 2) {
|
||||||
|
throw new FormError(name, I18n.guild.templateNameShort());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
div.append(code, edit);
|
||||||
|
template.addHTMLArea(div);
|
||||||
|
};
|
||||||
|
template.addButtonInput("", I18n.guild.createNewTemplate(), () => {
|
||||||
|
const form = template.addSubForm(
|
||||||
|
I18n.guild.createNewTemplate(),
|
||||||
|
(code) => {
|
||||||
|
template.returnFromSub();
|
||||||
|
generateTemplateArea(code as templateSkim);
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fetchURL: this.info.api + "/guilds/" + this.id + "/templates",
|
||||||
|
method: "POST",
|
||||||
|
headers: this.headers,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
form.addText(I18n.guild.templcateMetaDesc());
|
||||||
|
const name = form.addTextInput(I18n.guild.templateName(), "name");
|
||||||
|
form.addMDInput(I18n.guild.templateDesc(), "description");
|
||||||
|
form.addPreprocessor(() => {
|
||||||
|
if (name.value.length < 2) {
|
||||||
|
throw new FormError(name, I18n.guild.templateNameShort());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const templates = (await (
|
||||||
|
await fetch(this.info.api + "/guilds/" + this.id + "/templates", {headers: this.headers})
|
||||||
|
).json()) as templateSkim[];
|
||||||
|
for (const temp of templates.reverse()) {
|
||||||
|
generateTemplateArea(temp);
|
||||||
|
}
|
||||||
|
})();
|
||||||
let com = false;
|
let com = false;
|
||||||
if (this.properties.features.includes("COMMUNITY")) {
|
if (this.properties.features.includes("COMMUNITY")) {
|
||||||
this.addCommunity(settings, textChannels);
|
this.addCommunity(settings, textChannels);
|
||||||
|
|
|
@ -7,6 +7,7 @@ import {Message} from "./message.js";
|
||||||
import {File} from "./file.js";
|
import {File} from "./file.js";
|
||||||
import {I18n} from "./i18n.js";
|
import {I18n} from "./i18n.js";
|
||||||
(async () => {
|
(async () => {
|
||||||
|
let templateID = new URLSearchParams(window.location.search).get("templateID");
|
||||||
await I18n.done;
|
await I18n.done;
|
||||||
|
|
||||||
if (!Localuser.users.currentuser) {
|
if (!Localuser.users.currentuser) {
|
||||||
|
@ -54,6 +55,9 @@ import {I18n} from "./i18n.js";
|
||||||
loading.classList.add("doneloading");
|
loading.classList.add("doneloading");
|
||||||
loading.classList.remove("loading");
|
loading.classList.remove("loading");
|
||||||
console.log("done loading");
|
console.log("done loading");
|
||||||
|
if (templateID) {
|
||||||
|
thisUser.passTemplateID(templateID);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error(e);
|
console.error(e);
|
||||||
|
|
|
@ -131,6 +131,37 @@ interface banObj {
|
||||||
public_flags: number;
|
public_flags: number;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
interface templateSkim {
|
||||||
|
id: string;
|
||||||
|
code: string;
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
usage_count: null | number;
|
||||||
|
creator_id: string;
|
||||||
|
created_at: string;
|
||||||
|
updated_at: string;
|
||||||
|
source_guild_id: string;
|
||||||
|
serialized_source_guild: {
|
||||||
|
id: string;
|
||||||
|
afk_channel_id: null | string;
|
||||||
|
afk_timeout: number;
|
||||||
|
default_message_notifications: number;
|
||||||
|
description: null | "string";
|
||||||
|
explicit_content_filter: number;
|
||||||
|
features: string[];
|
||||||
|
icon: null | string;
|
||||||
|
large: boolean;
|
||||||
|
name: string;
|
||||||
|
preferred_locale: string;
|
||||||
|
region: string;
|
||||||
|
system_channel_id: null | string;
|
||||||
|
system_channel_flags: number;
|
||||||
|
verification_level: number;
|
||||||
|
widget_enabled: boolean;
|
||||||
|
nsfw: boolean;
|
||||||
|
premium_progress_bar_enabled: boolean;
|
||||||
|
};
|
||||||
|
}
|
||||||
interface addInfoBan {
|
interface addInfoBan {
|
||||||
id: string;
|
id: string;
|
||||||
user_id: string;
|
user_id: string;
|
||||||
|
@ -838,4 +869,5 @@ export {
|
||||||
stickerJson,
|
stickerJson,
|
||||||
banObj,
|
banObj,
|
||||||
addInfoBan,
|
addInfoBan,
|
||||||
|
templateSkim,
|
||||||
};
|
};
|
||||||
|
|
|
@ -1046,6 +1046,7 @@ class Localuser {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
loadGuild(id: string, forceReload = false): Guild | undefined {
|
loadGuild(id: string, forceReload = false): Guild | undefined {
|
||||||
this.searching = false;
|
this.searching = false;
|
||||||
let guild = this.guildids.get(id);
|
let guild = this.guildids.get(id);
|
||||||
|
@ -1172,7 +1173,10 @@ class Localuser {
|
||||||
}
|
}
|
||||||
this.unreads();
|
this.unreads();
|
||||||
}
|
}
|
||||||
createGuild() {
|
passTemplateID(id: string) {
|
||||||
|
this.createGuild(id);
|
||||||
|
}
|
||||||
|
createGuild(templateID?: string) {
|
||||||
const full = new Dialog("");
|
const full = new Dialog("");
|
||||||
const buttons = full.options.addButtons("", {top: true});
|
const buttons = full.options.addButtons("", {top: true});
|
||||||
const viacode = buttons.add(I18n.getTranslation("invite.joinUsing"));
|
const viacode = buttons.add(I18n.getTranslation("invite.joinUsing"));
|
||||||
|
@ -1224,7 +1228,61 @@ class Localuser {
|
||||||
full.hide();
|
full.hide();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
const guildcreateFromTemplate = buttons.add(I18n.guild.createFromTemplate());
|
||||||
|
{
|
||||||
|
const form = guildcreateFromTemplate.addForm(
|
||||||
|
"",
|
||||||
|
(_: any) => {
|
||||||
|
if (_.message) {
|
||||||
|
loading.hide();
|
||||||
|
full.show();
|
||||||
|
alert(_.message);
|
||||||
|
const htmlarea = buttons.htmlarea.deref();
|
||||||
|
if (htmlarea) buttons.generateHTMLArea(guildcreateFromTemplate, htmlarea);
|
||||||
|
} else {
|
||||||
|
loading.hide();
|
||||||
|
full.hide();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
method: "POST",
|
||||||
|
headers: this.headers,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const template = form.addTextInput(I18n.guild.template(), "template", {
|
||||||
|
initText: templateID || "",
|
||||||
|
});
|
||||||
|
form.addFileInput(I18n.getTranslation("guild.icon:"), "icon", {files: "one"});
|
||||||
|
form.addTextInput(I18n.getTranslation("guild.name:"), "name", {required: true});
|
||||||
|
|
||||||
|
const loading = new Dialog("");
|
||||||
|
loading.float.options.addTitle(I18n.guild.creating());
|
||||||
|
form.onFormError = () => {
|
||||||
|
loading.hide();
|
||||||
|
full.show();
|
||||||
|
};
|
||||||
|
form.addPreprocessor((e) => {
|
||||||
|
loading.show();
|
||||||
|
full.hide();
|
||||||
|
if ("template" in e) delete e.template;
|
||||||
|
let code: string;
|
||||||
|
if (URL.canParse(template.value)) {
|
||||||
|
const url = new URL(template.value);
|
||||||
|
code = url.pathname.split("/").at(-1) as string;
|
||||||
|
if (url.host === "discord.com") {
|
||||||
|
code = "discord:" + code;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
code = template.value;
|
||||||
|
}
|
||||||
|
form.fetchURL = this.info.api + "/guilds/templates/" + code;
|
||||||
|
});
|
||||||
|
}
|
||||||
full.show();
|
full.show();
|
||||||
|
if (templateID) {
|
||||||
|
const htmlarea = buttons.htmlarea.deref();
|
||||||
|
if (htmlarea) buttons.generateHTMLArea(guildcreateFromTemplate, htmlarea);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
async makeGuild(fields: {name: string; icon: string | null}) {
|
async makeGuild(fields: {name: string; icon: string | null}) {
|
||||||
return await (
|
return await (
|
||||||
|
|
|
@ -1095,7 +1095,7 @@ class Form implements OptionsElement<object> {
|
||||||
readonly names: Map<string, OptionsElement<any>> = new Map();
|
readonly names: Map<string, OptionsElement<any>> = new Map();
|
||||||
readonly required: WeakSet<OptionsElement<any>> = new WeakSet();
|
readonly required: WeakSet<OptionsElement<any>> = new WeakSet();
|
||||||
readonly submitText: string;
|
readonly submitText: string;
|
||||||
readonly fetchURL: string;
|
fetchURL: string;
|
||||||
readonly headers = {};
|
readonly headers = {};
|
||||||
readonly method: string;
|
readonly method: string;
|
||||||
value!: object;
|
value!: object;
|
||||||
|
|
|
@ -59,6 +59,18 @@ body {
|
||||||
margin-left: 8px;
|
margin-left: 8px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.templateMiniBox {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
padding: 6px;
|
||||||
|
border-radius: 4px;
|
||||||
|
width: fit-content;
|
||||||
|
background: var(--secondary-bg);
|
||||||
|
|
||||||
|
button {
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
.flexltr {
|
.flexltr {
|
||||||
min-height: 0;
|
min-height: 0;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1952,6 +1964,7 @@ img.bigembedimg {
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
align-items: flex-start;
|
align-items: flex-start;
|
||||||
|
z-index: 3;
|
||||||
}
|
}
|
||||||
.hypoprofile {
|
.hypoprofile {
|
||||||
position: relative;
|
position: relative;
|
||||||
|
|
35
src/webpage/template.html
Normal file
35
src/webpage/template.html
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<title>Jank Client</title>
|
||||||
|
<meta content="Invite" property="og:title" />
|
||||||
|
<meta content="Accept this invite for a spacebar guild" property="og:description" />
|
||||||
|
<meta name="description" content="A server template" />
|
||||||
|
<meta content="/logo.webp" property="og:image" />
|
||||||
|
<meta content="#4b458c" data-react-helmet="true" name="theme-color" />
|
||||||
|
<link href="/style.css" rel="stylesheet" />
|
||||||
|
<link href="/themes.css" rel="stylesheet" id="lightcss" />
|
||||||
|
<style>
|
||||||
|
body.no-theme {
|
||||||
|
background: #16191b;
|
||||||
|
}
|
||||||
|
@media (prefers-color-scheme: light) {
|
||||||
|
body.no-theme {
|
||||||
|
background: #9397bd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body class="no-theme">
|
||||||
|
<div>
|
||||||
|
<div id="invitebody">
|
||||||
|
<h1 id="templatename">Use Template Name</h1>
|
||||||
|
<p id="templatedescription"></p>
|
||||||
|
<button id="usetemplate">Use template</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="module" src="/templatePage.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
110
src/webpage/templatePage.ts
Normal file
110
src/webpage/templatePage.ts
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
import {I18n} from "./i18n.js";
|
||||||
|
import {templateSkim} from "./jsontypes.js";
|
||||||
|
import {getapiurls} from "./utils/utils.js";
|
||||||
|
import {getBulkUsers, Specialuser} from "./utils/utils.js";
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
const users = getBulkUsers();
|
||||||
|
const well = new URLSearchParams(window.location.search).get("instance");
|
||||||
|
const joinable: Specialuser[] = [];
|
||||||
|
|
||||||
|
for (const key in users.users) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(users.users, key)) {
|
||||||
|
const user: Specialuser = users.users[key];
|
||||||
|
if (well && user.serverurls.wellknown.includes(well)) {
|
||||||
|
joinable.push(user);
|
||||||
|
}
|
||||||
|
console.log(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let urls: {api: string; cdn: string} | undefined;
|
||||||
|
|
||||||
|
if (!joinable.length && well) {
|
||||||
|
const out = await getapiurls(well);
|
||||||
|
if (out) {
|
||||||
|
urls = out;
|
||||||
|
for (const key in users.users) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(users.users, key)) {
|
||||||
|
const user: Specialuser = users.users[key];
|
||||||
|
if (user.serverurls.api.includes(out.api)) {
|
||||||
|
joinable.push(user);
|
||||||
|
}
|
||||||
|
console.log(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Someone needs to handle the case where the servers don't exist");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
urls = joinable[0].serverurls;
|
||||||
|
}
|
||||||
|
await I18n.done;
|
||||||
|
if (!joinable.length) {
|
||||||
|
document.getElementById("usetemplate")!.textContent = I18n.htmlPages.noAccount();
|
||||||
|
}
|
||||||
|
|
||||||
|
const code = window.location.pathname.split("/")[2];
|
||||||
|
|
||||||
|
fetch(`${urls!.api}/guilds/templates/${code}`, {
|
||||||
|
method: "GET",
|
||||||
|
headers: {
|
||||||
|
Authorization: joinable[0].token,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.then((response) => response.json())
|
||||||
|
.then((json) => {
|
||||||
|
const template = json as templateSkim;
|
||||||
|
document.getElementById("templatename")!.textContent = I18n.useTemplate(template.name);
|
||||||
|
document.getElementById("templatedescription")!.textContent = template.description;
|
||||||
|
});
|
||||||
|
|
||||||
|
function showAccounts(): void {
|
||||||
|
const table = document.createElement("dialog");
|
||||||
|
for (const user of joinable) {
|
||||||
|
console.log(user.pfpsrc);
|
||||||
|
|
||||||
|
const userinfo = document.createElement("div");
|
||||||
|
userinfo.classList.add("flexltr", "switchtable");
|
||||||
|
|
||||||
|
const pfp = document.createElement("img");
|
||||||
|
pfp.src = user.pfpsrc;
|
||||||
|
pfp.classList.add("pfp");
|
||||||
|
userinfo.append(pfp);
|
||||||
|
|
||||||
|
const userDiv = document.createElement("div");
|
||||||
|
userDiv.classList.add("userinfo");
|
||||||
|
userDiv.textContent = user.username;
|
||||||
|
userDiv.append(document.createElement("br"));
|
||||||
|
|
||||||
|
const span = document.createElement("span");
|
||||||
|
span.textContent = user.serverurls.wellknown.replace("https://", "").replace("http://", "");
|
||||||
|
span.classList.add("serverURL");
|
||||||
|
userDiv.append(span);
|
||||||
|
|
||||||
|
userinfo.append(userDiv);
|
||||||
|
table.append(userinfo);
|
||||||
|
|
||||||
|
userinfo.addEventListener("click", () => {
|
||||||
|
const search = new URLSearchParams();
|
||||||
|
search.set("templateID", code);
|
||||||
|
sessionStorage.setItem("currentuser", user.uid);
|
||||||
|
window.location.assign("/channels/@me?" + search);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!joinable.length) {
|
||||||
|
const l = new URLSearchParams("?");
|
||||||
|
l.set("goback", window.location.href);
|
||||||
|
l.set("instance", well!);
|
||||||
|
window.location.href = "/login?" + l.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
table.classList.add("flexttb", "accountSwitcher");
|
||||||
|
console.log(table);
|
||||||
|
document.body.append(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById("usetemplate")!.addEventListener("click", showAccounts);
|
||||||
|
document.getElementById("usetemplate")!.textContent = I18n.useTemplateButton();
|
||||||
|
})();
|
|
@ -230,6 +230,8 @@
|
||||||
"box3title": "Contribute to Jank Client",
|
"box3title": "Contribute to Jank Client",
|
||||||
"box3description": "We always appreciate some help, whether that be in the form of bug reports, or code, or even just pointing out some typos."
|
"box3description": "We always appreciate some help, whether that be in the form of bug reports, or code, or even just pointing out some typos."
|
||||||
},
|
},
|
||||||
|
"useTemplate": "Use $1 as a template",
|
||||||
|
"useTemplateButton": "Use Template",
|
||||||
"register": {
|
"register": {
|
||||||
"passwordError:": "Password: $1",
|
"passwordError:": "Password: $1",
|
||||||
"usernameError": "Username: $1",
|
"usernameError": "Username: $1",
|
||||||
|
@ -244,7 +246,21 @@
|
||||||
"goThereTrust": "Go there and trust in the future",
|
"goThereTrust": "Go there and trust in the future",
|
||||||
"nevermind": "Nevermind",
|
"nevermind": "Nevermind",
|
||||||
"submit": "submit",
|
"submit": "submit",
|
||||||
|
"edit": "Edit",
|
||||||
"guild": {
|
"guild": {
|
||||||
|
"template": "Template:",
|
||||||
|
"viewTemplate": "View Template",
|
||||||
|
"createFromTemplate": "Create From Template",
|
||||||
|
"tempUseCount": "Template has been used $1 {{PLURAL:$1|time|times}}",
|
||||||
|
"tempCreatedBy": "Template created by:",
|
||||||
|
"editingTemplate": "Editing $1",
|
||||||
|
"createNewTemplate": "Create New Template",
|
||||||
|
"templates": "Templates",
|
||||||
|
"templateName": "Template Name:",
|
||||||
|
"templateDesc": "Template Description:",
|
||||||
|
"templcateMetaDesc": "A template allows others to use this guild as a base for their own guilds, it'll copy the channels, roles, and settings of this guild, but not the messages from within the guild, the bots, or the guilds icon.",
|
||||||
|
"templateNameShort": "Template name must at least be 2 characters long",
|
||||||
|
"templateURL": "Template URL: $1",
|
||||||
"bannedBy": "Banned by:",
|
"bannedBy": "Banned by:",
|
||||||
"banReason": "Ban reason: $1",
|
"banReason": "Ban reason: $1",
|
||||||
"bans": "Bans",
|
"bans": "Bans",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue