further translation support

A few more things need to be done, but it's getting a lot closer
This commit is contained in:
MathMan05 2024-11-01 12:16:47 -05:00
parent 4e7d181a14
commit 00c105db28
10 changed files with 194 additions and 106 deletions

View file

@ -36,7 +36,7 @@ class I18n{
for(const json of this.translations){ for(const json of this.translations){
let jsont:string|translation=json; let jsont:string|translation=json;
for(const thing of path){ for(const thing of path){
if(typeof jsont !== "string" ){ if(typeof jsont !== "string" && jsont!==undefined){
jsont=jsont[thing]; jsont=jsont[thing];
}else{ }else{

View file

@ -953,7 +953,7 @@ class Localuser{
content.innerHTML = ""; content.innerHTML = "";
const title = document.createElement("h2"); const title = document.createElement("h2");
title.textContent = I18n.getTranslation("guild.disoveryTitle"); title.textContent = I18n.getTranslation("guild.disoveryTitle",json.guilds.length+"");
content.appendChild(title); content.appendChild(title);
const guilds = document.createElement("div"); const guilds = document.createElement("div");
@ -1365,7 +1365,7 @@ class Localuser{
); );
form.addTextInput(I18n.getTranslation("lcoaluser.newDiscriminator"), "discriminator"); form.addTextInput(I18n.getTranslation("lcoaluser.newDiscriminator"), "discriminator");
}); });
security.addButtonInput("", I18n.getTranslation("lcoaluser.changeEmail"), ()=>{ security.addButtonInput("", I18n.getTranslation("localuser.changeEmail"), ()=>{
const form = security.addSubForm( const form = security.addSubForm(
I18n.getTranslation("lcoaluser.changeEmail"), I18n.getTranslation("lcoaluser.changeEmail"),
_=>{ _=>{
@ -1401,9 +1401,9 @@ class Localuser{
} }
form.addTextInput(I18n.getTranslation("localuser.newUsername"), "username"); form.addTextInput(I18n.getTranslation("localuser.newUsername"), "username");
}); });
security.addButtonInput("", "Change password", ()=>{ security.addButtonInput("", I18n.getTranslation("localuser.changePassword"), ()=>{
const form = security.addSubForm( const form = security.addSubForm(
"Change Password", I18n.getTranslation("localuser.changePassword"),
_=>{ _=>{
security.returnFromSub(); security.returnFromSub();
}, },
@ -1413,13 +1413,13 @@ class Localuser{
method: "PATCH", method: "PATCH",
} }
); );
form.addTextInput("Old password:", "password", { password: true }); form.addTextInput(I18n.getTranslation("localuser.oldPassword:"), "password", { password: true });
if(this.mfa_enabled){ if(this.mfa_enabled){
form.addTextInput("Code:", "code"); form.addTextInput(I18n.getTranslation("localuser.2faCode"), "code");
} }
let in1 = ""; let in1 = "";
let in2 = ""; let in2 = "";
form.addTextInput("New password:", "").watchForChange(text=>{ form.addTextInput(I18n.getTranslation("localuser.newPassword:"), "").watchForChange(text=>{
in1 = text; in1 = text;
}); });
const copy = form.addTextInput("New password again:", ""); const copy = form.addTextInput("New password again:", "");
@ -1430,7 +1430,7 @@ class Localuser{
if(in1 === in2){ if(in1 === in2){
return in1; return in1;
}else{ }else{
throw new FormError(copy, "Passwords don't match"); throw new FormError(copy, I18n.getTranslation("localuser.PasswordsNoMatch"));
} }
}); });
}); });
@ -1473,8 +1473,7 @@ class Localuser{
}); });
}else{ }else{
container.classList.add("disabled"); container.classList.add("disabled");
container.title = container.title = I18n.getTranslation("localuser.PasswordsNoMatch");
"This connection has been disabled server-side.";
} }
connectionContainer.appendChild(container); connectionContainer.appendChild(container);
@ -1483,16 +1482,16 @@ class Localuser{
connections.addHTMLArea(connectionContainer); connections.addHTMLArea(connectionContainer);
} }
{ {
const devPortal = settings.addButton("Developer Portal"); const devPortal = settings.addButton(I18n.getTranslation("localuser.devPortal"));
fetch(this.info.api + "/teams", { fetch(this.info.api + "/teams", {
headers: this.headers, headers: this.headers,
}).then(async (teamsRes)=>{ }).then(async (teamsRes)=>{
const teams = await teamsRes.json(); const teams = await teamsRes.json();
devPortal.addButtonInput("", "Create application", ()=>{ devPortal.addButtonInput("", I18n.getTranslation("localuser.createApp"), ()=>{
const form = devPortal.addSubForm( const form = devPortal.addSubForm(
"Create application", I18n.getTranslation("localuser.createApp"),
(json: any)=>{ (json: any)=>{
if(json.message) form.error("name", json.message); if(json.message) form.error("name", json.message);
else{ else{
@ -1509,7 +1508,7 @@ class Localuser{
form.addTextInput("Name:", "name", { required: true }); form.addTextInput("Name:", "name", { required: true });
form.addSelect( form.addSelect(
"Team:", I18n.getTranslation("localuser.team:"),
"team_id", "team_id",
["Personal", ...teams.map((team: { name: string })=>team.name)], ["Personal", ...teams.map((team: { name: string })=>team.name)],
{ {
@ -1583,16 +1582,16 @@ class Localuser{
headers:this.headers, headers:this.headers,
traditionalSubmit:true traditionalSubmit:true
}); });
form.addTextInput("Application name:","name",{initText:json.name}); form.addTextInput(I18n.getTranslation("localuser.appName"),"name",{initText:json.name});
form.addMDInput("Description:","description",{initText:json.description}); form.addMDInput(I18n.getTranslation("localuser.description"),"description",{initText:json.description});
form.addFileInput("Icon:","icon"); form.addFileInput("Icon:","icon");
form.addTextInput("Privacy policy URL:","privacy_policy_url",{initText:json.privacy_policy_url}); form.addTextInput(I18n.getTranslation("localuser.privacyPolcyURL"),"privacy_policy_url",{initText:json.privacy_policy_url});
form.addTextInput("Terms of Service URL:","terms_of_service_url",{initText:json.terms_of_service_url}); form.addTextInput(I18n.getTranslation("localuser.TOSURL"),"terms_of_service_url",{initText:json.terms_of_service_url});
form.addCheckboxInput("Make bot publicly inviteable?","bot_public",{initState:json.bot_public}); form.addCheckboxInput(I18n.getTranslation("localuser.publicAvaliable"),"bot_public",{initState:json.bot_public});
form.addCheckboxInput("Require code grant to invite the bot?","bot_require_code_grant",{initState:json.bot_require_code_grant}); form.addCheckboxInput(I18n.getTranslation("localuser.requireCode"),"bot_require_code_grant",{initState:json.bot_require_code_grant});
form.addButtonInput("",(json.bot ? "Manage" : "Add")+" bot",async ()=>{ form.addButtonInput("",I18n.getTranslation("localuser."+(json.bot?"manageBot":"addBot")),async ()=>{
if(!json.bot){ if(!json.bot){
if(!confirm("Are you sure you want to add a bot to this application? There's no going back.")){ if(!confirm(I18n.getTranslation("localuser.confirmAddBot"))){
return; return;
} }
const updateRes = await fetch( const updateRes = await fetch(
@ -1614,19 +1613,19 @@ class Localuser{
}); });
const json = await res.json(); const json = await res.json();
if(!json.bot){ if(!json.bot){
return alert("For some reason, this application doesn't have a bot (yet)."); return alert(I18n.getTranslation("localuser.confuseNoBot"));
} }
const bot:mainuserjson=json.bot; const bot:mainuserjson=json.bot;
const form=container.addSubForm("Editing bot "+bot.username,out=>{console.log(out)},{ const form=container.addSubForm(I18n.getTranslation("localuser.editingBot",bot.username),out=>{console.log(out)},{
method:"PATCH", method:"PATCH",
fetchURL:this.info.api + "/applications/" + appId + "/bot", fetchURL:this.info.api + "/applications/" + appId + "/bot",
headers:this.headers, headers:this.headers,
traditionalSubmit:true traditionalSubmit:true
}); });
form.addTextInput("Bot username:","username",{initText:bot.username}); form.addTextInput(I18n.getTranslation("localuser.botUsername"),"username",{initText:bot.username});
form.addFileInput("Bot avatar:","avatar"); form.addFileInput(I18n.getTranslation("localuser.botAvatar"),"avatar");
form.addButtonInput("","Reset Token",async ()=>{ form.addButtonInput("",I18n.getTranslation("localuser.resetToken"),async ()=>{
if(!confirm("Are you sure you want to reset the bot token? Your bot will stop working until you update it.")){ if(!confirm(I18n.getTranslation("localuser.confirmReset"))){
return; return;
} }
const updateRes = await fetch( const updateRes = await fetch(
@ -1637,27 +1636,27 @@ class Localuser{
} }
); );
const updateJSON = await updateRes.json(); const updateJSON = await updateRes.json();
text.setText("Token: "+updateJSON.token); text.setText(I18n.getTranslation("localuser.tokenDisplay",updateJSON.token));
this.botTokens.set(appId,updateJSON.token); this.botTokens.set(appId,updateJSON.token);
if(this.perminfo.applications[appId]){ if(this.perminfo.applications[appId]){
this.perminfo.applications[appId]=updateJSON.token; this.perminfo.applications[appId]=updateJSON.token;
this.userinfo.updateLocal(); this.userinfo.updateLocal();
} }
}); });
const text=form.addText(this.botTokens.has(appId)?"Token: "+this.botTokens.get(appId):"Token: *****************"); const text=form.addText(I18n.getTranslation("localuser.tokenDisplay",this.botTokens.has(appId)?this.botTokens.get(appId) as string:"*****************") );
const check=form.addOptions("",{noSubmit:true}); const check=form.addOptions("",{noSubmit:true});
if(!this.perminfo.applications){ if(!this.perminfo.applications){
this.perminfo.applications={}; this.perminfo.applications={};
this.userinfo.updateLocal(); this.userinfo.updateLocal();
} }
const checkbox=check.addCheckboxInput("Save token to localStorage",()=>{},{initState:!!this.perminfo.applications[appId]}); const checkbox=check.addCheckboxInput(I18n.getTranslation("localuser.saveToken"),()=>{},{initState:!!this.perminfo.applications[appId]});
checkbox.watchForChange(_=>{ checkbox.watchForChange(_=>{
if(_){ if(_){
if(this.botTokens.has(appId)){ if(this.botTokens.has(appId)){
this.perminfo.applications[appId]=this.botTokens.get(appId); this.perminfo.applications[appId]=this.botTokens.get(appId);
this.userinfo.updateLocal(); this.userinfo.updateLocal();
}else{ }else{
alert("Don't know token so can't save it to localStorage, sorry"); alert(I18n.getTranslation("localuser.noToken"));
checkbox.setState(false); checkbox.setState(false);
} }
}else{ }else{
@ -1665,14 +1664,14 @@ class Localuser{
this.userinfo.updateLocal(); this.userinfo.updateLocal();
} }
}); });
form.addButtonInput("","Advanced Bot Settings",()=>{ form.addButtonInput("",I18n.getTranslation("localuser.advancedBot"),()=>{
const token=this.botTokens.get(appId); const token=this.botTokens.get(appId);
if(token){ if(token){
const botc=new Bot(bot,token,this); const botc=new Bot(bot,token,this);
botc.settings(); botc.settings();
} }
}); });
form.addButtonInput("","Bot Invite Creator",()=>{ form.addButtonInput("",I18n.getTranslation("localuser.botInviteCreate"),()=>{
Bot.InviteMaker(appId,form,this.info); Bot.InviteMaker(appId,form,this.info);
}) })
} }
@ -1849,11 +1848,11 @@ class Localuser{
const dialog = new Dialog([ const dialog = new Dialog([
"vdiv", "vdiv",
["title", "Instance stats: " + this.instancePing.name], ["title", I18n.getTranslation("instanceStats.name",this.instancePing.name) ],
["text", "Registered users: " + json.counts.user], ["text", I18n.getTranslation("instanceStats.users",json.counts.user)],
["text", "Servers: " + json.counts.guild], ["text", I18n.getTranslation("instanceStats.servers",json.counts.guild)],
["text", "Messages: " + json.counts.message], ["text", I18n.getTranslation("instanceStats.messages",json.counts.message)],
["text", "Members: " + json.counts.members], ["text", I18n.getTranslation("instanceStats.members",json.counts.members)],
]); ]);
dialog.show(); dialog.show();
} }

View file

@ -1,4 +1,5 @@
import{ Dialog }from"./dialog.js"; import{ Dialog }from"./dialog.js";
import { I18n } from "./i18n.js";
const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent); const mobile = /iPhone|iPad|iPod|Android/i.test(navigator.userAgent);
const iOS = /iPhone|iPad|iPod/i.test(navigator.userAgent); const iOS = /iPhone|iPad|iPod/i.test(navigator.userAgent);
@ -338,7 +339,7 @@ async function getapiurls(str: string): Promise<
async function checkInstance(instance?: string){ async function checkInstance(instance?: string){
const verify = document.getElementById("verify"); const verify = document.getElementById("verify");
try{ try{
verify!.textContent = "Checking Instance"; verify!.textContent = I18n.getTranslation("login.checking");
const instanceValue = instance || (instancein as HTMLInputElement).value; const instanceValue = instance || (instancein as HTMLInputElement).value;
const instanceinfo = (await getapiurls(instanceValue)) as { const instanceinfo = (await getapiurls(instanceValue)) as {
wellknown: string; wellknown: string;
@ -351,7 +352,7 @@ async function checkInstance(instance?: string){
if(instanceinfo){ if(instanceinfo){
instanceinfo.value = instanceValue; instanceinfo.value = instanceValue;
localStorage.setItem("instanceinfo", JSON.stringify(instanceinfo)); localStorage.setItem("instanceinfo", JSON.stringify(instanceinfo));
verify!.textContent = "Instance is all good"; verify!.textContent = I18n.getTranslation("login.allGood");
// @ts-ignore // @ts-ignore
if(checkInstance.alt){ if(checkInstance.alt){
// @ts-ignore // @ts-ignore
@ -362,11 +363,11 @@ async function checkInstance(instance?: string){
verify!.textContent = ""; verify!.textContent = "";
}, 3000); }, 3000);
}else{ }else{
verify!.textContent = "Invalid Instance, try again"; verify!.textContent = I18n.getTranslation("login.invalid");
} }
}catch{ }catch{
console.log("catch"); console.log("catch");
verify!.textContent = "Invalid Instance, try again"; verify!.textContent = I18n.getTranslation("login.invalid");
} }
} }
@ -374,7 +375,7 @@ if(instancein){
console.log(instancein); console.log(instancein);
instancein.addEventListener("keydown", ()=>{ instancein.addEventListener("keydown", ()=>{
const verify = document.getElementById("verify"); const verify = document.getElementById("verify");
verify!.textContent = "Waiting to check Instance"; verify!.textContent = I18n.getTranslation("login.waiting");
if(timeout !== null && typeof timeout !== "string"){ if(timeout !== null && typeof timeout !== "string"){
clearTimeout(timeout); clearTimeout(timeout);
} }
@ -442,7 +443,7 @@ async function login(username: string, password: string, captcha: string){
let onetimecode = ""; let onetimecode = "";
new Dialog([ new Dialog([
"vdiv", "vdiv",
["title", "2FA code:"], ["title", I18n.getTranslation("2faCode")],
[ [
"textbox", "textbox",
"", "",
@ -455,7 +456,7 @@ async function login(username: string, password: string, captcha: string){
[ [
"button", "button",
"", "",
"Submit", I18n.getTranslation("submit"),
function(){ function(){
fetch(api + "/auth/mfa/totp", { fetch(api + "/auth/mfa/totp", {
method: "POST", method: "POST",

View file

@ -2,6 +2,7 @@ import{ Channel }from"./channel.js";
import{ Dialog }from"./dialog.js"; import{ Dialog }from"./dialog.js";
import{ Emoji }from"./emoji.js"; import{ Emoji }from"./emoji.js";
import{ Guild }from"./guild.js"; import{ Guild }from"./guild.js";
import { I18n } from "./i18n.js";
import{ Localuser }from"./localuser.js"; import{ Localuser }from"./localuser.js";
import{ Member }from"./member.js"; import{ Member }from"./member.js";
@ -9,8 +10,8 @@ class MarkDown{
txt: string[]; txt: string[];
keep: boolean; keep: boolean;
stdsize: boolean; stdsize: boolean;
owner: Localuser | Channel; owner: Localuser | Channel|void;
info: Localuser["info"]; info: Localuser["info"]|void=undefined;
constructor( constructor(
text: string | string[], text: string | string[],
owner: MarkDown["owner"], owner: MarkDown["owner"],
@ -24,7 +25,9 @@ class MarkDown{
if(this.txt === undefined){ if(this.txt === undefined){
this.txt = []; this.txt = [];
} }
this.info = owner.info; if(owner){
this.info = owner.info;
}
this.keep = keep; this.keep = keep;
this.owner = owner; this.owner = owner;
this.stdsize = stdsize; this.stdsize = stdsize;
@ -32,9 +35,10 @@ class MarkDown{
get localuser(){ get localuser(){
if(this.owner instanceof Localuser){ if(this.owner instanceof Localuser){
return this.owner; return this.owner;
}else{ }else if(this.owner){
return this.owner.localuser; return this.owner.localuser;
} }
return null;
} }
get rawString(){ get rawString(){
return this.txt.join(""); return this.txt.join("");
@ -437,7 +441,7 @@ txt[j + 1] === undefined)
continue; continue;
} }
} }
if(txt[i] === "<" && (txt[i + 1] === "@" || txt[i + 1] === "#")){ if((txt[i] === "<" && (txt[i + 1] === "@" || txt[i + 1] === "#"))&&this.localuser){
let id = ""; let id = "";
let j = i + 2; let j = i + 2;
const numbers = new Set(["0","1","2","3","4","5","6","7","8","9",]); const numbers = new Set(["0","1","2","3","4","5","6","7","8","9",]);
@ -485,6 +489,7 @@ txt[j + 1] === undefined)
mention.textContent = `#${channel.name}`; mention.textContent = `#${channel.name}`;
if(!keep){ if(!keep){
mention.onclick = _=>{ mention.onclick = _=>{
if(!this.localuser) return;
this.localuser.goToChannel(id); this.localuser.goToChannel(id);
}; };
} }
@ -586,7 +591,7 @@ txt[j + 1] === undefined)
if( if(
txt[i] === "<" && txt[i] === "<" &&
(txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":")) (txt[i + 1] === ":" || (txt[i + 1] === "a" && txt[i + 2] === ":")&&this.owner)
){ ){
let found = false; let found = false;
const build = txt[i + 1] === "a" ? ["<", "a", ":"] : ["<", ":"]; const build = txt[i + 1] === "a" ? ["<", "a", ":"] : ["<", ":"];
@ -609,6 +614,7 @@ txt[j + 1] === undefined)
const isEmojiOnly = txt.join("").trim() === buildjoin.trim(); const isEmojiOnly = txt.join("").trim() === buildjoin.trim();
const owner = const owner =
this.owner instanceof Channel ? this.owner.guild : this.owner; this.owner instanceof Channel ? this.owner.guild : this.owner;
if(!owner) continue;
const emoji = new Emoji( const emoji = new Emoji(
{ name: buildjoin, id: parts[2], animated: Boolean(parts[1]) }, { name: buildjoin, id: parts[2], animated: Boolean(parts[1]) },
owner owner
@ -765,20 +771,18 @@ txt[j + 1] === undefined)
}else{ }else{
const full: Dialog = new Dialog([ const full: Dialog = new Dialog([
"vdiv", "vdiv",
["title", "You're leaving Spacebar"], ["title", I18n.getTranslation("leaving")],
[ [
"text", "text",
"You're going to " + I18n.getTranslation("goingToURL",Url.host)
Url.host +
". Are you sure you want to go there?",
], ],
[ [
"hdiv", "hdiv",
["button", "", "Nevermind", (_: any)=>full.hide()], ["button", "", I18n.getTranslation("nevermind"), (_: any)=>full.hide()],
[ [
"button", "button",
"", "",
"Go there", I18n.getTranslation("goThere"),
(_: any)=>{ (_: any)=>{
open(); open();
full.hide(); full.hide();
@ -787,7 +791,7 @@ txt[j + 1] === undefined)
[ [
"button", "button",
"", "",
"Go there and trust in the future", I18n.getTranslation("goThereTrust"),
(_: any)=>{ (_: any)=>{
open(); open();
full.hide(); full.hide();

View file

@ -4,6 +4,7 @@ import{ Guild }from"./guild.js";
import{ SnowFlake }from"./snowflake.js"; import{ SnowFlake }from"./snowflake.js";
import{ memberjson, presencejson }from"./jsontypes.js"; import{ memberjson, presencejson }from"./jsontypes.js";
import{ Dialog }from"./dialog.js"; import{ Dialog }from"./dialog.js";
import { I18n } from "./i18n.js";
class Member extends SnowFlake{ class Member extends SnowFlake{
static already = {}; static already = {};
@ -213,10 +214,10 @@ class Member extends SnowFlake{
let reason = ""; let reason = "";
const menu = new Dialog([ const menu = new Dialog([
"vdiv", "vdiv",
["title", "Kick " + this.name + " from " + this.guild.properties.name], ["title", I18n.getTranslation("member.kick",this.name,this.guild.properties.name)],
[ [
"textbox", "textbox",
"Reason:", I18n.getTranslation("member.reason:"),
"", "",
function(e: Event){ function(e: Event){
reason = (e.target as HTMLInputElement).value; reason = (e.target as HTMLInputElement).value;
@ -225,7 +226,7 @@ class Member extends SnowFlake{
[ [
"button", "button",
"", "",
"submit", I18n.getTranslation("submit"),
()=>{ ()=>{
this.kickAPI(reason); this.kickAPI(reason);
menu.hide(); menu.hide();
@ -246,10 +247,10 @@ class Member extends SnowFlake{
let reason = ""; let reason = "";
const menu = new Dialog([ const menu = new Dialog([
"vdiv", "vdiv",
["title", "Ban " + this.name + " from " + this.guild.properties.name], ["title", I18n.getTranslation("member.ban",this.name,this.guild.properties.name)],
[ [
"textbox", "textbox",
"Reason:", I18n.getTranslation("member.reason",this.name,this.guild.properties.name),
"", "",
function(e: Event){ function(e: Event){
reason = (e.target as HTMLInputElement).value; reason = (e.target as HTMLInputElement).value;
@ -258,7 +259,7 @@ class Member extends SnowFlake{
[ [
"button", "button",
"", "",
"submit", I18n.getTranslation("submit",this.name,this.guild.properties.name),
()=>{ ()=>{
this.banAPI(reason); this.banAPI(reason);
menu.hide(); menu.hide();

View file

@ -1,4 +1,6 @@
import { I18n } from "./i18n.js";
import{ checkInstance, adduser }from"./login.js"; import{ checkInstance, adduser }from"./login.js";
import { MarkDown } from "./markdown.js";
const registerElement = document.getElementById("register"); const registerElement = document.getElementById("register");
if(registerElement){ if(registerElement){
@ -18,8 +20,7 @@ async function registertry(e: Event){
const captchaKey = (elements[7] as HTMLInputElement)?.value; const captchaKey = (elements[7] as HTMLInputElement)?.value;
if(password !== confirmPassword){ if(password !== confirmPassword){
(document.getElementById("wrong") as HTMLElement).textContent = (document.getElementById("wrong") as HTMLElement).textContent = I18n.getTranslation("localuser.PasswordsNoMatch");
"Passwords don't match";
return; return;
} }
@ -83,22 +84,22 @@ function handleErrors(errors: any, elements: HTMLFormControlsCollection){
}else if(errors.password){ }else if(errors.password){
showError( showError(
elements[3] as HTMLElement, elements[3] as HTMLElement,
"Password: " + errors.password._errors[0].message I18n.getTranslation("register.passwordError",errors.password._errors[0].message)
); );
}else if(errors.username){ }else if(errors.username){
showError( showError(
elements[2] as HTMLElement, elements[2] as HTMLElement,
"Username: " + errors.username._errors[0].message I18n.getTranslation("register.usernameError",errors.username._errors[0].message)
); );
}else if(errors.email){ }else if(errors.email){
showError( showError(
elements[1] as HTMLElement, elements[1] as HTMLElement,
"Email: " + errors.email._errors[0].message I18n.getTranslation("register.emailError",errors.email._errors[0].message)
); );
}else if(errors.date_of_birth){ }else if(errors.date_of_birth){
showError( showError(
elements[5] as HTMLElement, elements[5] as HTMLElement,
"Date of Birth: " + errors.date_of_birth._errors[0].message I18n.getTranslation("register.DOBError",errors.date_of_birth._errors[0].message)
); );
}else{ }else{
(document.getElementById("wrong") as HTMLElement).textContent = (document.getElementById("wrong") as HTMLElement).textContent =
@ -125,8 +126,6 @@ function showError(element: HTMLElement, message: string){
errorElement.textContent = message; errorElement.textContent = message;
} }
let TOSa = document.getElementById("TOSa") as HTMLAnchorElement | null;
async function tosLogic(){ async function tosLogic(){
const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}"); const instanceInfo = JSON.parse(localStorage.getItem("instanceinfo") ?? "{}");
const apiurl = new URL(instanceInfo.api); const apiurl = new URL(instanceInfo.api);
@ -136,14 +135,12 @@ async function tosLogic(){
const tosPage = data.instance.tosPage; const tosPage = data.instance.tosPage;
if(tosPage){ if(tosPage){
document.getElementById("TOSbox")!.innerHTML = const box=document.getElementById("TOSbox");
"I agree to the <a href=\"\" id=\"TOSa\">Terms of Service</a>:"; if(!box) return;
TOSa = document.getElementById("TOSa") as HTMLAnchorElement; box.innerHTML ="";
TOSa.href = tosPage; box.append(new MarkDown(I18n.getTranslation("register.agreeTOS",tosPage)).makeHTML());
}else{ }else{
document.getElementById("TOSbox")!.textContent = document.getElementById("TOSbox")!.textContent =I18n.getTranslation("register.noTOS");
"This instance has no Terms of Service, accept ToS anyways:";
TOSa = null;
} }
console.log(tosPage); console.log(tosPage);
} }

View file

@ -142,6 +142,7 @@ class PermissionToggle implements OptionsElement<number>{
import{ OptionsElement, Buttons }from"./settings.js"; import{ OptionsElement, Buttons }from"./settings.js";
import { Contextmenu } from "./contextmenu.js"; import { Contextmenu } from "./contextmenu.js";
import { Channel } from "./channel.js"; import { Channel } from "./channel.js";
import { I18n } from "./i18n.js";
class RoleList extends Buttons{ class RoleList extends Buttons{
permissions: [Role, Permissions][]; permissions: [Role, Permissions][];
permission: Permissions; permission: Permissions;
@ -204,26 +205,26 @@ class RoleList extends Buttons{
this.redoButtons(); this.redoButtons();
} }
makeguildmenus(option:Options){ makeguildmenus(option:Options){
option.addButtonInput("","Display settings",()=>{ option.addButtonInput("",I18n.getTranslation("role.displaySettings"),()=>{
const role=this.guild.roleids.get(this.curid as string); const role=this.guild.roleids.get(this.curid as string);
if(!role) return; if(!role) return;
const form=option.addSubForm("Display settings",()=>{},{ const form=option.addSubForm(I18n.getTranslation("role.displaySettings"),()=>{},{
fetchURL:this.info.api+"/guilds/"+this.guild.id+"/roles/"+this.curid, fetchURL:this.info.api+"/guilds/"+this.guild.id+"/roles/"+this.curid,
method:"PATCH", method:"PATCH",
headers:this.headers, headers:this.headers,
traditionalSubmit:true traditionalSubmit:true
}); });
form.addTextInput("Role Name:","name",{ form.addTextInput(I18n.getTranslation("role.name"),"name",{
initText:role.name initText:role.name
}); });
form.addCheckboxInput("Hoisted:","hoist",{ form.addCheckboxInput(I18n.getTranslation("role.hoisted"),"hoist",{
initState:role.hoist initState:role.hoist
}); });
form.addCheckboxInput("Allow anyone to ping this role:","mentionable",{ form.addCheckboxInput(I18n.getTranslation("role.mentionable"),"mentionable",{
initState:role.mentionable initState:role.mentionable
}); });
const color="#"+role.color.toString(16).padStart(6,"0"); const color="#"+role.color.toString(16).padStart(6,"0");
form.addColorInput("Color","color",{ form.addColorInput(I18n.getTranslation("role.color"),"color",{
initColor:color initColor:color
}); });
form.addPreprocessor((obj:any)=>{ form.addPreprocessor((obj:any)=>{
@ -236,7 +237,7 @@ class RoleList extends Buttons{
static guildrolemenu=this.GuildRoleMenu(); static guildrolemenu=this.GuildRoleMenu();
private static ChannelRoleMenu(){ private static ChannelRoleMenu(){
const menu=new Contextmenu<RoleList,Role>("role settings"); const menu=new Contextmenu<RoleList,Role>("role settings");
menu.addbutton("Remove role",function(role){ menu.addbutton(()=>I18n.getTranslation("role.remove"),function(role){
if(!this.channel) return; if(!this.channel) return;
console.log(role); console.log(role);
fetch(this.info.api+"/channels/"+this.channel.id+"/permissions/"+role.id,{ fetch(this.info.api+"/channels/"+this.channel.id+"/permissions/"+role.id,{
@ -248,8 +249,8 @@ class RoleList extends Buttons{
} }
private static GuildRoleMenu(){ private static GuildRoleMenu(){
const menu=new Contextmenu<RoleList,Role>("role settings"); const menu=new Contextmenu<RoleList,Role>("role settings");
menu.addbutton("Delete Role",function(role){ menu.addbutton(()=>I18n.getTranslation("role.delete"),function(role){
if(!confirm("Are you sure you want to delete "+role.name+"?")) return; if(!confirm(I18n.getTranslation("role.confirmDelete"))) return;
console.log(role); console.log(role);
fetch(this.info.api+"/guilds/"+this.guild.id+"/roles/"+role.id,{ fetch(this.info.api+"/guilds/"+this.guild.id+"/roles/"+role.id,{
method:"DELETE", method:"DELETE",

View file

@ -1,3 +1,5 @@
import { I18n } from "./i18n.js";
interface OptionsElement<x> { interface OptionsElement<x> {
// //
generateHTML(): HTMLElement; generateHTML(): HTMLElement;
@ -828,9 +830,9 @@ class Options implements OptionsElement<void>{
div.classList.add("flexltr", "savediv"); div.classList.add("flexltr", "savediv");
const span = document.createElement("span"); const span = document.createElement("span");
div.append(span); div.append(span);
span.textContent = "Careful, you have unsaved changes"; span.textContent = I18n.getTranslation("settings.unsaved");
const button = document.createElement("button"); const button = document.createElement("button");
button.textContent = "Save changes"; button.textContent = I18n.getTranslation("settings.save");
div.append(button); div.append(button);
this.haschanged = true; this.haschanged = true;
this.owner.changed(div); this.owner.changed(div);
@ -886,7 +888,7 @@ class Form implements OptionsElement<object>{
onSubmit: (arg1: object) => void, onSubmit: (arg1: object) => void,
{ {
ltr = false, ltr = false,
submitText = "Submit", submitText = I18n.getTranslation("submit"),
fetchURL = "", fetchURL = "",
headers = {}, headers = {},
method = "POST", method = "POST",
@ -919,7 +921,7 @@ class Form implements OptionsElement<object>{
onSubmit: (arg1: object) => void, onSubmit: (arg1: object) => void,
{ {
ltr = false, ltr = false,
submitText = "Submit", submitText = I18n.getTranslation("submit"),
fetchURL = "", fetchURL = "",
headers = {}, headers = {},
method = "POST", method = "POST",

View file

@ -161,6 +161,19 @@
"uptimeStats":"Uptime: \n All time: $1\nThis week: $2\nToday: $3", "uptimeStats":"Uptime: \n All time: $1\nThis week: $2\nToday: $3",
"warnOffiline":"Instance is offline, can't connect" "warnOffiline":"Instance is offline, can't connect"
}, },
"register":{
"passwordError:":"Password: $1",
"usernameError":"Username: $1",
"emailError":"Email: $1",
"DOBError":"Date of Birth: $1",
"agreeTOS":"I agree to the [Terms of Service]($1):",
"noTOS":"This instance has no Terms of Service, accept ToS anyways:"
},
"leaving":"You're leaving Spacebar",
"goingToURL":"You're going to $1. Are you sure you want to go there?",
"goThere":"Go there",
"goThereTrust":"Go there and trust in the future",
"nevermind":"Nevermind",
"submit":"submit", "submit":"submit",
"guild":{ "guild":{
"copyId":"Copy guild id", "copyId":"Copy guild id",
@ -191,7 +204,21 @@
"noDelete":"Nevermind", "noDelete":"Nevermind",
"create":"Create guild", "create":"Create guild",
"loadingDiscovery":"Loading...", "loadingDiscovery":"Loading...",
"disoveryTitle":"Guild discovery ($1) {{PLURAL:$1|entrie|entries}}" "disoveryTitle":"Guild discovery ($1) {{PLURAL:$1|entry|entries}}"
},
"role":{
"displaySettings":"Display settings",
"name":"Role name:",
"hoisted":"Hoisted:",
"mentionable":"Allow anyone to ping this role:",
"color":"Color",
"remove":"Remove role",
"delete":"Delete Role",
"confirmDelete":"Are you sure you want to delete $1?"
},
"settings":{
"unsaved":"Careful, you have unsaved changes",
"save":"Save changes"
}, },
"localuser":{ "localuser":{
"settings":"Settings", "settings":"Settings",
@ -224,7 +251,42 @@
"password:":"Password", "password:":"Password",
"newEmail:":"New email", "newEmail:":"New email",
"changeUsername":"Change username", "changeUsername":"Change username",
"newUsername":"New username:" "newUsername":"New username:",
"changePassword":"Change password",
"oldPassword:":"Old password:",
"newPassword:":"New password:",
"PasswordsNoMatch":"Password don't match",
"disableConnection":"This connection has been disabled server-side",
"devPortal":"Developer Portal",
"createApp":"Create application",
"team:":"Team:",
"appName":"Application name:",
"description":"Description:",
"privacyPolcyURL":"Privacy policy URL:",
"TOSURL":"Terms of Service URL:",
"publicAvaliable":"Make bot publicly inviteable?",
"requireCode":"Require code grant to invite the bot?",
"manageBot":"Manage bot",
"addBot":"Add bot",
"confirmAddBot":"Are you sure you want to add a bot to this application? There's no going back.",
"confuseNoBot":"For some reason, this application doesn't have a bot (yet).",
"editingBot":"Editing bot $1",
"botUsername":"Bot username:",
"botAvatar":"Bot avatar:",
"resetToken":"Reset Token",
"confirmReset":"Are you sure you want to reset the bot token? Your bot will stop working until you update it.",
"tokenDisplay":"Token: $1",
"saveToken":"Save token to localStorage",
"noToken":"Don't know token so can't save it to localStorage, sorry",
"advancedBot":"Advanced Bot Settings",
"botInviteCreate":"Bot Invite Creator"
},
"instanceStats":{
"name":"Instance stats: $1",
"users":"Registered users: $1",
"servers":"Servers: $1",
"messages":"Messages: $1",
"members":"Members: $1"
}, },
"inviteOptions":{ "inviteOptions":{
"title":"Invite People", "title":"Invite People",
@ -239,6 +301,7 @@
"limit":"$1 {{PLURAL:$1|use|uses}}", "limit":"$1 {{PLURAL:$1|use|uses}}",
"noLimit":"No limit" "noLimit":"No limit"
}, },
"2faCode":"2FA code:",
"invite":{ "invite":{
"invitedBy":"You've been invited by $1", "invitedBy":"You've been invited by $1",
"alreadyJoined":"Already joined", "alreadyJoined":"Already joined",
@ -258,7 +321,26 @@
"user":{ "user":{
"copyId":"Copy user ID", "copyId":"Copy user ID",
"online":"Online", "online":"Online",
"offline":"Offline" "offline":"Offline",
"message":"Message user",
"block":"Block user",
"unblock":"unblock user",
"friendReq":"Friend request",
"kick":"Kick member",
"ban":"Ban member",
"addRole":"Add roles",
"removeRole":"Remove roles"
},
"login":{
"checking":"Checking Instance",
"allGood":"All good",
"invalid":"Invalid Instance, try again",
"waiting":"Waiting to check Instance"
},
"member":{
"kick":"Kick $1 from $2",
"reason:":"Reason:",
"ban":"Ban $1 from $2"
}, },
"errorReconnect":"Unable to connect to the server, retrying in <b>$1</b> seconds...", "errorReconnect":"Unable to connect to the server, retrying in <b>$1</b> seconds...",
"retrying":"Retrying...", "retrying":"Retrying...",

View file

@ -7,6 +7,7 @@ import{ SnowFlake }from"./snowflake.js";
import{ presencejson, userjson }from"./jsontypes.js"; import{ presencejson, userjson }from"./jsontypes.js";
import { Role } from "./role.js"; import { Role } from "./role.js";
import { Search } from "./search.js"; import { Search } from "./search.js";
import { I18n } from "./i18n.js";
class User extends SnowFlake{ class User extends SnowFlake{
owner: Localuser; owner: Localuser;
@ -96,10 +97,10 @@ class User extends SnowFlake{
static contextmenu = new Contextmenu<User, Member | undefined>("User Menu"); static contextmenu = new Contextmenu<User, Member | undefined>("User Menu");
static setUpContextMenu(): void{ static setUpContextMenu(): void{
this.contextmenu.addbutton("Copy user id", function(this: User){ this.contextmenu.addbutton(()=>I18n.getTranslation("user.copyId"), function(this: User){
navigator.clipboard.writeText(this.id); navigator.clipboard.writeText(this.id);
}); });
this.contextmenu.addbutton("Message user", function(this: User){ this.contextmenu.addbutton(()=>I18n.getTranslation("user.message"), function(this: User){
fetch(this.info.api + "/users/@me/channels", { fetch(this.info.api + "/users/@me/channels", {
method: "POST", method: "POST",
body: JSON.stringify({ recipients: [this.id] }), body: JSON.stringify({ recipients: [this.id] }),
@ -111,7 +112,7 @@ class User extends SnowFlake{
}); });
}); });
this.contextmenu.addbutton( this.contextmenu.addbutton(
"Block user", ()=>I18n.getTranslation("user.block"),
function(this: User){ function(this: User){
this.block(); this.block();
}, },
@ -122,7 +123,7 @@ class User extends SnowFlake{
); );
this.contextmenu.addbutton( this.contextmenu.addbutton(
"Unblock user", ()=>I18n.getTranslation("user.unblock"),
function(this: User){ function(this: User){
this.unblock(); this.unblock();
}, },
@ -131,7 +132,7 @@ class User extends SnowFlake{
return this.relationshipType === 2; return this.relationshipType === 2;
} }
); );
this.contextmenu.addbutton("Friend request", function(this: User){ this.contextmenu.addbutton(()=>I18n.getTranslation("user.friendReq"), function(this: User){
fetch(`${this.info.api}/users/@me/relationships/${this.id}`, { fetch(`${this.info.api}/users/@me/relationships/${this.id}`, {
method: "PUT", method: "PUT",
headers: this.owner.headers, headers: this.owner.headers,
@ -141,7 +142,7 @@ class User extends SnowFlake{
}); });
}); });
this.contextmenu.addbutton( this.contextmenu.addbutton(
"Kick member", ()=>I18n.getTranslation("user.kick"),
function(this: User, member: Member | undefined){ function(this: User, member: Member | undefined){
member?.kick(); member?.kick();
}, },
@ -159,7 +160,7 @@ class User extends SnowFlake{
} }
); );
this.contextmenu.addbutton( this.contextmenu.addbutton(
"Ban member", ()=>I18n.getTranslation("user.ban"),
function(this: User, member: Member | undefined){ function(this: User, member: Member | undefined){
member?.ban(); member?.ban();
}, },
@ -177,7 +178,7 @@ class User extends SnowFlake{
} }
); );
this.contextmenu.addbutton( this.contextmenu.addbutton(
"Add roles", ()=>I18n.getTranslation("user.addRole"),
async function(this: User, member: Member | undefined,e){ async function(this: User, member: Member | undefined,e){
if(member){ if(member){
e.stopPropagation(); e.stopPropagation();
@ -203,7 +204,7 @@ class User extends SnowFlake{
} }
); );
this.contextmenu.addbutton( this.contextmenu.addbutton(
"Remove roles", ()=>I18n.getTranslation("user.removeRole"),
async function(this: User, member: Member | undefined,e){ async function(this: User, member: Member | undefined,e){
if(member){ if(member){
e.stopPropagation(); e.stopPropagation();