From 958f1c83d40953f3a63f81fe8d5824add13e1bdf Mon Sep 17 00:00:00 2001 From: win7he Date: Sat, 18 Apr 2026 01:46:37 -0500 Subject: [PATCH 1/3] language file --- assets/internal/lang.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 assets/internal/lang.json diff --git a/assets/internal/lang.json b/assets/internal/lang.json new file mode 100644 index 0000000..29c2020 --- /dev/null +++ b/assets/internal/lang.json @@ -0,0 +1 @@ +{"v":"WL1","n":"bar","l":{"en":{"langname":"English","chat":"Chat","regusers":"Registered users","chlist":"Channel list","lchan":"Leave channel","insert":"Insert","emoticon":"Emoticon","gif":"GIF","status":"Status","statmes":"Status messages","onlinestat":"Online (All notifs)","inactstat":"Inactive (Pings only)","busystat":"Busy (No notifs)","offlinestat":"Appear offline","pref":"Preferences","prefl":"prefrences","help":"Help","user":"User","chans":"Channels","lseen":"Last seen","impmes":"Important message! ","save":"Save","cancel":"Cancel","btodef":"Back to defaults","interface":"Interface","ffam":"Font family","fsiz":"Font size","fthi":"Frame thickness","backc":"Background color","textc":"Text color","userc":"Username color","usernh":"Use {username} where you want\n your username to be.","joinm":"Join message","leavm":"Leave message","inacm":"Inactive message","busym":"Busy message","choose":"Choose..."}},"r":{"gb":"en","us":"en"},"d":"en"} \ No newline at end of file From 8f54378afdfa25eed3217b2a36159006b7a52e63 Mon Sep 17 00:00:00 2001 From: win7he Date: Sat, 18 Apr 2026 01:49:03 -0500 Subject: [PATCH 2/3] yes me let dogo use my wlang even tough i implementeded it --- r2chat_LEGACY.py | 100 +++++++++++++++++++++++++++++++++++++++++++++++ wlang.py | 55 ++++++++++++++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 r2chat_LEGACY.py create mode 100644 wlang.py diff --git a/r2chat_LEGACY.py b/r2chat_LEGACY.py new file mode 100644 index 0000000..8acbd1e --- /dev/null +++ b/r2chat_LEGACY.py @@ -0,0 +1,100 @@ +import tkinter as tk +from tkinter import scrolledtext +import os +import time +import getpass +from json import loads + +CHAT_FILE = "C:/Users/Public/r2chat/chat.txt" +REFRESH_INTERVAL = 1000 + +BORDER_WIDTH = 3 +THEMES = [['white','white','white','black','Basic'],['#000707','#002727','#001717','white','Aqua']] + +username = getpass.getuser() +CONFIG_FILE = f'C:/r2chat/legacy_config/{username}.r2cc' + +if not os.path.exists(CONFIG_FILE): + CFILE_C=open(CONFIG_FILE, "a") + CFILE_C.write('0\n is now online.\n is now offline.') + CFILE_C.close() + +def conf_line(n): + return((open(CONFIG_FILE).read()).split('\n')[n]) + +THEME = int(conf_line(0)) +JOIN_MESSAGE = conf_line(1) +LEAVE_MESSAGE = conf_line(2) + +class r2chat: + def __init__(self, root): + self.root = root + self.root.title(f"r2chat Legacy :: {username}") + + self.last_size = 0 + + self.chat_area = scrolledtext.ScrolledText(root, wrap='word', font=("Lucida Console", 11), bg=THEMES[THEME][1], fg=THEMES[THEME][3], relief='groove', borderwidth=BORDER_WIDTH) + self.chat_area.pack(padx=10, pady=10, fill=tk.BOTH, expand=True) + self.chat_area.bind("", lambda e: "break") + + self.entry = tk.Entry(root, font=("Lucida Console", 11), bg=THEMES[THEME][2], fg=THEMES[THEME][3], relief='groove', borderwidth=BORDER_WIDTH) + self.entry.pack(padx=10, pady=(0, 10), fill=tk.X) + self.entry.bind("", self.send_message) + + if not os.path.exists(CHAT_FILE): + open(CHAT_FILE, "a").close() + + self.update_chat() + self.write_system_message(f"{username}{JOIN_MESSAGE}") + + def on_close(self): + self.write_system_message(f"{username}{LEAVE_MESSAGE}") + self.root.destroy() + + def write_system_message(self, msg): + line = f"---- {msg} ----\n" + with open(CHAT_FILE, "a", encoding="utf-8") as f: + f.write(line) + + def send_message(self, event=None): + msg = self.entry.get().strip() + if msg: + timestamp = time.strftime("%y/%m/%d %H:%M") + line = f"[{timestamp}] {username} (legacy): {msg}\n" + try: + with open(CHAT_FILE, "a", encoding="utf-8") as f: + f.write(line) + except Exception as e: + print("oh noes! ", e) + + self.entry.delete(0, tk.END) + + def update_chat(self): + try: + current_size = os.path.getsize(CHAT_FILE) + + if current_size > self.last_size: + with open(CHAT_FILE, "r", encoding="utf-8") as f: + f.seek(self.last_size) + new_data = f.read() + self.last_size = current_size + self.chat_area.config(state='normal') + self.chat_area.insert(tk.END, new_data) + self.chat_area.config(state='disabled') + self.chat_area.yview(tk.END) + + except Exception as e: + print("oh noes! ", e) + + self.root.after(REFRESH_INTERVAL, self.update_chat) + + +if __name__ == "__main__": + root = tk.Tk() + app = r2chat(root) + root.geometry("500x520") + root.minsize(360, 520) + root.attributes('-topmost', True) + root.protocol("WM_DELETE_WINDOW", app.on_close) + root.configure(bg=THEMES[THEME][0]) + root.mainloop() diff --git a/wlang.py b/wlang.py new file mode 100644 index 0000000..6928cc0 --- /dev/null +++ b/wlang.py @@ -0,0 +1,55 @@ +import locale +import json + +# default language file +langfile='lang.json' + +# error and shit +try: + langfilecon=open(langfile).read() +except: + print('wlang error:Language file not found, continuing execution. Make sure to set the language file!') + +# default language +lang='en' +deflangfull=locale.getdefaultlocale()[0] +deflang=deflangfull[3:len(deflangfull)].lower() + +# functions +def setlangfile(lfile): + global langfile + global langfilecon + langfile=lfile + langfilecon=open(langfile).read() + +def setlang(l): + global lang + lang=l + +# get the d, n and v values +def getlangname(): + return json.loads(langfilecon)["n"] + +def getlangver(): + return json.loads(langfilecon)["v"] + +def getinlangdef(): + return json.loads(langfilecon)["d"] + +# the big one +def getobj(obj): + # sssdfg + obj=str(obj) + # get the thing + try: + return json.loads(langfilecon)["l"][lang][obj] + except: + # else use replaced + try: + return json.loads(langfilecon)["l"][json.loads(langfilecon)["r"][lang]][obj] + except: + # else use default + try: + return json.loads(langfilecon)["l"][json.loads(langfilecon)["d"]][obj] + except: + return '{'+obj+'}' # give up \ No newline at end of file From 78d1fbffd1a94222295b94316dee01dd37d020b5 Mon Sep 17 00:00:00 2001 From: win7he Date: Sat, 18 Apr 2026 01:50:27 -0500 Subject: [PATCH 3/3] update r2chat --- r2chat.py | 109 +++++++++++++++++++++++++++--------------------------- 1 file changed, 55 insertions(+), 54 deletions(-) diff --git a/r2chat.py b/r2chat.py index 970d2eb..3ebeb50 100644 --- a/r2chat.py +++ b/r2chat.py @@ -1,15 +1,14 @@ import tkinter as tk from tkinter import scrolledtext, messagebox from tkinter import ttk, colorchooser, font as tkfont -import os, sys, json +import os, sys, json, time, getpass, webbrowser, re, subprocess from pathlib import Path -import time -import getpass from plyer import notification import pygame as media -import webbrowser -import re -import subprocess +from random import randint +import wlang + +wlang.setlangfile('assets/internal/lang.json') if sys.platform == "win32": ROOT = Path("C:/Users/Public") @@ -18,8 +17,8 @@ else: try: if sys.argv[1]!='chat': - CHANCHAN = sys.argv[1].replace(' ','_').replace('.','-') - CHANNEL = 'chat_'+CHANCHAN + CHANCHAN = sys.argv[1].replace(' ','_').replace('.','-').replace('\\','/').replace(':','/') + CHANNEL = 'chat_'+CHANCHAN.replace('/','#') else: CHANNEL = 'chat' CHANCHAN = 'chat' @@ -49,11 +48,12 @@ DEFAULT_CONFIG = { "border_width": 2, "bg_color": "#f0f0f0", "fg_color": "#1e1e1e", - "user_color": "#0000ff", + "user_color": f"#{['0000ff','af0000','00af00','ffaf00','ff00ff','00ffff','7f00ff','ff7f00','00ff7f','007fff'][randint(0,9)]}", "status_join": "{username} is now online.", "status_leave": "{username} is now offline.", "status_inactive": "{username} will be right back.", - "status_busy": "{username} is busy." + "status_busy": "{username} is busy.", + "language": "en" } def load_config(): @@ -76,8 +76,8 @@ class r2chat: def __init__(self, root): self.root = root self.cfg = load_config() - self.root.title(f"r2chat :: {username} / #{CHANCHAN}") - + self.root.title(f"r2chat :: {username} / #{CHANCHAN.replace('#','/')}") + wlang.setlang(self.cfg['language']) self.last_size = 0 # configs @@ -98,28 +98,29 @@ class r2chat: ## chat menu self.chatmenu = tk.Menu(self.menubar, tearoff=0) - self.menubar.add_cascade(label="Chat", menu=self.chatmenu) - self.chatmenu.add_command(label="Registered users", command=lambda: self.show_users()) - self.chatmenu.add_command(label="Channel list", command=lambda: self.show_channels()) - self.chatmenu.add_command(label="Leave channel", command=lambda: self.on_close()) + self.menubar.add_cascade(label=wlang.getobj('chat'), menu=self.chatmenu) + self.chatmenu.add_command(label=wlang.getobj('regusers'), command=lambda: self.show_users()) + self.chatmenu.add_command(label=wlang.getobj('chlist'), command=lambda: self.show_channels()) + self.chatmenu.add_command(label=wlang.getobj('lchan'), command=lambda: self.on_close()) ## insert menu self.chatmenu = tk.Menu(self.menubar, tearoff=0) - self.menubar.add_cascade(label="Insert", menu=self.chatmenu) - self.chatmenu.add_command(label="Emoticon", command=lambda: print("")) - self.chatmenu.add_command(label="GIF", command=lambda: print("")) + self.menubar.add_cascade(label=wlang.getobj('insert'), menu=self.chatmenu) + self.chatmenu.add_command(label=wlang.getobj('emoticon'), command=lambda: print("")) + ## its pronounced jif + self.chatmenu.add_command(label=wlang.getobj('gif'), command=lambda: print("")) ## status menu self.chatmenu = tk.Menu(self.menubar, tearoff=0) - self.menubar.add_cascade(label="Status", menu=self.chatmenu) - self.chatmenu.add_command(label="Online (All notifs)", command=lambda: self.setstatus("online")) - self.chatmenu.add_command(label="Inactive (Pings only)", command=lambda: self.setstatus("inactive")) - self.chatmenu.add_command(label="Busy (No notifs)", command=lambda: self.setstatus("busy")) - self.chatmenu.add_command(label="Appear offline", command=lambda: self.setstatus("offline")) + self.menubar.add_cascade(label=wlang.getobj('status'), menu=self.chatmenu) + self.chatmenu.add_command(label=wlang.getobj('onlinestat'), command=lambda: self.setstatus("online")) + self.chatmenu.add_command(label=wlang.getobj('inactstat'), command=lambda: self.setstatus("inactive")) + self.chatmenu.add_command(label=wlang.getobj('busystat'), command=lambda: self.setstatus("busy")) + self.chatmenu.add_command(label=wlang.getobj('offlinestat'), command=lambda: self.setstatus("offline")) ## menu buttons - self.menubar.add_command(label="Preferences", command=lambda: self.openprefs()) - self.menubar.add_command(label="Help", command=lambda: webbrowser.open_new_tab("https://forgejo.nishi.boats/Dogo6647/r2chat")) + self.menubar.add_command(label=wlang.getobj('pref'), command=lambda: self.openprefs()) + self.menubar.add_command(label=wlang.getobj('help'), command=lambda: webbrowser.open_new_tab("https://forgejo.nishi.boats/Dogo6647/r2chat")) # MAIN MENU STUFFS self.entry = tk.Entry(root, relief='sunken', borderwidth=self.cfg["border_width"]) @@ -135,7 +136,7 @@ class r2chat: open(CHAT_FILE, "a").close() self.update_chat() - self.write_system_message(f'◉ {self.cfg["status_join"]}') + self.write_system_message(f'((#00af00 | ◉)) {self.cfg["status_join"]}') def on_close(self): self.write_system_message(f'◌ {self.cfg["status_leave"]}') @@ -180,13 +181,13 @@ class r2chat: status = new_status if status == "online": - self.write_system_message(msg=f'◉ {self.cfg["status_join"]}') + self.write_system_message(msg=f'((#00af00 | ◉)) {self.cfg["status_join"]}') elif status == "offline": self.write_system_message(msg=f'◌ {self.cfg["status_leave"]}') elif status == "inactive": - self.write_system_message(msg=f'◍ {self.cfg["status_inactive"]}') + self.write_system_message(msg=f'((#ffaf00 | ◍)) {self.cfg["status_inactive"]}') elif status == "busy": - self.write_system_message(msg=f'◎ {self.cfg["status_busy"]}') + self.write_system_message(msg=f'((#af0000 | ◎)) {self.cfg["status_busy"]}') self.user_data["status"] = status self.save_userdata(self.user_data) @@ -213,15 +214,15 @@ class r2chat: def show_users(self): win = tk.Toplevel(self.root) - win.title("Registered users") + win.title(wlang.getobj('regusers')) win.geometry("420x320") tree = ttk.Treeview(win, columns=("user", "status", "channels", "last_seen"), show="headings") - tree.heading("user", text="User") - tree.heading("status", text="Status") - tree.heading("channels", text="Channels") - tree.heading("last_seen", text="Last seen") + tree.heading("user", text=wlang.getobj('user')) + tree.heading("status", text=wlang.getobj('status')) + tree.heading("channels", text=wlang.getobj('chans')) + tree.heading("last_seen", text=wlang.getobj('lseen')) tree.column("user", width=80) tree.column("status", width=60, anchor="center") @@ -250,7 +251,7 @@ class r2chat: def show_channels(self): win = tk.Toplevel(self.root) win.title("Channel list") - win.geometry("200x320") + win.geometry("600x320") tree = ttk.Treeview(win, columns=("channel"), show="headings") tree.heading("channel", text="Channels") @@ -275,7 +276,7 @@ class r2chat: tree.bind("", on_select) def open_channel(self, channel): - self.write_system_message(f"⇄ {username} is chatting in {channel}.") + self.write_system_message(f"((#006fff | ⇄)) {username} is chatting in {channel.replace('#','/')}.") if sys.platform == "win32": subprocess.Popen(f'pythonw "{os.path.abspath(__file__)}" "{channel}"', shell=True) else: @@ -317,7 +318,7 @@ class r2chat: try: current_size = os.path.getsize(CHAT_FILE) - if current_size > self.last_size: + if current_size != self.last_size: with open(CHAT_FILE, "r", encoding="utf-8") as f: f.seek(self.last_size) new_data = f.read() @@ -326,7 +327,7 @@ class r2chat: self.chat_area.config(state='normal') if f"@{username} " in new_data and not "---" in new_data and not status == "busy" and not status == "offline": media.mixer.Sound("assets/internal/ping.ogg").play() - messagebox.showinfo("Important message!", new_data) + messagebox.showinfo(wlang.getobj('impmes'), new_data) if self.root.wm_state() == 'iconic': if not f"@{username} " in new_data and not status == "busy" and not status == "inactive": notification.notify(title="r2chat", message=new_data) @@ -347,7 +348,7 @@ class PreferencesWindow: self.on_save = on_save self.win = tk.Toplevel(parent) - self.win.title("r2chat prefs") + self.win.title(f"r2chat {wlang.getobj('prefl')}") self.win.geometry("420x520") self.win.resizable(False, False) self.win.transient(parent) @@ -366,16 +367,16 @@ class PreferencesWindow: btn_frame = tk.Frame(self.win) btn_frame.pack(fill=tk.X, padx=10, pady=(0, 10)) - tk.Button(btn_frame, text="Save", width=10, command=self._save).pack(side=tk.RIGHT, padx=(4, 0)) - tk.Button(btn_frame, text="Cancel", width=10, command=self.win.destroy).pack(side=tk.RIGHT) - tk.Button(btn_frame, text="Back to defaults", command=self._reset).pack(side=tk.LEFT) + tk.Button(btn_frame, text=wlang.getobj('save'), width=10, command=self._save).pack(side=tk.RIGHT, padx=(4, 0)) + tk.Button(btn_frame, text=wlang.getobj('cancel'), width=10, command=self.win.destroy).pack(side=tk.RIGHT) + tk.Button(btn_frame, text=wlang.getobj('btodef'), command=self._reset).pack(side=tk.LEFT) def _build_appearance_tab(self, notebook): frame = tk.Frame(notebook) - notebook.add(frame, text="Interface") + notebook.add(frame, text=wlang.getobj('interface')) # font family - self._row(frame, 0, "Font family") + self._row(frame, 0, wlang.getobj('ffam')) font_var = tk.StringVar(value=self.cfg["font_family"]) self.vars["font_family"] = font_var families = sorted(tkfont.families()) @@ -383,34 +384,34 @@ class PreferencesWindow: font_combo.grid(row=0, column=1, padx=10, pady=6, sticky=tk.W) # font size - self._row(frame, 1, "Font size") + self._row(frame, 1, wlang.getobj('fsiz')) size_var = tk.IntVar(value=self.cfg["font_size"]) self.vars["font_size"] = size_var tk.Spinbox(frame, from_=7, to=24, textvariable=size_var, width=6).grid(row=1, column=1, padx=10, pady=6, sticky=tk.W) # border width - self._row(frame, 2, "Frame thickness") + self._row(frame, 2, wlang.getobj('fthi')) bw_var = tk.IntVar(value=self.cfg["border_width"]) self.vars["border_width"] = bw_var tk.Spinbox(frame, from_=0, to=6, textvariable=bw_var, width=6).grid(row=2, column=1, padx=10, pady=6, sticky=tk.W) # color pickers for i, (key, label) in enumerate([ - ("bg_color", "Background color"), - ("fg_color", "Text color"), - ("user_color", "Username color"), + ("bg_color", wlang.getobj('backc')), + ("fg_color", wlang.getobj('textc')), + ("user_color", wlang.getobj('userc')), ], start=3): self._row(frame, i, label) self._color_picker_row(frame, i, key) def _build_status_messages_tab(self, notebook): frame = tk.Frame(notebook) - notebook.add(frame, text="Status messages") + notebook.add(frame, text=wlang.getobj('statmes')) - tk.Label(frame, text="Use {username} where you want your username to be.", fg="gray", font=("Lucida Console", 9)).grid( + tk.Label(frame, text=wlang.getobj('usernh'), fg="gray", font=("Lucida Console", 9)).grid( row=0, column=0, columnspan=2, padx=10, pady=(10, 4), sticky=tk.W) - for i, (key, label) in enumerate([("status_join", "Join message"),("status_leave", "Leave message"),("status_inactive", "Inactive message"),("status_busy", "Busy message")], start=1): + for i, (key, label) in enumerate([("status_join", wlang.getobj('joinm')),("status_leave", wlang.getobj('leavm')),("status_inactive", wlang.getobj('inacm')),("status_busy", wlang.getobj('busym'))], start=1): self._row(frame, i, label) var = tk.StringVar(value=self.cfg[key]) self.vars[key] = var @@ -432,7 +433,7 @@ class PreferencesWindow: v.set(result[1]) p.config(bg=result[1]) - tk.Button(frame, text="Choose…", command=pick, width=8).grid(row=row, column=1, padx=(44, 0), pady=6, sticky=tk.W) + tk.Button(frame, text=wlang.getobj('choose'), command=pick, width=8).grid(row=row, column=1, padx=(44, 0), pady=6, sticky=tk.W) def _save(self): for key, var in self.vars.items():