diff --git a/src/webpage/bot.ts b/src/webpage/bot.ts index 64cf641..9d85e4b 100644 --- a/src/webpage/bot.ts +++ b/src/webpage/bot.ts @@ -6,6 +6,7 @@ import { User } from "./user.js"; import {guildjson} from "./jsontypes.js"; import { PermissionToggle } from "./role.js"; import { Permissions } from "./permissions.js"; +import { I18n } from "./i18n.js"; class Bot{ readonly owner:Localuser; readonly token:string; @@ -27,7 +28,7 @@ class Bot{ }; } settings(){ - const settings = new Settings("Bot Settings"); + const settings = new Settings(I18n.getTranslation("botSettings")); const botOptions = settings.addButton("Profile",{ltr:true}); const bot=new User(this.json,this.localuser); { @@ -50,7 +51,7 @@ class Bot{ settingsRight.addHTMLArea(hypotheticalProfile); const finput = settingsLeft.addFileInput( - "Upload pfp:", + I18n.getTranslation("uploadPfp"), _=>{ if(file){ this.updatepfp(file); @@ -76,7 +77,7 @@ class Bot{ }); let bfile: undefined | File | null; const binput = settingsLeft.addFileInput( - "Upload banner:", + I18n.getTranslation("uploadBanner"), _=>{ if(bfile !== undefined){ this.updatebanner(bfile); @@ -102,7 +103,7 @@ class Bot{ }); let changed = false; const pronounbox = settingsLeft.addTextInput( - "Pronouns", + I18n.getTranslation("pronouns"), _=>{ if(newpronouns || newbio || changed){ this.updateProfile({ @@ -119,7 +120,7 @@ class Bot{ newpronouns = _; regen(); }); - const bioBox = settingsLeft.addMDInput("Bio:", _=>{}, { + const bioBox = settingsLeft.addMDInput(I18n.getTranslation("bio"), _=>{}, { initText: bot.bio.rawString, }); bioBox.watchForChange(_=>{ @@ -134,7 +135,7 @@ class Bot{ color = "transparent"; } const colorPicker = settingsLeft.addColorInput( - "Profile color", + I18n.getTranslation("profileColor"), _=>{}, { initColor: color } ); @@ -148,7 +149,7 @@ class Bot{ } { const guildsettings=settings.addButton("Guilds"); - guildsettings.addTitle("Guilds bot is in:"); + guildsettings.addTitle(I18n.getTranslation("botGuilds")); fetch(this.info.api+"/users/@me/guilds/",{ headers:this.headers }).then(_=>_.json()).then((json:(guildjson["properties"])[])=>{ @@ -187,8 +188,8 @@ class Bot{ content.onclick=()=>{ const guildsetting=guildsettings.addSubOptions(guild.name); guildsetting.addHTMLArea(content); - guildsetting.addButtonInput("","Leave Guild",()=>{ - if(confirm(`Are you sure you want to leave ${guild.name}?`)){ + guildsetting.addButtonInput("",I18n.getTranslation("leaveGuild"),()=>{ + if(confirm(I18n.getTranslation("confirmGuildLeave",guild.name))){ fetch(this.info.api+"/users/@me/guilds/"+guild.id,{ method:"DELETE", headers:this.headers @@ -250,7 +251,7 @@ class Bot{ }); } static InviteMaker(id:string,container:Form,info:Localuser["info"]){ - const gen=container.addSubOptions("URL generator",{ + const gen=container.addSubOptions(I18n.getTranslation("UrlGen"),{ noSubmit:true }); const params = new URLSearchParams(""); diff --git a/src/webpage/channel.ts b/src/webpage/channel.ts index 227bfc8..21b0bbc 100644 --- a/src/webpage/channel.ts +++ b/src/webpage/channel.ts @@ -15,6 +15,7 @@ import{ MarkDown }from"./markdown.js"; import{ Member }from"./member.js"; import { Voice } from "./voice.js"; import { User } from "./user.js"; +import { I18n } from "./i18n.js"; declare global { interface NotificationOptions { @@ -53,20 +54,20 @@ class Channel extends SnowFlake{ voice?:Voice; bitrate:number=128000; static setupcontextmenu(){ - this.contextmenu.addbutton("Copy channel id", function(this: Channel){ + this.contextmenu.addbutton(()=>I18n.getTranslation("channel.copyId"), function(this: Channel){ navigator.clipboard.writeText(this.id); }); - this.contextmenu.addbutton("Mark as read", function(this: Channel){ + this.contextmenu.addbutton(()=>I18n.getTranslation("channel.markRead"), function(this: Channel){ this.readbottom(); }); - this.contextmenu.addbutton("Settings", function(this: Channel){ + this.contextmenu.addbutton(()=>I18n.getTranslation("channel.settings"), function(this: Channel){ this.generateSettings(); }); this.contextmenu.addbutton( - "Delete channel", + ()=>I18n.getTranslation("channel.delete"), function(this: Channel){ this.deleteChannel(); }, @@ -77,7 +78,7 @@ class Channel extends SnowFlake{ ); this.contextmenu.addbutton( - "Make invite", + ()=>I18n.getTranslation("channel.makeInvite"), function(this: Channel){ this.createInvite(); }, @@ -86,24 +87,6 @@ class Channel extends SnowFlake{ return this.hasPermission("CREATE_INSTANT_INVITE") && this.type !== 4; } ); - /* - this.contextmenu.addbutton("Test button",function(){ - this.localuser.ws.send(JSON.stringify({ - "op": 14, - "d": { - "guild_id": this.guild.id, - "channels": { - [this.id]: [ - [ - 0, - 99 - ] - ] - } - } - })) - },null); - /**/ } createInvite(){ const div = document.createElement("div"); @@ -148,20 +131,20 @@ class Channel extends SnowFlake{ update(); new Dialog([ "vdiv", - ["title", "Invite people"], + ["title", I18n.getTranslation("inviteOptions.title")], ["text", `to #${this.name} in ${this.guild.properties.name}`], [ "select", "Expire after:", [ - "30 Minutes", - "1 Hour", - "6 Hours", - "12 Hours", - "1 Day", - "7 Days", - "30 Days", - "Never", + I18n.getTranslation("inviteOptions.30m"), + I18n.getTranslation("inviteOptions.1h"), + I18n.getTranslation("inviteOptions.6h"), + I18n.getTranslation("inviteOptions.12h"), + I18n.getTranslation("inviteOptions.1d"), + I18n.getTranslation("inviteOptions.7d"), + I18n.getTranslation("inviteOptions.30d"), + I18n.getTranslation("inviteOptions.never"), ], function(e: Event){ expires = [1800, 3600, 21600, 43200, 86400, 604800, 2592000, 0,][(e.srcElement as HTMLSelectElement).selectedIndex]; @@ -174,13 +157,13 @@ class Channel extends SnowFlake{ "select", "Max uses:", [ - "No limit", - "1 use", - "5 uses", - "10 uses", - "25 uses", - "50 uses", - "100 uses", + I18n.getTranslation("inviteOptions.noLimit"), + I18n.getTranslation("inviteOptions.limit","1"), + I18n.getTranslation("inviteOptions.limit","5"), + I18n.getTranslation("inviteOptions.limit","10"), + I18n.getTranslation("inviteOptions.limit","25"), + I18n.getTranslation("inviteOptions.limit","50"), + I18n.getTranslation("inviteOptions.limit","100"), ], function(e: Event){ uses = [0, 1, 5, 10, 25, 50, 100][(e.srcElement as HTMLSelectElement).selectedIndex]; @@ -193,7 +176,7 @@ class Channel extends SnowFlake{ } generateSettings(){ this.sortPerms(); - const settings = new Settings("Settings for " + this.name); + const settings = new Settings(I18n.getTranslation("channel.settingsFor",this.name)); { const gensettings=settings.addButton("Settings"); const form=gensettings.addForm("",()=>{},{ @@ -201,18 +184,19 @@ class Channel extends SnowFlake{ method: "PATCH", headers: this.headers, }); - form.addTextInput("Name:","name",{initText:this.name}); - form.addMDInput("Topic:","topic",{initText:this.topic}); - form.addCheckboxInput("NSFW:","nsfw",{initState:this.nsfw}); + form.addTextInput(I18n.getTranslation("channel.name:"),"name",{initText:this.name}); + form.addMDInput(I18n.getTranslation("channel.topic:"),"topic",{initText:this.topic}); + form.addCheckboxInput(I18n.getTranslation("channel.nsfw:"),"nsfw",{initState:this.nsfw}); if(this.type!==4){ const options=["voice", "text", "announcement"]; - form.addSelect("Type:","type",options,{ + form.addSelect("Type:","type",options.map(e=>I18n.getTranslation("channel."+e)),{ defaultIndex:options.indexOf({0:"text", 2:"voice", 5:"announcement", 4:"category" }[this.type] as string) + },options); + form.addPreprocessor((obj:any)=>{ + obj.type={text: 0, voice: 2, announcement: 5, category: 4 }[obj.type as string] }) } - form.addPreprocessor((obj:any)=>{ - obj.type={text: 0, voice: 2, announcement: 5, category: 4 }[obj.type as string] - }) + } const s1 = settings.addButton("Permissions"); s1.options.push( @@ -308,10 +292,7 @@ class Channel extends SnowFlake{ this.permission_overwrites = new Map(); this.permission_overwritesar = []; for(const thing of json.permission_overwrites){ - if( - thing.id === "1182819038095799904" || - thing.id === "1182820803700625444" - ){ + if(thing.id === "1182819038095799904" ||thing.id === "1182820803700625444"){ continue; } if(!this.permission_overwrites.has(thing.id)){ @@ -376,10 +357,10 @@ class Channel extends SnowFlake{ } return( Boolean(this.lastmessageid) && - (!this.lastreadmessageid || - SnowFlake.stringToUnixTime(this.lastmessageid as string) > - SnowFlake.stringToUnixTime(this.lastreadmessageid)) && - this.type !== 4 + (!this.lastreadmessageid || + SnowFlake.stringToUnixTime(this.lastmessageid as string) > + SnowFlake.stringToUnixTime(this.lastreadmessageid)) && + this.type !== 4 ); } hasPermission(name: string, member = this.guild.member): boolean{ @@ -406,10 +387,7 @@ class Channel extends SnowFlake{ return false; } get canMessage(): boolean{ - if( - this.permission_overwritesar.length === 0 && - this.hasPermission("MANAGE_CHANNELS") - ){ + if(this.permission_overwritesar.length === 0 &&this.hasPermission("MANAGE_CHANNELS")){ const role = this.guild.roles.find(_=>_.name === "@everyone"); if(role){ this.addRoleToPerms(role); @@ -435,16 +413,17 @@ class Channel extends SnowFlake{ calculateReorder(){ let position = -1; const build: { - id: string; - position: number | undefined; - parent_id: string | undefined; - }[] = []; + id: string; + position: number | undefined; + parent_id: string | undefined; + }[] = []; for(const thing of this.children){ const thisthing: { - id: string; - position: number | undefined; - parent_id: string | undefined; - } = { id: thing.id, position: undefined, parent_id: undefined }; + id: string; + position: number | undefined; + parent_id: string | undefined; + } = { id: thing.id, position: undefined, parent_id: undefined }; + if(thing.position < position){ thing.position = thisthing.position = position + 1; } @@ -652,12 +631,7 @@ class Channel extends SnowFlake{ return; } fetch( - this.info.api + - "/channels/" + - this.id + - "/messages/" + - this.lastmessageid + - "/ack", + this.info.api +"/channels/" + this.id + "/messages/" + this.lastmessageid + "/ack", { method: "POST", headers: this.headers, @@ -768,7 +742,7 @@ class Channel extends SnowFlake{ if(this.replyingto){ replybox.innerHTML = ""; const span = document.createElement("span"); - span.textContent = "Replying to " + this.replyingto.author.username; + span.textContent = I18n.getTranslation("replyingTo", this.replyingto.author.username); const X = document.createElement("button"); X.onclick = _=>{ if(this.replyingto?.div){ @@ -827,9 +801,7 @@ class Channel extends SnowFlake{ history.pushState(null, "", "/channels/" + this.guild_id + "/" + this.id); this.localuser.pageTitle("#" + this.name); - const channelTopic = document.getElementById( - "channelTopic" - ) as HTMLSpanElement; + const channelTopic = document.getElementById("channelTopic") as HTMLSpanElement; if(this.topic){ channelTopic.innerHTML = new MarkDown( this.topic, @@ -855,8 +827,7 @@ class Channel extends SnowFlake{ await this.buildmessages(); //loading.classList.remove("loading"); - (document.getElementById("typebox") as HTMLDivElement).contentEditable = - "" + this.canMessage; + (document.getElementById("typebox") as HTMLDivElement).contentEditable =""+this.canMessage; } typingmap: Map = new Map(); async typingStart(typing: startTypingjson): Promise{ @@ -893,11 +864,7 @@ class Channel extends SnowFlake{ this.typingmap.delete(thing); } } - if(i > 1){ - build += " are typing"; - }else{ - build += " is typing"; - } + build=I18n.getTranslation("typing",i+"",build); if(this.localuser.channelfocus === this){ if(showing){ typingtext.classList.remove("hidden"); @@ -1013,12 +980,7 @@ class Channel extends SnowFlake{ } await fetch( - this.info.api + - "/channels/" + - this.id + - "/messages?before=" + - id + - "&limit=100", + this.info.api + "/channels/" + this.id +"/messages?before=" + id + "&limit=100", { headers: this.headers, } @@ -1059,10 +1021,10 @@ class Channel extends SnowFlake{ }); } /** - * Please dont use this, its not implemented. - * @deprecated - * @todo - **/ + * Please dont use this, its not implemented. + * @deprecated + * @todo + **/ async grabArround(/* id: string */){ //currently unused and no plans to use it yet throw new Error("please don't call this, no one has implemented it :P"); @@ -1099,8 +1061,7 @@ class Channel extends SnowFlake{ if(!removetitle){ const title = document.createElement("h2"); title.id = "removetitle"; - title.textContent = - "No messages appear to be here, be the first to say something!"; + title.textContent = I18n.getTranslation("noMessages"); title.classList.add("titlespace"); messages.append(title); } @@ -1353,7 +1314,7 @@ class Channel extends SnowFlake{ noticontent ||= message.embeds[0]?.json.title; noticontent ||= message.content.textContent; } - noticontent ||= "Blank Message"; + noticontent ||= I18n.getTranslation("blankMessage"); let imgurl: null | string = null; const images = message.getimages(); if(images.length){ diff --git a/src/webpage/direct.ts b/src/webpage/direct.ts index edabcd5..8568574 100644 --- a/src/webpage/direct.ts +++ b/src/webpage/direct.ts @@ -12,6 +12,7 @@ import{ import{ Permissions }from"./permissions.js"; import{ SnowFlake }from"./snowflake.js"; import{ Contextmenu }from"./contextmenu.js"; +import { I18n } from "./i18n.js"; class Direct extends Guild{ declare channelids: { [key: string]: Group }; @@ -99,24 +100,24 @@ dmPermissions.setPermission("SPEAK", 1); dmPermissions.setPermission("STREAM", 1); dmPermissions.setPermission("USE_VAD", 1); -// @ts-ignore +// @ts-ignore I need to look into this lol class Group extends Channel{ user: User; static contextmenu = new Contextmenu("channel menu"); static setupcontextmenu(){ - this.contextmenu.addbutton("Copy DM id", function(this: Group){ + this.contextmenu.addbutton(()=>I18n.getTranslation("DMs.copyId"), function(this: Group){ navigator.clipboard.writeText(this.id); }); - this.contextmenu.addbutton("Mark as read", function(this: Group){ + this.contextmenu.addbutton(()=>I18n.getTranslation("DMs.markRead"), function(this: Group){ this.readbottom(); }); - this.contextmenu.addbutton("Close DM", function(this: Group){ + this.contextmenu.addbutton(()=>I18n.getTranslation("DMs.close"), function(this: Group){ this.deleteChannel(); }); - this.contextmenu.addbutton("Copy user ID", function(){ + this.contextmenu.addbutton(()=>I18n.getTranslation("user.copyId"), function(){ navigator.clipboard.writeText(this.user.id); }); } @@ -179,10 +180,7 @@ class Group extends Channel{ const prom = this.infinite.delete(); history.pushState(null, "", "/channels/" + this.guild_id + "/" + this.id); this.localuser.pageTitle("@" + this.name); - (document.getElementById("channelTopic") as HTMLElement).setAttribute( - "hidden", - "" - ); + (document.getElementById("channelTopic") as HTMLElement).setAttribute("hidden",""); const loading = document.getElementById("loadingdiv") as HTMLDivElement; Channel.regenLoadingMessages(); @@ -306,4 +304,5 @@ class Group extends Channel{ } } export{ Direct, Group }; -Group.setupcontextmenu(); + +Group.setupcontextmenu() diff --git a/src/webpage/embed.ts b/src/webpage/embed.ts index 91804fc..d2f8fe9 100644 --- a/src/webpage/embed.ts +++ b/src/webpage/embed.ts @@ -4,6 +4,7 @@ import{ MarkDown }from"./markdown.js"; import{ embedjson, invitejson }from"./jsontypes.js"; import{ getapiurls, getInstances }from"./login.js"; import{ Guild }from"./guild.js"; +import { I18n } from "./i18n.js"; class Embed{ type: string; @@ -296,8 +297,7 @@ guild as invitejson["guild"] & { info: { cdn: string } } guildinfo.append(name); const members = document.createElement("span"); - members.innerText = -"#" + json.channel.name + " • Members: " + guild.member_count; + members.innerText = "#" + json.channel.name + " • Members: " + guild.member_count; guildinfo.append(members); members.classList.add("subtext"); iconrow.append(guildinfo); @@ -305,12 +305,12 @@ guild as invitejson["guild"] & { info: { cdn: string } } div.append(iconrow); const h2 = document.createElement("h2"); - h2.textContent = `You've been invited by ${json.inviter.username}`; + h2.textContent = I18n.getTranslation("invite.invitedBy",json.inviter.username); div.append(h2); const button = document.createElement("button"); - button.textContent = "Accept"; + button.textContent = I18n.getTranslation("invite.accept"); if(this.localuser.info.api.startsWith(info.api) && this.localuser.guildids.has(guild.id)){ - button.textContent = "Already joined"; + button.textContent = I18n.getTranslation("invite.alreadyJoined"); button.disabled = true; } button.classList.add("acceptinvbutton"); diff --git a/src/webpage/emoji.ts b/src/webpage/emoji.ts index c605345..7380cd8 100644 --- a/src/webpage/emoji.ts +++ b/src/webpage/emoji.ts @@ -2,6 +2,7 @@ import{ Contextmenu }from"./contextmenu.js"; import{ Guild }from"./guild.js"; import{ Localuser }from"./localuser.js"; +//I need to recompile the emoji format for translation class Emoji{ static emojis: { name: string; @@ -158,13 +159,7 @@ class Emoji{ const img = document.createElement("img"); img.classList.add("pfp", "servericon", "emoji-server"); img.crossOrigin = "anonymous"; - img.src = - localuser.info.cdn + - "/icons/" + - guild.properties.id + - "/" + - guild.properties.icon + - ".png?size=48"; + img.src = localuser.info.cdn+"/icons/"+guild.properties.id+"/"+guild.properties.icon+".png?size=48"; img.alt = "Server: " + guild.properties.name; select.appendChild(img); }else{ diff --git a/src/webpage/file.ts b/src/webpage/file.ts index 63969ca..3a67853 100644 --- a/src/webpage/file.ts +++ b/src/webpage/file.ts @@ -145,9 +145,7 @@ class File{ static filesizehuman(fsize: number){ const i = fsize == 0 ? 0 : Math.floor(Math.log(fsize) / Math.log(1024)); return( - Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + -" " + -["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i] + Number((fsize / Math.pow(1024, i)).toFixed(2)) * 1 + " " + ["Bytes", "Kilobytes", "Megabytes", "Gigabytes", "Terabytes"][i] // I don't think this changes across languages, correct me if I'm wrong ); } } diff --git a/src/webpage/guild.ts b/src/webpage/guild.ts index 22b16e7..dd6091d 100644 --- a/src/webpage/guild.ts +++ b/src/webpage/guild.ts @@ -16,6 +16,7 @@ import{ rolesjson, }from"./jsontypes.js"; import{ User }from"./user.js"; +import { I18n } from "./i18n.js"; class Guild extends SnowFlake{ owner!: Localuser; @@ -38,20 +39,20 @@ class Guild extends SnowFlake{ members=new Set(); static contextmenu = new Contextmenu("guild menu"); static setupcontextmenu(){ - Guild.contextmenu.addbutton("Copy Guild id", function(this: Guild){ + Guild.contextmenu.addbutton(()=>I18n.getTranslation("guild.copyId"), function(this: Guild){ navigator.clipboard.writeText(this.id); }); - Guild.contextmenu.addbutton("Mark as read", function(this: Guild){ + Guild.contextmenu.addbutton(()=>I18n.getTranslation("guild.markRead"), function(this: Guild){ this.markAsRead(); }); - Guild.contextmenu.addbutton("Notifications", function(this: Guild){ + Guild.contextmenu.addbutton(()=>I18n.getTranslation("guild.notifications"), function(this: Guild){ this.setnotifcation(); }); Guild.contextmenu.addbutton( - "Leave guild", + ()=>I18n.getTranslation("guild.leave"), function(this: Guild){ this.confirmleave(); }, @@ -62,7 +63,7 @@ class Guild extends SnowFlake{ ); Guild.contextmenu.addbutton( - "Delete guild", + ()=>I18n.getTranslation("guild.delete"), function(this: Guild){ this.confirmDelete(); }, @@ -73,13 +74,13 @@ class Guild extends SnowFlake{ ); Guild.contextmenu.addbutton( - "Create invite", + ()=>I18n.getTranslation("guild.makeInvite"), function(this: Guild){}, null, _=>true, _=>false ); - Guild.contextmenu.addbutton("Settings", function(this: Guild){ + Guild.contextmenu.addbutton(()=>I18n.getTranslation("guild.settings"), function(this: Guild){ this.generateSettings(); }); /* -----things left for later----- @@ -94,28 +95,28 @@ class Guild extends SnowFlake{ */ } generateSettings(){ - const settings = new Settings("Settings for " + this.properties.name); + const settings = new Settings(I18n.getTranslation("guild.settingsFor",this.properties.name)); { - const overview = settings.addButton("Overview"); + const overview = settings.addButton(I18n.getTranslation("guild.overview")); const form = overview.addForm("", _=>{}, { headers: this.headers, traditionalSubmit: true, fetchURL: this.info.api + "/guilds/" + this.id, method: "PATCH", }); - form.addTextInput("Name:", "name", { initText: this.properties.name }); + form.addTextInput(I18n.getTranslation("guild.name:"), "name", { initText: this.properties.name }); form.addMDInput("Description:", "description", { initText: this.properties.description, }); - form.addFileInput("Banner:", "banner", { clear: true }); - form.addFileInput("Icon:", "icon", { clear: true }); + form.addFileInput(I18n.getTranslation("guild.banner:"), "banner", { clear: true }); + form.addFileInput(I18n.getTranslation("guild.icon:"), "icon", { clear: true }); let region = this.properties.region; if(!region){ region = ""; } - form.addTextInput("Region:", "region", { initText: region }); + form.addTextInput(I18n.getTranslation("guild.region:"), "region", { initText: region }); } - const s1 = settings.addButton("Roles"); + const s1 = settings.addButton(I18n.getTranslation("guild.roles")); const permlist: [Role, Permissions][] = []; for(const thing of this.roles){ permlist.push([thing, thing.permissions]); @@ -261,14 +262,15 @@ class Guild extends SnowFlake{ } setnotifcation(){ let noti = this.message_notifications; + const options=["all", "onlyMentions", "none"].map(e=>I18n.getTranslation("guild."+e)) const notiselect = new Dialog([ "vdiv", [ "radio", - "select notifications type", - ["all", "only mentions", "none"], - function(e: string /* "all" | "only mentions" | "none" */){ - noti = ["all", "only mentions", "none"].indexOf(e); + I18n.getTranslation("guild.selectnoti"), + options, + function(e: string){ + noti = options.indexOf(e); }, noti, ], @@ -294,13 +296,13 @@ class Guild extends SnowFlake{ confirmleave(){ const full = new Dialog([ "vdiv", - ["title", "Are you sure you want to leave?"], + ["title", I18n.getTranslation("guild.confirmLeave")], [ "hdiv", [ "button", "", - "Yes, I'm sure", + I18n.getTranslation("yesLeave"), (_: any)=>{ this.leave().then(_=>{ full.hide(); @@ -310,7 +312,7 @@ class Guild extends SnowFlake{ [ "button", "", - "Nevermind", + I18n.getTranslation("noLeave"), (_: any)=>{ full.hide(); }, @@ -467,11 +469,11 @@ class Guild extends SnowFlake{ "vdiv", [ "title", - "Are you sure you want to delete " + this.properties.name + "?", + I18n.getTranslation("guild.confirmDelete",this.properties.name) ], [ "textbox", - "Name of server:", + I18n.getTranslation("serverName"), "", function(this: HTMLInputElement){ confirmname = this.value; @@ -482,7 +484,7 @@ class Guild extends SnowFlake{ [ "button", "", - "Yes, I'm sure", + I18n.getTranslation("yesDelete"), (_: any)=>{ console.log(confirmname); if(confirmname !== this.properties.name){ @@ -496,7 +498,7 @@ class Guild extends SnowFlake{ [ "button", "", - "Nevermind", + I18n.getTranslation("noDelete"), (_: any)=>{ full.hide(); }, @@ -638,22 +640,23 @@ class Guild extends SnowFlake{ createchannels(func = this.createChannel){ let name = ""; let category = 0; + const options=["voice", "text", "announcement"].map(e=>I18n.getTranslation("channel."+e)); + const numbers=[2,0,5] const channelselect = new Dialog([ "vdiv", [ "radio", - "select channel type", - ["voice", "text", "announcement"], + I18n.getTranslation("channel.selectType"), + options, function(radio: string){ console.log(radio); - category = - { text: 0, voice: 2, announcement: 5, category: 4 }[radio] || 0; + category = numbers[options.indexOf(radio)] || 0; }, 1, ], [ "textbox", - "Name of channel", + I18n.getTranslation("channel.selectName"), "", function(this: HTMLInputElement){ name = this.value; @@ -662,7 +665,7 @@ class Guild extends SnowFlake{ [ "button", "", - "submit", + I18n.getTranslation("submit"), ()=>{ console.log(name, category); func.bind(this)(name, category); @@ -679,7 +682,7 @@ class Guild extends SnowFlake{ "vdiv", [ "textbox", - "Name of category", + I18n.getTranslation("channel.selectCatName"), "", function(this: HTMLInputElement){ name = this.value; @@ -688,7 +691,7 @@ class Guild extends SnowFlake{ [ "button", "", - "submit", + I18n.getTranslation("submit"), function(this:Guild){ console.log(name, category); this.createChannel(name, category); diff --git a/src/webpage/home.ts b/src/webpage/home.ts index ce94e44..57c4824 100644 --- a/src/webpage/home.ts +++ b/src/webpage/home.ts @@ -1,3 +1,4 @@ +import { I18n } from "./i18n.js"; import{ mobile }from"./login.js"; console.log(mobile); const serverbox = document.getElementById("instancebox") as HTMLDivElement; @@ -5,7 +6,7 @@ const serverbox = document.getElementById("instancebox") as HTMLDivElement; fetch("/instances.json") .then(_=>_.json()) .then( - ( + async ( json: { name: string; description?: string; @@ -24,6 +25,7 @@ fetch("/instances.json") }; }[] )=>{ + await I18n.done; console.warn(json); for(const instance of json){ if(instance.display === false){ @@ -66,11 +68,11 @@ fetch("/instances.json") const stats = document.createElement("div"); stats.classList.add("flexltr"); const span = document.createElement("span"); - span.innerText = `Uptime: All time: ${Math.round( + span.innerText = I18n.getTranslation("home.uptimeStats",Math.round( instance.uptime.alltime * 100 - )}% This week: ${Math.round( + )+"",Math.round( instance.uptime.weektime * 100 - )}% Today: ${Math.round(instance.uptime.daytime * 100)}%`; + )+"",Math.round(instance.uptime.daytime * 100)+"") stats.append(span); statbox.append(stats); } @@ -79,7 +81,7 @@ fetch("/instances.json") if(instance.online){ window.location.href = "/register.html?instance=" + encodeURI(instance.name); }else{ - alert("Instance is offline, can't connect"); + alert(I18n.getTranslation("home.warnOffiline")); } }; serverbox.append(div); diff --git a/src/webpage/i18n.ts b/src/webpage/i18n.ts index a7c3052..09c8949 100644 --- a/src/webpage/i18n.ts +++ b/src/webpage/i18n.ts @@ -105,4 +105,5 @@ class I18n{ } } } +I18n.create("/translations/en.json","en") export{I18n}; diff --git a/src/webpage/index.ts b/src/webpage/index.ts index 7f19a01..1b40b9d 100644 --- a/src/webpage/index.ts +++ b/src/webpage/index.ts @@ -4,6 +4,7 @@ import{ mobile, getBulkUsers, setTheme, Specialuser }from"./login.js"; import{ MarkDown }from"./markdown.js"; import{ Message }from"./message.js"; import{ File }from"./file.js"; +import { I18n } from "./i18n.js"; (async ()=>{ async function waitForLoad(): Promise{ @@ -13,7 +14,7 @@ import{ File }from"./file.js"; } await waitForLoad(); - + await I18n.done const users = getBulkUsers(); if(!users.currentuser){ window.location.href = "/login.html"; @@ -74,7 +75,7 @@ import{ File }from"./file.js"; const switchAccountDiv = document.createElement("div"); switchAccountDiv.classList.add("switchtable"); - switchAccountDiv.textContent = "Switch accounts ⇌"; + switchAccountDiv.textContent = I18n.getTranslation("switchAccounts"); switchAccountDiv.addEventListener("click", ()=>{ window.location.href = "/login.html"; }); @@ -93,9 +94,7 @@ import{ File }from"./file.js"; showAccountSwitcher(); }); - const switchAccountsElement = document.getElementById( - "switchaccounts" - ) as HTMLDivElement; + const switchAccountsElement = document.getElementById("switchaccounts") as HTMLDivElement; switchAccountsElement.addEventListener("click", event=>{ event.stopImmediatePropagation(); showAccountSwitcher(); @@ -115,14 +114,13 @@ import{ File }from"./file.js"; }); }catch(e){ console.error(e); - (document.getElementById("load-desc") as HTMLSpanElement).textContent = - "Account unable to start"; + (document.getElementById("load-desc") as HTMLSpanElement).textContent = I18n.getTranslation("accountNotStart"); thisUser = new Localuser(-1); } - const menu = new Contextmenu("create rightclick"); + const menu = new Contextmenu("create rightclick"); menu.addbutton( - "Create channel", + I18n.getTranslation("channel.createChannel"), ()=>{ if(thisUser.lookingguild){ thisUser.lookingguild.createchannels(); @@ -133,7 +131,7 @@ import{ File }from"./file.js"; ); menu.addbutton( - "Create category", + I18n.getTranslation("channel.createCatagory"), ()=>{ if(thisUser.lookingguild){ thisUser.lookingguild.createcategory(); @@ -143,15 +141,9 @@ import{ File }from"./file.js"; ()=>thisUser.isAdmin() ); - menu.bindContextmenu( - document.getElementById("channels") as HTMLDivElement, - 0, - 0 - ); + menu.bindContextmenu(document.getElementById("channels") as HTMLDivElement); - const pasteImageElement = document.getElementById( - "pasteimage" - ) as HTMLDivElement; + const pasteImageElement = document.getElementById("pasteimage") as HTMLDivElement; let replyingTo: Message | null = null; async function handleEnter(event: KeyboardEvent): Promise{ diff --git a/src/webpage/localuser.ts b/src/webpage/localuser.ts index 589ff7c..17cc184 100644 --- a/src/webpage/localuser.ts +++ b/src/webpage/localuser.ts @@ -65,7 +65,6 @@ class Localuser{ "Content-type": "application/json; charset=UTF-8", Authorization: this.userinfo.token, }; - I18n.create("/translations/en.json","en") } async gottenReady(ready: readyjson): Promise{ await I18n.done; diff --git a/src/webpage/message.ts b/src/webpage/message.ts index 49b2acd..574a106 100644 --- a/src/webpage/message.ts +++ b/src/webpage/message.ts @@ -56,13 +56,13 @@ class Message extends SnowFlake{ Message.setupcmenu(); } static setupcmenu(){ - Message.contextmenu.addbutton(I18n.getTranslation.bind(I18n,"copyrawtext"), function(this: Message){ + Message.contextmenu.addbutton(()=>I18n.getTranslation("copyrawtext"), function(this: Message){ navigator.clipboard.writeText(this.content.rawString); }); - Message.contextmenu.addbutton(I18n.getTranslation.bind(I18n,"reply"), function(this: Message){ + Message.contextmenu.addbutton(()=>I18n.getTranslation("reply"), function(this: Message){ this.channel.setReplying(this); }); - Message.contextmenu.addbutton(I18n.getTranslation.bind(I18n,"copymessageid"), function(this: Message){ + Message.contextmenu.addbutton(()=>I18n.getTranslation("copymessageid"), function(this: Message){ navigator.clipboard.writeText(this.id); }); Message.contextmenu.addsubmenu( diff --git a/src/webpage/settings.ts b/src/webpage/settings.ts index 245948b..8e7fd73 100644 --- a/src/webpage/settings.ts +++ b/src/webpage/settings.ts @@ -938,15 +938,18 @@ class Form implements OptionsElement{ (this.button.deref() as HTMLElement).hidden=false; } } + selectMap=new WeakMap(); addSelect( label: string, formName: string, selections: string[], - { defaultIndex = 0, required = false } = {} + { defaultIndex = 0, required = false}={}, + correct:string[]=selections ){ const select = this.options.addSelect(label, _=>{}, selections, { defaultIndex, }); + this.selectMap.set(select,correct); this.names.set(formName, select); if(required){ this.required.add(select); @@ -1110,7 +1113,7 @@ class Form implements OptionsElement{ if(thing === "")continue; const input = this.names.get(thing) as OptionsElement; if(input instanceof SelectInput){ - (build as any)[thing] = input.options[input.value]; + (build as any)[thing] = (this.selectMap.get(input) as string[])[input.value]; continue; }else if(input instanceof FileInput){ const options = this.fileOptions.get(input); diff --git a/src/webpage/translations/en.json b/src/webpage/translations/en.json index 26a351f..7841732 100644 --- a/src/webpage/translations/en.json +++ b/src/webpage/translations/en.json @@ -122,7 +122,101 @@ "no":"No", "todayAt":"Today at $1", "yesterdayAt":"Yesterday at $1", - "otherAt":"$1 at $2" + "otherAt":"$1 at $2", + "botSettings":"Bot Settings", + "uploadPfp":"Upload pfp:", + "uploadBanner":"Upload banner:", + "pronouns":"Pronouns:", + "bio":"Bio:", + "profileColor":"Profile color", + "botGuilds":"Guilds bot is in:", + "leaveGuild":"Leave Guild", + "confirmGuildLeave":"Are you sure you want to leave $1", + "UrlGen":"URL generator", + "typing":"$2 {{PLURAL:$1|are|is}} typing", + "noMessages":"No messages appear to be here, be the first to say something!", + "blankMessage":"Blank Message", + "channel":{ + "copyId":"Copy channel id", + "markRead":"Mark as read", + "settings":"Settings", + "delete":"Delete channel", + "makeInvite":"Make invite", + "settingsFor":"Settings for $1", + "voice":"Voice", + "text":"Text", + "announcement":"Announcements", + "name:":"Name:", + "topic:":"Topic:", + "nsfw:":"NSFW:", + "selectType":"Select channel type", + "selectName":"Name of channel", + "selectCatName":"Name of channel", + "createChannel":"Create channel", + "createCatagory":"Create category" + }, + "switchAccounts":"Switch accounts ⇌", + "accountNotStart":"Account unable to start", + "home":{ + "uptimeStats":"Uptime: \n All time: $1\nThis week: $2\nToday: $3", + "warnOffiline":"Instance is offline, can't connect" + }, + "submit":"submit", + "guild":{ + "copyId":"Copy guild id", + "markRead":"Mark as read", + "notifications":"Notifications", + "leave":"Leave guild", + "settings":"Settings", + "delete":"Delete guild", + "makeInvite":"Make invite", + "settingsFor":"Settings for $1", + "name:":"Name:", + "topic:":"Topic:", + "icon:":"Icon:", + "overview":"Overview", + "banner:":"Banner:", + "region:":"Region:", + "roles":"Roles", + "selectnoti":"Select notifications type", + "all":"all", + "onlyMentions":"only mentions", + "none":"node", + "confirmLeave":"Are you sure you want to leave?", + "yesLeave":"Yes, I'm sure", + "noLeave":"Nevermind", + "confirmDelete":"Are you sure you want to delete $1?", + "serverName":"Name of server:", + "yesDelete":"Yes, I'm sure", + "noDelete":"Nevermind" + }, + "inviteOptions":{ + "title":"Invite People", + "30m":"30 Minutes", + "1h":"1 Hour", + "6h":"6 Hours", + "12h":"12 Hours", + "1d":"1 Day", + "7d":"7 Days", + "30d":"30 Days", + "never":"Never", + "limit":"$1 {{PLURAL:$1|use|uses}}", + "noLimit":"No limit" + }, + "invite":{ + "invitedBy":"You've been invited by $1", + "alreadyJoined":"Already joined", + "accept":"Accept" + }, + "replyingTo":"Replying to $1", + "DMs":{ + "copyId":"Copy DM id", + "markRead":"Mark as read", + "close":"Close DM" + }, + "user":{ + "copyId":"Copy user ID" + } }, "ru": "./ru.json" }