diff --git a/src/webpage/contextmenu.ts b/src/webpage/contextmenu.ts index 205c025..67cafb0 100644 --- a/src/webpage/contextmenu.ts +++ b/src/webpage/contextmenu.ts @@ -2,12 +2,12 @@ class Contextmenu{ static currentmenu: HTMLElement | ""; name: string; buttons: [ - string, - (this: x, arg: y, e: MouseEvent) => void, - string | null, - (this: x, arg: y) => boolean, - (this: x, arg: y) => boolean, - string + string|(()=>string), + (this: x, arg: y, e: MouseEvent) => void, + string | null, + (this: x, arg: y) => boolean, + (this: x, arg: y) => boolean, + string ][]; div!: HTMLDivElement; static setup(){ @@ -27,7 +27,7 @@ class Contextmenu{ this.buttons = []; } addbutton( - text: string, + text: string|(()=>string), onclick: (this: x, arg: y, e: MouseEvent) => void, img: null | string = null, shown: (this: x, arg: y) => boolean = _=>true, @@ -58,7 +58,11 @@ class Contextmenu{ const intext = document.createElement("button"); intext.disabled = !thing[4].bind(addinfo).call(addinfo, other); intext.classList.add("contextbutton"); - intext.textContent = thing[0]; + if(thing[0] instanceof Function){ + intext.textContent = thing[0](); + }else{ + intext.textContent = thing[0]; + } console.log(thing); if(thing[5] === "button" || thing[5] === "submenu"){ intext.onclick = thing[1].bind(addinfo, other); diff --git a/src/webpage/i18n.ts b/src/webpage/i18n.ts new file mode 100644 index 0000000..7f7094e --- /dev/null +++ b/src/webpage/i18n.ts @@ -0,0 +1,96 @@ +type translation={ + [key:string]:string|{[key:string]:string} +}; +let res:()=>unknown=()=>{}; +class I18n{ + static lang:string; + static translations:{[key:string]:string}[]=[]; + static done=new Promise((res2,_reject)=>{ + res=res2; + }); + static async create(json:translation|string,lang:string){ + if(typeof json === "string"){ + json=await (await fetch(json)).json() as translation; + } + const translations:{[key:string]:string}[]=[]; + let translation=json[lang]; + if(!translation){ + translation=json[lang[0]+lang[1]]; + if(!translation){ + console.error(lang+" does not exist in the translations"); + translation=json["en"]; + lang="en"; + } + } + translations.push(await this.toTranslation(translation,lang)); + if(lang!=="en"){ + translations.push(await this.toTranslation(json["en"],"en")) + } + this.lang=lang; + this.translations=translations; + res(); + } + static getTranslation(msg:string,...params:string[]):string{ + let str:string|undefined; + for(const json of this.translations){ + str=json[msg]; + if(str){ + break; + } + } + if(str){ + return this.fillInBlanks(str,params); + }else{ + throw new Error(msg+" not found") + } + } + static fillInBlanks(msg:string,params:string[]):string{ + //thanks to geotale for the regex + msg=msg.replace(/{{(.+?)}}/g, + (str, match:string) => { + const [op,strsSplit]=this.fillInBlanks(match,params).split(":"); + const [first,...strs]=strsSplit.split("|"); + switch(op.toUpperCase()){ + case "PLURAL":{ + const numb=Number(first); + if(numb===0){ + return strs[strs.length-1]; + } + return strs[Math.min(strs.length-1,numb-1)]; + } + case "GENDER":{ + if(first==="male"){ + return strs[0]; + }else if(first==="female"){ + return strs[1]; + }else if(first==="neutral"){ + if(strs[2]){ + return strs[2]; + }else{ + return strs[0]; + } + } + } + } + return str; + } + ); + msg=msg.replace(/\$\d+/g,(str, match:string) => { + const number=Number(match); + if(params[number-1]){ + return params[number-1]; + }else{ + return str; + } + }); + return msg; + } + private static async toTranslation(trans:string|{[key:string]:string},lang:string):Promise<{[key:string]:string}>{ + if(typeof trans==='string'){ + return this.toTranslation((await (await fetch(trans)).json() as translation)[lang],lang); + }else{ + return trans; + } + } +} +export{I18n}; diff --git a/src/webpage/localuser.ts b/src/webpage/localuser.ts index f2461fe..db17bf3 100644 --- a/src/webpage/localuser.ts +++ b/src/webpage/localuser.ts @@ -12,14 +12,12 @@ import{ MarkDown }from"./markdown.js"; import { Bot } from "./bot.js"; import { Role } from "./role.js"; import { VoiceFactory } from "./voice.js"; +import { I18n } from "./i18n.js"; const wsCodesRetry = new Set([4000, 4003, 4005, 4007, 4008, 4009]); class Localuser{ - badges: Map< - string, - { id: string; description: string; icon: string; link: string } - > = new Map(); + badges: Map = new Map(); lastSequence: number | null = null; token!: string; userinfo!: Specialuser; @@ -67,8 +65,10 @@ class Localuser{ "Content-type": "application/json; charset=UTF-8", Authorization: this.userinfo.token, }; + I18n.create("/translations/en.json","en") } - gottenReady(ready: readyjson): void{ + async gottenReady(ready: readyjson): Promise{ + await I18n.done; this.initialized = true; this.ready = ready; this.guilds = []; @@ -200,10 +200,10 @@ class Localuser{ try{ const temp = JSON.parse(build); build = ""; + await this.handleEvent(temp); if(temp.op === 0 && temp.t === "READY"){ returny(); } - await this.handleEvent(temp); }catch{} } })(); @@ -231,9 +231,9 @@ class Localuser{ if( !( array[len - 1] === 255 && - array[len - 2] === 255 && - array[len - 3] === 0 && - array[len - 4] === 0 + array[len - 2] === 255 && + array[len - 3] === 0 && + array[len - 4] === 0 ) ){ return; @@ -244,10 +244,11 @@ class Localuser{ }else{ temp = JSON.parse(event.data); } + + await this.handleEvent(temp as readyjson); if(temp.op === 0 && temp.t === "READY"){ returny(); } - await this.handleEvent(temp as readyjson); }catch(e){ console.error(e); }finally{ @@ -367,7 +368,7 @@ class Localuser{ break; } case"READY": - this.gottenReady(temp as readyjson); + await this.gottenReady(temp as readyjson); break; case"MESSAGE_UPDATE": { temp.d.guild_id ??= "@me"; diff --git a/src/webpage/message.ts b/src/webpage/message.ts index fc79b87..0cc86c5 100644 --- a/src/webpage/message.ts +++ b/src/webpage/message.ts @@ -11,6 +11,7 @@ import{ SnowFlake }from"./snowflake.js"; import{ memberjson, messagejson }from"./jsontypes.js"; import{ Emoji }from"./emoji.js"; import{ Dialog }from"./dialog.js"; +import { I18n } from "./i18n.js"; class Message extends SnowFlake{ static contextmenu = new Contextmenu("message menu"); @@ -44,9 +45,7 @@ class Message extends SnowFlake{ return this.weakdiv?.deref(); } //*/ - div: - | (HTMLDivElement & { pfpparent?: Message | undefined; txt?: HTMLElement }) - | undefined; + div:(HTMLDivElement & { pfpparent?: Message | undefined; txt?: HTMLElement })| undefined; member: Member | undefined; reactions!: messagejson["reactions"]; static setup(){ @@ -56,13 +55,13 @@ class Message extends SnowFlake{ Message.setupcmenu(); } static setupcmenu(){ - Message.contextmenu.addbutton("Copy raw text", function(this: Message){ + Message.contextmenu.addbutton(I18n.getTranslation.bind(I18n,"copyrawtext"), function(this: Message){ navigator.clipboard.writeText(this.content.rawString); }); - Message.contextmenu.addbutton("Reply", function(this: Message){ + Message.contextmenu.addbutton(I18n.getTranslation.bind(I18n,"reply"), function(this: Message){ this.channel.setReplying(this); }); - Message.contextmenu.addbutton("Copy message id", function(this: Message){ + Message.contextmenu.addbutton(I18n.getTranslation.bind(I18n,"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 85d7c81..23fb76f 100644 --- a/src/webpage/settings.ts +++ b/src/webpage/settings.ts @@ -4,7 +4,7 @@ interface OptionsElement { submit: () => void; readonly watchForChange: (func: (arg1: x) => void) => void; value: x; - } +} //future me stuff class Buttons implements OptionsElement{ readonly name: string; diff --git a/src/webpage/translations/en.json b/src/webpage/translations/en.json new file mode 100644 index 0000000..8f0fd4d --- /dev/null +++ b/src/webpage/translations/en.json @@ -0,0 +1,16 @@ +{ + "@metadata": { + "authors": [ + "MathMan05" + ], + "last-updated": "2024/15/24", + "locale": "en", + "comment":"Don't know how often I'll update this top part lol" + }, + "en": { + "reply": "Reply", + "copyrawtext":"Copy raw text", + "copymessageid":"Copy message id" + }, + "ru": "./ru.json" +} diff --git a/src/webpage/translations/ru.json b/src/webpage/translations/ru.json new file mode 100644 index 0000000..bbc86f1 --- /dev/null +++ b/src/webpage/translations/ru.json @@ -0,0 +1,12 @@ +{ + "@metadata": { + "authors": [ + ], + "last-updated": "2024/15/24", + "locale": "ru", + "comment":"I need some help with this :P" + }, + "ru": { + + } +}