Add translation

This commit is contained in:
月月
2024-09-16 16:40:54 +08:00
parent 73334862c6
commit 69adcbbda5
20 changed files with 312 additions and 123 deletions
+1 -2
View File
@@ -37,7 +37,7 @@ async function loadLanguage(lang) {
// Get translation, if no corresponding value, return the key // Get translation, if no corresponding value, return the key
function getString(key) { function getString(key) {
if (!translations[currentLanguage]?.[key]) { if (!translations[currentLanguage]?.[key] && key) {
console.log('Not found:' + key); console.log('Not found:' + key);
} }
return translations[currentLanguage]?.[key] || key; return translations[currentLanguage]?.[key] || key;
@@ -48,7 +48,6 @@ function init() {
try { try {
loadLanguage(currentLanguage); loadLanguage(currentLanguage);
console.log("初始化完成"); console.log("初始化完成");
} catch (error) { } catch (error) {
console.error('Failed to initialize default language:', error); console.error('Failed to initialize default language:', error);
} }
+180 -3
View File
@@ -1,6 +1,5 @@
{ {
"No media": "无媒体活动", "No media": "无媒体活动",
"Clear": "清除",
"Assistant": "助手", "Assistant": "助手",
"Powered by Google": "由谷歌提供技术支持", "Powered by Google": "由谷歌提供技术支持",
"Uses gemini-pro.\nNot affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\n but will be read by human reviewers to improve the model.": "使用 gemini-pro\n不隶属于、不受谷歌赞助或支持。\n\n隐私:聊天信息不会与你的账户关联。\n但会被人类审阅者阅读,用于改进模型。", "Uses gemini-pro.\nNot affiliated, endorsed, or sponsored by Google.\n\nPrivacy: Chat messages aren't linked to your account,\n but will be read by human reviewers to improve the model.": "使用 gemini-pro\n不隶属于、不受谷歌赞助或支持。\n\n隐私:聊天信息不会与你的账户关联。\n但会被人类审阅者阅读,用于改进模型。",
@@ -19,6 +18,11 @@
"Updated API Key at": "更新了 API 密钥于", "Updated API Key at": "更新了 API 密钥于",
"Currently using": "当前使用", "Currently using": "当前使用",
"Select ChatGPT-compatible API provider": "选择与 ChatGPT 兼容的 API 提供商", "Select ChatGPT-compatible API provider": "选择与 ChatGPT 兼容的 API 提供商",
"Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.": "官方 OpenAI API。\n定价:前 $5 或前 3 个月免费,取较小者。",
"Official Ollama API.\nPricing: Free.": "官方 Ollama API。\n定价:免费。",
"A unified interface for LLMs": "LLM 的统一接口",
"An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key": "来自 Tornado Softwares 的 API\n定价:免费:每天 100 次请求\n需要加入他们的 Discord 以获取密钥",
"An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it's buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key": "来自GitHub上的@zukixa的API。\n注意:密钥与IP绑定,所以有时会出错。\n定价:免费:每分钟10次,每天800次。\n需要加入他们的Discord才能获得密钥。",
"Provider shown above": "上述显示的提供商", "Provider shown above": "上述显示的提供商",
"Uses gpt-3.5-turbo.\nNot affiliated, endorsed, or sponsored by OpenAI.\n\nPrivacy: OpenAI claims they do not use your data\nwhen you use their API. Idk about others.": "使用 gpt-3.5-turbo。\n与 OpenAI 无关联,未获得其认可或赞助。\n\n隐私:OpenAI 声明,当您使用他们的 API 时,他们不会使用您的数据。\n我不清楚其他人的情况。", "Uses gpt-3.5-turbo.\nNot affiliated, endorsed, or sponsored by OpenAI.\n\nPrivacy: OpenAI claims they do not use your data\nwhen you use their API. Idk about others.": "使用 gpt-3.5-turbo。\n与 OpenAI 无关联,未获得其认可或赞助。\n\n隐私:OpenAI 声明,当您使用他们的 API 时,他们不会使用您的数据。\n我不清楚其他人的情况。",
"The model's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "模型的temperature值。\n 精确 = 0\n 平衡 = 0.5\n 创意 = 1", "The model's temperature value.\n Precise = 0\n Balanced = 0.5\n Creative = 1": "模型的temperature值。\n 精确 = 0\n 平衡 = 0.5\n 创意 = 1",
@@ -37,7 +41,7 @@
"Saves images in folders by their tags": "按标签将图片保存到文件夹中", "Saves images in folders by their tags": "按标签将图片保存到文件夹中",
"Message Gemini...": "向Gemini发消息...", "Message Gemini...": "向Gemini发消息...",
"Enter Google AI API Key...": "输入 Google AI API 密钥...", "Enter Google AI API Key...": "输入 Google AI API 密钥...",
"Message the model...": "模型发消息...", "Message the model...": "模型发消息...",
"Enter API Key...": "输入 API 密钥...", "Enter API Key...": "输入 API 密钥...",
"Enter tags": "输入标签", "Enter tags": "输入标签",
"Quick scripts": "快速脚本", "Quick scripts": "快速脚本",
@@ -49,5 +53,178 @@
"Uninstall unused flatpak packages": "卸载未使用的 Flatpak 包", "Uninstall unused flatpak packages": "卸载未使用的 Flatpak 包",
"<span strikethrough=\"true\">Inaccurate</span> Color picker": "<span strikethrough=\"true\">不准确</span> 颜色选择器", "<span strikethrough=\"true\">Inaccurate</span> Color picker": "<span strikethrough=\"true\">不准确</span> 颜色选择器",
"Result": "结果", "Result": "结果",
"illogical-impulse": "illogical-impulse" "Type to search": "输入以搜索",
"illogical-impulse": "illogical-impulse",
"RAM Usage": "RAM使用情况",
"Swap Usage": "Swap使用情况",
"CPU Usage": "CPU使用情况",
"Uptime:": "运行时间:",
"Screen snip": "屏幕截图",
"Color picker": "颜色选择器",
"Toggle on-screen keyboard": "切换屏幕键盘",
"Night Light": "夜灯",
"Color inversion": "颜色反转",
"Keep system awake": "保持系统唤醒",
"Cloudflare WARP": "Cloudflare WARP",
"Session": "会话",
"Bluetooth | Right-click to configure": "蓝牙 | 右键单击以配置",
"Wifi | Right-click to configure": "Wi-Fi | 右键单击以配置",
"Right-click to configure": "右键单击以配置",
"Unknown": "未知",
"Reload Environment config": "重新加载环境配置",
"Open Settings": "打开设置",
"Notifications": "通知",
"Audio controls": "音频控制",
"Bluetooth": "蓝牙",
"Wifi networks": "Wi-Fi 网络",
"Live config": "实时配置",
"Silence": "静音",
"Clear": "清除",
"No notifications": "没有通知",
"notifications": "条通知",
"Close": "关闭",
"Now": "刚才",
"Yesterday": "昨天",
"No audio source": "没有音频源",
"Remove device": "移除设备",
"Connected": "已连接",
"Paired": "配对",
"More": "更多",
"Selected": "已选中",
"Current network": "当前网络",
"Authentication": "身份验证",
"Effects": "效果",
"Transparency": "透明度",
"[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this": "[AGS]\n使外壳元素透明\n如果启用此功能,也建议使用模糊效果",
"Blur": "模糊",
"[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.": "[Hyprland]\n在透明元素上启用模糊效果\n除非您有透明窗口,否则不会影响性能/功耗。",
"X-ray": "X-ray",
"[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ": "[Hyprland]\n使窗口/图层后面的所有内容(除了壁纸)在其模糊表面上不渲染\n建议提高性能(如果您不滥用透明度/模糊)",
"Size": "大小",
"[Hyprland]\nAdjust the blur radius. Generally doesn't affect performance\nHigher = more color spread": "[Hyprland]\n调整模糊半径。通常不会影响性能\n数值越高 = 颜色扩散越大",
"Passes": "次数",
"[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.": "[Hyprland]\n调整模糊算法的运行次数\n次数越多 = 扩散越大,功耗越高\n建议使用 4 次\n2 次看起来很奇怪,6 次以上看起来很糟糕。",
"Animations": "动画",
"[Hyprland] [GTK]\nEnable animations": "[Hyprland] [GTK]\n启用动画",
"Choreography delay": "间隔",
"In milliseconds, the delay between animations of a series": "以毫秒为单位,一系列动画之间的延迟",
"Developer": "开发者",
"Show FPS": "显示FPS",
"[Hyprland]\nShow FPS overlay on top-left corner": "[Hyprland]\n在左上角显示 FPS 叠加层",
"Log to stdout": "输出日志",
"[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console": "[Hyprland]\n将 LOG、ERR、WARN 等消息打印到控制台",
"Damage tracking": "损坏跟踪",
"[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work": "[Hyprland]\n启用损坏跟踪\n通常情况下,保持启用状态\n仅当着色器无法正常工作时才禁用",
"Damage blink": "显示视图更新",
"[Hyprland] [Epilepsy warning!]\nShow screen damage flashes": "[Hyprland] [癫痫警告!]\n屏幕视图更新时闪烁",
"Not all changes are saved": "并非所有更改都已保存",
"Mo": "一",
"Tu": "二",
"We": "三",
"Th": "四",
"Fr": "五",
"Sa": "六",
"Su": "日",
"Calendar": "日历",
"To Do": "待办",
"Unfinished": "未完成",
"Done": "已完成",
"Finished tasks will go here": "已完成的任务将显示在此处",
"Nothing here!": "这里什么也没有!",
"+ New task": "+ 新任务",
"Add a task...": "添加任务...",
"Color scheme": "配色方案",
"Options": "选项",
"Dark Mode": "深色模式",
"Ya should go to sleep!": "你应该去睡觉!",
"Use Gradience": "GTK主题",
"Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)": "使用强调色对 GTK 应用程序进行主题化\n(缺点:深色/浅色模式切换需要重启)",
"Scheme styles": "样式方案",
"Vibrant": "鲜艳",
"Vibrant+": "鲜艳+",
"Expressive": "表现力",
"Monochrome": "黑白",
"Rainbow": "彩虹",
"Fidelity": "保真度",
"Fruit Salad": "水果沙拉",
"Tonal Spot": "色调点",
"Content": "内容",
"Use arrow keys to navigate.\nEnter to select, Esc to cancel.": "使用箭头键导航。\n回车键选择,Esc 键取消。",
"Lock": "锁屏",
"Logout": "注销",
"Sleep": "睡眠",
"Hibernate": "休眠",
"Shutdown": "关机",
"Reboot": "重启",
"Cancel": "取消",
"Cheat sheet": "备忘单",
"Keybinds": "按键绑定",
"Periodic table": "元素周期表",
"Essentials for beginners": "初学者必备",
"Make shell elements transparent": "使外壳元素透明",
"Actions": "操作",
"Window management": "窗口管理",
"Window arrangement": "窗口排列",
"Workspace management": "工作区管理",
"Workspace navigation": "工作区导航",
"Widgets": "小部件",
"Media": "媒体",
"Apps": "应用程序",
"Neutral": "中性",
"Launch foot (terminal)": "启动终端(foot",
"Open app launcher": "打开应用程序启动器",
"Change wallpaper": "更改壁纸",
"Clipboard history >> clipboard": "剪贴板历史 >> 剪贴板",
"Pick emoji >> clipboard": "选择表情符号 >> 剪贴板",
"Screen snip >> edit": "屏幕截图 >> 编辑",
"Screen snip to text >> clipboard": "屏幕截图转文字 >> 剪贴板",
"Pick color (Hex) >> clipboard": "选择颜色(十六进制)>> 剪贴板",
"Screenshot >> clipboard": "屏幕截图 >> 剪贴板",
"Screenshot >> clipboard & file": "屏幕截图 >> 剪贴板和文件",
"Record region (no sound)": "录制区域(无声音)",
"Record screen (with sound)": "录制屏幕(带声音)",
"Suspend system": "挂起系统",
"Move focus in direction": "在方向上移动焦点",
"Move window": "移动窗口",
"Resize window": "调整窗口大小",
"Close window": "关闭窗口",
"Pick and kill a window": "选择并关闭一个窗口",
"Window: move in direction": "窗口:在方向上移动",
"Window: split ratio +/- 0.1": "窗口:分割比例 +/- 0.1",
"Float/unfloat window": "浮动/取消浮动窗口",
"Toggle fake fullscreen": "切换伪全屏",
"Toggle fullscreen": "切换全屏",
"Toggle maximization": "切换最大化",
"Focus workspace # (1, 2, 3, 4, ...)": "聚焦工作区 #1, 2, 3, 4, ...",
"Workspace: focus left/right": "工作区:聚焦左右",
"Workspace: toggle special": "工作区:切换特殊",
"Window: move to workspace # (1, 2, 3, 4, ...)": "窗口:移动到工作区 #1, 2, 3, 4, ...",
"Window: move to workspace left/right": "窗口:移动到左右工作区",
"Window: move to workspace special": "窗口:移动到特殊工作区",
"Window: pin (show on all workspaces)": "窗口:固定(在所有工作区显示)",
"Restart widgets": "重启小部件",
"Cycle bar mode (normal, focus)": "循环栏模式(正常,聚焦)",
"Toggle overview/launcher": "切换概览/启动器",
"Show cheatsheet": "显示快捷键表",
"Toggle left sidebar": "切换左侧边栏",
"Toggle right sidebar": "切换右侧边栏",
"Toggle music controls": "切换音乐控制",
"View color scheme and options": "查看配色方案和选项",
"Toggle power menu": "切换电源菜单",
"Toggle crosshair": "切换准星",
"Next track": "下一曲目",
"Previous track": "上一曲目",
"Play/pause media": "播放/暂停媒体",
"Launch Zed (editor)": "启动Zed(编辑器)",
"Launch VSCode (editor)": "启动VSCode(编辑器)",
"Launch Nautilus (file manager)": "启动Nautilus(文件管理器)",
"Launch Firefox (browser)": "启动Firefox(浏览器)",
"Launch GNOME Text Editor": "启动GNOME文本编辑器",
"Launch WPS Office": "启动WPS办公软件",
"Launch GNOME Settings": "启动GNOME设置",
"Launch pavucontrol (volume mixer)": "启动pavucontrol(音量混合器)",
"Launch EasyEffects (equalizer & other audio effects)": "启动EasyEffects(均衡器和其他音频效果)",
"Launch GNOME System monitor": "启动GNOME系统监视器",
"Toggle fallback launcher: anyrun": "切换备用启动器:anyrun",
"Toggle fallback launcher: fuzzel": "切换备用启动器:fuzzel"
} }
@@ -6,6 +6,7 @@ const { Box, EventBox, Icon, Overlay, Label, Button, Revealer } = Widget;
import { MaterialIcon } from './materialicon.js'; import { MaterialIcon } from './materialicon.js';
import { setupCursorHover } from "../.widgetutils/cursorhover.js"; import { setupCursorHover } from "../.widgetutils/cursorhover.js";
import { AnimatedCircProg } from "./cairo_circularprogress.js"; import { AnimatedCircProg } from "./cairo_circularprogress.js";
import { getString } from '../../i18n/i18n.js';
function guessMessageType(summary) { function guessMessageType(summary) {
const str = summary.toLowerCase(); const str = summary.toLowerCase();
@@ -29,11 +30,11 @@ const getFriendlyNotifTimeString = (timeObject) => {
const messageTime = GLib.DateTime.new_from_unix_local(timeObject); const messageTime = GLib.DateTime.new_from_unix_local(timeObject);
const oneMinuteAgo = GLib.DateTime.new_now_local().add_seconds(-60); const oneMinuteAgo = GLib.DateTime.new_now_local().add_seconds(-60);
if (messageTime.compare(oneMinuteAgo) > 0) if (messageTime.compare(oneMinuteAgo) > 0)
return 'Now'; return getString('Now');
else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year()) else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year())
return messageTime.format(userOptions.time.format); return messageTime.format(userOptions.time.format);
else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year() - 1) else if (messageTime.get_day_of_year() == GLib.DateTime.new_now_local().get_day_of_year() - 1)
return 'Yesterday'; return getString('Yesterday');
else else
return messageTime.format(userOptions.time.dateFormat); return messageTime.format(userOptions.time.dateFormat);
} }
@@ -198,7 +199,7 @@ export default ({
onClicked: () => destroyWithAnims(), onClicked: () => destroyWithAnims(),
setup: setupCursorHover, setup: setupCursorHover,
child: Label({ child: Label({
label: 'Close', label: getString('Close'),
}), }),
}), }),
...notifObject.actions.map(action => Widget.Button({ ...notifObject.actions.map(action => Widget.Button({
+3 -3
View File
@@ -183,7 +183,7 @@ export default () => {
} else return BarGroup({ } else return BarGroup({
child: Box({ child: Box({
children: [ children: [
BarResource('RAM Usage', 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`, BarResource(getString('RAM Usage'), 'memory', `LANG=C free | awk '/^Mem/ {printf("%.2f\\n", ($3/$2) * 100)}'`,
'bar-ram-circprog', 'bar-ram-txt', 'bar-ram-icon'), 'bar-ram-circprog', 'bar-ram-txt', 'bar-ram-icon'),
Revealer({ Revealer({
revealChild: true, revealChild: true,
@@ -192,9 +192,9 @@ export default () => {
child: Box({ child: Box({
className: 'spacing-h-10 margin-left-10', className: 'spacing-h-10 margin-left-10',
children: [ children: [
BarResource('Swap Usage', 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`, BarResource(getString('Swap Usage'), 'swap_horiz', `LANG=C free | awk '/^Swap/ {if ($2 > 0) printf("%.2f\\n", ($3/$2) * 100); else print "0";}'`,
'bar-swap-circprog', 'bar-swap-txt', 'bar-swap-icon'), 'bar-swap-circprog', 'bar-swap-txt', 'bar-swap-icon'),
BarResource('CPU Usage', 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`, BarResource(getString('CPU Usage'), 'settings_motion_mode', `LANG=C top -bn1 | grep Cpu | sed 's/\\,/\\./g' | awk '{print $2}'`,
'bar-cpu-circprog', 'bar-cpu-txt', 'bar-cpu-icon'), 'bar-cpu-circprog', 'bar-cpu-txt', 'bar-cpu-icon'),
] ]
}), }),
+4 -3
View File
@@ -8,6 +8,7 @@ import Battery from 'resource:///com/github/Aylur/ags/service/battery.js';
import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
import { AnimatedCircProg } from "../../.commonwidgets/cairo_circularprogress.js"; import { AnimatedCircProg } from "../../.commonwidgets/cairo_circularprogress.js";
import { WWO_CODE, WEATHER_SYMBOL, NIGHT_WEATHER_SYMBOL } from '../../.commondata/weather.js'; import { WWO_CODE, WEATHER_SYMBOL, NIGHT_WEATHER_SYMBOL } from '../../.commondata/weather.js';
import { getString } from '../../../i18n/i18n.js';
const WEATHER_CACHE_FOLDER = `${GLib.get_user_cache_dir()}/ags/weather`; const WEATHER_CACHE_FOLDER = `${GLib.get_user_cache_dir()}/ags/weather`;
Utils.exec(`mkdir -p ${WEATHER_CACHE_FOLDER}`); Utils.exec(`mkdir -p ${WEATHER_CACHE_FOLDER}`);
@@ -74,18 +75,18 @@ const Utilities = () => Box({
className: 'spacing-h-4', className: 'spacing-h-4',
children: [ children: [
UtilButton({ UtilButton({
name: 'Screen snip', icon: 'screenshot_region', onClicked: () => { name: getString('Screen snip'), icon: 'screenshot_region', onClicked: () => {
Utils.execAsync(`${App.configDir}/scripts/grimblast.sh copy area`) Utils.execAsync(`${App.configDir}/scripts/grimblast.sh copy area`)
.catch(print) .catch(print)
} }
}), }),
UtilButton({ UtilButton({
name: 'Color picker', icon: 'colorize', onClicked: () => { name: getString('Color picker'), icon: 'colorize', onClicked: () => {
Utils.execAsync(['hyprpicker', '-a']).catch(print) Utils.execAsync(['hyprpicker', '-a']).catch(print)
} }
}), }),
UtilButton({ UtilButton({
name: 'Toggle on-screen keyboard', icon: 'keyboard', onClicked: () => { name: getString('Toggle on-screen keyboard'), icon: 'keyboard', onClicked: () => {
toggleWindowOnAllMonitors('osk'); toggleWindowOnAllMonitors('osk');
} }
}), }),
+4 -4
View File
@@ -12,8 +12,8 @@ const getKeybindList = () => {
let data = Utils.exec(`${App.configDir}/scripts/hyprland/get_keybinds.py --path ${HYPRLAND_KEYBIND_CONFIG_FILE}`); let data = Utils.exec(`${App.configDir}/scripts/hyprland/get_keybinds.py --path ${HYPRLAND_KEYBIND_CONFIG_FILE}`);
if (data == "\"error\"") { if (data == "\"error\"") {
Utils.timeout(2000, () => Utils.execAsync(['notify-send', Utils.timeout(2000, () => Utils.execAsync(['notify-send',
'Update path to keybinds', 'Update path to keybinds',
'Keybinds hyprland config file not found. Check your user options.', 'Keybinds hyprland config file not found. Check your user options.',
'-a', 'ags', '-a', 'ags',
]).catch(print)) ]).catch(print))
return { children: [] }; return { children: [] };
@@ -45,7 +45,7 @@ const Keybind = (keybindData, type) => { // type: either "keys" or "actions"
}); });
const Action = (text) => Label({ // Binds const Action = (text) => Label({ // Binds
xalign: 0, xalign: 0,
label: text, label: getString(text),
className: "txt txt-small cheatsheet-action", className: "txt txt-small cheatsheet-action",
}) })
return Widget.Box({ return Widget.Box({
@@ -74,7 +74,7 @@ const Section = (sectionData, scope) => {
const name = Label({ const name = Label({
xalign: 0, xalign: 0,
className: "cheatsheet-category-title txt margin-bottom-10", className: "cheatsheet-category-title txt margin-bottom-10",
label: sectionData.name, label: getString(sectionData.name),
}) })
const binds = Box({ const binds = Box({
className: 'spacing-h-10', className: 'spacing-h-10',
+3 -3
View File
@@ -9,12 +9,12 @@ import clickCloseRegion from '../.commonwidgets/clickcloseregion.js';
const cheatsheets = [ const cheatsheets = [
{ {
name: 'Keybinds', name: getString('Keybinds'),
materialIcon: 'keyboard', materialIcon: 'keyboard',
contentWidget: Keybinds, contentWidget: Keybinds,
}, },
{ {
name: 'Periodic table', name: getString('Periodic table'),
materialIcon: 'experiment', materialIcon: 'experiment',
contentWidget: PeriodicTable, contentWidget: PeriodicTable,
}, },
@@ -35,7 +35,7 @@ const CheatsheetHeader = () => Widget.CenterBox({
hpack: 'center', hpack: 'center',
css: 'margin-right: 0.682rem;', css: 'margin-right: 0.682rem;',
className: 'txt-title', className: 'txt-title',
label: 'Cheat sheet', label: getString('Cheat sheet'),
}), }),
Widget.Label({ Widget.Label({
vpack: 'center', vpack: 'center',
+19 -19
View File
@@ -78,22 +78,22 @@ function calculateSchemeInitIndex(optionsArr, searchValue = 'vibrant') {
const schemeOptionsArr = [ const schemeOptionsArr = [
[ [
{ name: 'Tonal Spot', value: 'tonalspot' }, { name: getString('Tonal Spot'), value: 'tonalspot' },
{ name: 'Fruit Salad', value: 'fruitsalad' }, { name: getString('Fruit Salad'), value: 'fruitsalad' },
{ name: 'Fidelity', value: 'fidelity' }, { name: getString('Fidelity'), value: 'fidelity' },
{ name: 'Rainbow', value: 'rainbow' }, { name: getString('Rainbow'), value: 'rainbow' },
], ],
[ [
{ name: 'Neutral', value: 'neutral' }, { name: getString('Neutral'), value: 'neutral' },
{ name: 'Monochrome', value: 'monochrome' }, { name: getString('Monochrome'), value: 'monochrome' },
{ name: 'Expressive', value: 'expressive' }, { name: getString('Expressive'), value: 'expressive' },
{ name: 'Vibrant', value: 'vibrant' }, { name: getString('Vibrant'), value: 'vibrant' },
], ],
[ [
{ name: 'Vibrant+', value: 'morevibrant' }, { name: getString('Vibrant+'), value: 'morevibrant' },
], ],
//[ //[
// { name: 'Content', value: 'content' }, // { name: getString('Content'), value: 'content' },
//] //]
]; ];
@@ -114,14 +114,14 @@ const ColorSchemeSettings = () => Widget.Box({
Widget.Label({ Widget.Label({
xalign: 0, xalign: 0,
className: 'txt-norm titlefont txt', className: 'txt-norm titlefont txt',
label: 'Options', label: getString('Options'),
hpack: 'center', hpack: 'center',
}), }),
////////////////// //////////////////
ConfigToggle({ ConfigToggle({
icon: 'dark_mode', icon: 'dark_mode',
name: 'Dark Mode', name: getString('Dark Mode'),
desc: 'Ya should go to sleep!', desc: getString('Ya should go to sleep!'),
initValue: darkMode.value, initValue: darkMode.value,
onChange: (_, newValue) => { onChange: (_, newValue) => {
darkMode.value = !!newValue; darkMode.value = !!newValue;
@@ -132,8 +132,8 @@ const ColorSchemeSettings = () => Widget.Box({
}), }),
ConfigToggle({ ConfigToggle({
icon: 'border_clear', icon: 'border_clear',
name: 'Transparency', name: getString('Transparency'),
desc: 'Make shell elements transparent', desc: getString('Make shell elements transparent'),
initValue: initTransparencyVal, initValue: initTransparencyVal,
onChange: (self, newValue) => { onChange: (self, newValue) => {
let transparency = newValue == 0 ? "opaque" : "transparent"; let transparency = newValue == 0 ? "opaque" : "transparent";
@@ -143,13 +143,13 @@ const ColorSchemeSettings = () => Widget.Box({
}, },
}), }),
Widget.Box({ Widget.Box({
tooltipText: 'Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)', tooltipText: getString('Theme GTK apps using accent color\n(drawback: dark/light mode switching requires restart)'),
className: 'txt spacing-h-5 configtoggle-box', className: 'txt spacing-h-5 configtoggle-box',
children: [ children: [
MaterialIcon('imagesearch_roller', 'norm'), MaterialIcon('imagesearch_roller', 'norm'),
Widget.Label({ Widget.Label({
className: 'txt txt-small', className: 'txt txt-small',
label: 'Use Gradience', label: getString('Use Gradience'),
}), }),
Widget.Box({ hexpand: true }), Widget.Box({ hexpand: true }),
ConfigMulipleSelection({ ConfigMulipleSelection({
@@ -179,7 +179,7 @@ const ColorSchemeSettings = () => Widget.Box({
Widget.Label({ Widget.Label({
xalign: 0, xalign: 0,
className: 'txt-norm titlefont txt margin-top-5', className: 'txt-norm titlefont txt margin-top-5',
label: 'Scheme styles', label: getString('Scheme styles'),
hpack: 'center', hpack: 'center',
}), }),
////////////////// //////////////////
@@ -207,7 +207,7 @@ const ColorschemeContent = () => Widget.Box({
Widget.Label({ Widget.Label({
xalign: 0, xalign: 0,
className: 'txt-norm titlefont txt', className: 'txt-norm titlefont txt',
label: 'Color scheme', label: getString('Color scheme'),
hpack: 'center', hpack: 'center',
}), }),
Widget.Box({ Widget.Box({
@@ -70,7 +70,7 @@ export const SearchAndWindows = () => {
hpack: 'center', hpack: 'center',
child: Widget.Label({ child: Widget.Label({
className: 'overview-search-prompt txt-small txt', className: 'overview-search-prompt txt-small txt',
label: 'Type to search' label: getString('Type to search')
}), }),
}); });
+9 -9
View File
@@ -61,14 +61,14 @@ const SessionButton = (name, icon, command, props = {}, colorid = 0) => {
export default ({ id = 0 }) => { export default ({ id = 0 }) => {
// lock, logout, sleep // lock, logout, sleep
const lockButton = SessionButton('Lock', 'lock', () => { closeWindowOnAllMonitors('session'); execAsync(['loginctl', 'lock-session']).catch(print) }, {}, 1); const lockButton = SessionButton(getString('Lock'), 'lock', () => { closeWindowOnAllMonitors('session'); execAsync(['loginctl', 'lock-session']).catch(print) }, {}, 1);
const logoutButton = SessionButton('Logout', 'logout', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'pkill Hyprland || pkill sway || pkill niri || loginctl terminate-user $USER']).catch(print) }, {}, 2); const logoutButton = SessionButton(getString('Logout'), 'logout', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'pkill Hyprland || pkill sway || pkill niri || loginctl terminate-user $USER']).catch(print) }, {}, 2);
const sleepButton = SessionButton('Sleep', 'sleep', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl suspend || loginctl suspend']).catch(print) }, {}, 3); const sleepButton = SessionButton(getString('Sleep'), 'sleep', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl suspend || loginctl suspend']).catch(print) }, {}, 3);
// hibernate, shutdown, reboot // hibernate, shutdown, reboot
const hibernateButton = SessionButton('Hibernate', 'downloading', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl hibernate || loginctl hibernate']).catch(print) }, {}, 4); const hibernateButton = SessionButton(getString('Hibernate'), 'downloading', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl hibernate || loginctl hibernate']).catch(print) }, {}, 4);
const shutdownButton = SessionButton('Shutdown', 'power_settings_new', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl poweroff || loginctl poweroff']).catch(print) }, {}, 5); const shutdownButton = SessionButton(getString('Shutdown'), 'power_settings_new', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl poweroff || loginctl poweroff']).catch(print) }, {}, 5);
const rebootButton = SessionButton('Reboot', 'restart_alt', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl reboot || loginctl reboot']).catch(print) }, {}, 6); const rebootButton = SessionButton(getString('Reboot'), 'restart_alt', () => { closeWindowOnAllMonitors('session'); execAsync(['bash', '-c', 'systemctl reboot || loginctl reboot']).catch(print) }, {}, 6);
const cancelButton = SessionButton('Cancel', 'close', () => closeWindowOnAllMonitors('session'), { className: 'session-button-cancel' }, 7); const cancelButton = SessionButton(getString('Cancel'), 'close', () => closeWindowOnAllMonitors('session'), { className: 'session-button-cancel' }, 7);
const sessionDescription = Widget.Box({ const sessionDescription = Widget.Box({
vertical: true, vertical: true,
@@ -76,12 +76,12 @@ export default ({ id = 0 }) => {
children: [ children: [
Widget.Label({ Widget.Label({
className: 'txt-title txt', className: 'txt-title txt',
label: 'Session', label: getString('Session'),
}), }),
Widget.Label({ Widget.Label({
justify: Gtk.Justification.CENTER, justify: Gtk.Justification.CENTER,
className: 'txt-small txt', className: 'txt-small txt',
label: 'Use arrow keys to navigate.\nEnter to select, Esc to cancel.' label: getString('Use arrow keys to navigate.\nEnter to select, Esc to cancel.')
}), }),
] ]
}); });
+10 -9
View File
@@ -7,6 +7,7 @@ import { setupCursorHover } from '../.widgetutils/cursorhover.js';
import { TodoWidget } from "./todolist.js"; import { TodoWidget } from "./todolist.js";
import { getCalendarLayout } from "./calendar_layout.js"; import { getCalendarLayout } from "./calendar_layout.js";
import { getString } from '../../i18n/i18n.js';
let calendarJson = getCalendarLayout(undefined, true); let calendarJson = getCalendarLayout(undefined, true);
let monthshift = 0; let monthshift = 0;
@@ -30,13 +31,13 @@ function getDateInXMonthsTime(x) {
} }
const weekDays = [ // MONDAY IS THE FIRST DAY OF THE WEEK :HESRIGHTYOUKNOW: const weekDays = [ // MONDAY IS THE FIRST DAY OF THE WEEK :HESRIGHTYOUKNOW:
{ day: 'Mo', today: 0 }, { day: getString('Mo'), today: 0 },
{ day: 'Tu', today: 0 }, { day: getString('Tu'), today: 0 },
{ day: 'We', today: 0 }, { day: getString('We'), today: 0 },
{ day: 'Th', today: 0 }, { day: getString('Th'), today: 0 },
{ day: 'Fr', today: 0 }, { day: getString('Fr'), today: 0 },
{ day: 'Sa', today: 0 }, { day: getString('Sa'), today: 0 },
{ day: 'Su', today: 0 }, { day: getString('Su'), today: 0 },
] ]
const CalendarDay = (day, today) => Widget.Button({ const CalendarDay = (day, today) => Widget.Button({
@@ -192,8 +193,8 @@ export const ModuleCalendar = () => Box({
vertical: true, vertical: true,
className: 'sidebar-navrail spacing-v-10', className: 'sidebar-navrail spacing-v-10',
children: [ children: [
StackButton('calendar', 'calendar_month', 'Calendar'), StackButton('calendar', 'calendar_month', getString('Calendar')),
StackButton('todo', 'done_outline', 'To Do'), StackButton('todo', 'done_outline', getString('To Do')),
// StackButton(box, 'stars', 'star', 'GitHub'), // StackButton(box, 'stars', 'star', 'GitHub'),
] ]
}), false, false, 0); }), false, false, 0);
@@ -5,6 +5,7 @@ const { Box, Button, Icon, Label, Revealer, Scrollable, Slider, Stack } = Widget
import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
import { iconExists } from '../../.miscutils/icons.js'; import { iconExists } from '../../.miscutils/icons.js';
import { getString } from '../../../i18n/i18n.js';
const AppVolume = (stream) => Box({ const AppVolume = (stream) => Box({
className: 'sidebar-volmixer-stream spacing-h-10', className: 'sidebar-volmixer-stream spacing-h-10',
@@ -165,7 +166,7 @@ export default (props) => {
className: 'spacing-v-5 txt-subtext', className: 'spacing-v-5 txt-subtext',
children: [ children: [
MaterialIcon('brand_awareness', 'gigantic'), MaterialIcon('brand_awareness', 'gigantic'),
Label({ label: 'No audio source', className: 'txt-small' }), Label({ label: getString('No audio source'), className: 'txt-small' }),
] ]
}), }),
] ]
@@ -6,6 +6,7 @@ const { execAsync, exec } = Utils;
import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
import { ConfigToggle } from '../../.commonwidgets/configwidgets.js'; import { ConfigToggle } from '../../.commonwidgets/configwidgets.js';
import { getString } from '../../../i18n/i18n.js';
// can't connect: sync_problem // can't connect: sync_problem
@@ -43,7 +44,7 @@ const BluetoothDevice = (device) => {
label: device.connected ? 'Connected' : (device.paired ? 'Paired' : ''), label: device.connected ? 'Connected' : (device.paired ? 'Paired' : ''),
className: 'txt-subtext', className: 'txt-subtext',
setup: (self) => self.hook(device, (self) => { setup: (self) => self.hook(device, (self) => {
self.label = device.connected ? 'Connected' : (device.paired ? 'Paired' : ''); self.label = device.connected ? getString('Connected') : (device.paired ? getString('Paired') : '');
}), }),
}), }),
] ]
@@ -64,7 +65,7 @@ const BluetoothDevice = (device) => {
vpack: 'center', vpack: 'center',
className: 'sidebar-bluetooth-device-remove', className: 'sidebar-bluetooth-device-remove',
child: MaterialIcon('delete', 'norm'), child: MaterialIcon('delete', 'norm'),
tooltipText: 'Remove device', tooltipText: getString('Remove device'),
setup: setupCursorHover, setup: setupCursorHover,
onClicked: () => execAsync(['bluetoothctl', 'remove', device.address]).catch(print), onClicked: () => execAsync(['bluetoothctl', 'remove', device.address]).catch(print),
}); });
@@ -144,7 +145,7 @@ export default (props) => {
execAsync(['bash', '-c', userOptions.apps.bluetooth]).catch(print); execAsync(['bash', '-c', userOptions.apps.bluetooth]).catch(print);
closeEverything(); closeEverything();
}, },
label: 'More', label: getString('More'),
setup: setupCursorHover, setup: setupCursorHover,
})], })],
}) })
@@ -7,6 +7,7 @@ const { execAsync, exec } = Utils;
import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
import { ConfigGap, ConfigSpinButton, ConfigToggle } from '../../.commonwidgets/configwidgets.js'; import { ConfigGap, ConfigSpinButton, ConfigToggle } from '../../.commonwidgets/configwidgets.js';
import { getString } from '../../../i18n/i18n.js';
const HyprlandToggle = ({ icon, name, desc = null, option, enableValue = 1, disableValue = 0, extraOnChange = () => { } }) => ConfigToggle({ const HyprlandToggle = ({ icon, name, desc = null, option, enableValue = 1, disableValue = 0, extraOnChange = () => { } }) => ConfigToggle({
icon: icon, icon: icon,
@@ -60,11 +61,11 @@ export default (props) => {
className: 'spacing-v-10', className: 'spacing-v-10',
children: [ children: [
ConfigSection({ ConfigSection({
name: 'Effects', children: [ name: getString('Effects'), children: [
ConfigToggle({ ConfigToggle({
icon: 'border_clear', icon: 'border_clear',
name: 'Transparency', name: getString('Transparency'),
desc: '[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this', desc: getString('[AGS]\nMake shell elements transparent\nBlur is also recommended if you enable this'),
initValue: exec(`bash -c "sed -n \'2p\' ${GLib.get_user_state_dir()}/ags/user/colormode.txt"`) == "transparent", initValue: exec(`bash -c "sed -n \'2p\' ${GLib.get_user_state_dir()}/ags/user/colormode.txt"`) == "transparent",
onChange: (self, newValue) => { onChange: (self, newValue) => {
const transparency = newValue == 0 ? "opaque" : "transparent"; const transparency = newValue == 0 ? "opaque" : "transparent";
@@ -74,22 +75,22 @@ export default (props) => {
.catch(print); .catch(print);
}, },
}), }),
HyprlandToggle({ icon: 'blur_on', name: 'Blur', desc: "[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows.", option: "decoration:blur:enabled" }), HyprlandToggle({ icon: 'blur_on', name: getString('Blur'), desc: getString("[Hyprland]\nEnable blur on transparent elements\nDoesn't affect performance/power consumption unless you have transparent windows."), option: "decoration:blur:enabled" }),
Subcategory([ Subcategory([
HyprlandToggle({ icon: 'stack_off', name: 'X-ray', desc: "[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) ", option: "decoration:blur:xray" }), HyprlandToggle({ icon: 'stack_off', name: getString('X-ray'), desc: getString("[Hyprland]\nMake everything behind a window/layer except the wallpaper not rendered on its blurred surface\nRecommended to improve performance (if you don't abuse transparency/blur) "), option: "decoration:blur:xray" }),
HyprlandSpinButton({ icon: 'target', name: 'Size', desc: '[Hyprland]\nAdjust the blur radius. Generally doesn\'t affect performance\nHigher = more color spread', option: 'decoration:blur:size', minValue: 1, maxValue: 1000 }), HyprlandSpinButton({ icon: 'target', name: getString('Size'), desc: getString('[Hyprland]\nAdjust the blur radius. Generally doesn\'t affect performance\nHigher = more color spread'), option: 'decoration:blur:size', minValue: 1, maxValue: 1000 }),
HyprlandSpinButton({ icon: 'repeat', name: 'Passes', desc: '[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.', option: 'decoration:blur:passes', minValue: 1, maxValue: 10 }), HyprlandSpinButton({ icon: 'repeat', name: getString('Passes'), desc: getString('[Hyprland] Adjust the number of runs of the blur algorithm\nMore passes = more spread and power consumption\n4 is recommended\n2- would look weird and 6+ would look lame.'), option: 'decoration:blur:passes', minValue: 1, maxValue: 10 }),
]), ]),
ConfigGap({}), ConfigGap({}),
HyprlandToggle({ HyprlandToggle({
icon: 'animation', name: 'Animations', desc: '[Hyprland] [GTK]\nEnable animations', option: 'animations:enabled', icon: 'animation', name: getString('Animations'), desc: getString('[Hyprland] [GTK]\nEnable animations'), option: 'animations:enabled',
extraOnChange: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', `${newValue}`]) extraOnChange: (self, newValue) => execAsync(['gsettings', 'set', 'org.gnome.desktop.interface', 'enable-animations', `${newValue}`])
}), }),
Subcategory([ Subcategory([
ConfigSpinButton({ ConfigSpinButton({
icon: 'clear_all', icon: 'clear_all',
name: 'Choreography delay', name: getString('Choreography delay'),
desc: 'In milliseconds, the delay between animations of a series', desc: getString('In milliseconds, the delay between animations of a series'),
initValue: userOptions.animations.choreographyDelay, initValue: userOptions.animations.choreographyDelay,
step: 10, minValue: 0, maxValue: 1000, step: 10, minValue: 0, maxValue: 1000,
onChange: (self, newValue) => { onChange: (self, newValue) => {
@@ -100,11 +101,11 @@ export default (props) => {
] ]
}), }),
ConfigSection({ ConfigSection({
name: 'Developer', children: [ name: getString('Developer'), children: [
HyprlandToggle({ icon: 'speed', name: 'Show FPS', desc: "[Hyprland]\nShow FPS overlay on top-left corner", option: "debug:overlay" }), HyprlandToggle({ icon: 'speed', name: getString('Show FPS'), desc: getString("[Hyprland]\nShow FPS overlay on top-left corner"), option: "debug:overlay" }),
HyprlandToggle({ icon: 'sort', name: 'Log to stdout', desc: "[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console", option: "debug:enable_stdout_logs" }), HyprlandToggle({ icon: 'sort', name: getString('Log to stdout'), desc: getString("[Hyprland]\nPrint LOG, ERR, WARN, etc. messages to the console"), option: "debug:enable_stdout_logs" }),
HyprlandToggle({ icon: 'motion_sensor_active', name: 'Damage tracking', desc: "[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work", option: "debug:damage_tracking", enableValue: 2 }), HyprlandToggle({ icon: 'motion_sensor_active', name: getString('Damage tracking'), desc: getString("[Hyprland]\nEnable damage tracking\nGenerally, leave it on.\nTurn off only when a shader doesn't work"), option: "debug:damage_tracking", enableValue: 2 }),
HyprlandToggle({ icon: 'destruction', name: 'Damage blink', desc: "[Hyprland] [Epilepsy warning!]\nShow screen damage flashes", option: "debug:damage_blink" }), HyprlandToggle({ icon: 'destruction', name: getString('Damage blink'), desc: getString("[Hyprland] [Epilepsy warning!]\nShow screen damage flashes"), option: "debug:damage_blink" }),
] ]
}), }),
] ]
@@ -115,7 +116,7 @@ export default (props) => {
children: [Label({ children: [Label({
hpack: 'center', hpack: 'center',
className: 'txt txt-italic txt-subtext margin-5', className: 'txt txt-italic txt-subtext margin-5',
label: 'Not all changes are saved', label: getString('Not all changes are saved'),
})] })]
}) })
return Box({ return Box({
@@ -8,6 +8,7 @@ import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
import Notification from '../../.commonwidgets/notification.js'; import Notification from '../../.commonwidgets/notification.js';
import { ConfigToggle } from '../../.commonwidgets/configwidgets.js'; import { ConfigToggle } from '../../.commonwidgets/configwidgets.js';
import { getString } from '../../../i18n/i18n.js';
export default (props) => { export default (props) => {
const notifEmptyContent = Box({ const notifEmptyContent = Box({
@@ -22,7 +23,7 @@ export default (props) => {
className: 'spacing-v-5 txt-subtext', className: 'spacing-v-5 txt-subtext',
children: [ children: [
MaterialIcon('notifications_active', 'gigantic'), MaterialIcon('notifications_active', 'gigantic'),
Label({ label: 'No notifications', className: 'txt-small' }), Label({ label: getString('No notifications'), className: 'txt-small' }),
] ]
}), }),
] ]
@@ -82,7 +83,7 @@ export default (props) => {
}), }),
setup: setupCursorHover, setup: setupCursorHover,
}); });
const silenceButton = ListActionButton('notifications_paused', 'Silence', (self) => { const silenceButton = ListActionButton('notifications_paused', getString('Silence'), (self) => {
Notifications.dnd = !Notifications.dnd; Notifications.dnd = !Notifications.dnd;
self.toggleClassName('notif-listaction-btn-enabled', Notifications.dnd); self.toggleClassName('notif-listaction-btn-enabled', Notifications.dnd);
}); });
@@ -101,7 +102,7 @@ export default (props) => {
setup: (self) => self.hook(Notifications, (self) => { setup: (self) => self.hook(Notifications, (self) => {
self.revealChild = Notifications.notifications.length > 0; self.revealChild = Notifications.notifications.length > 0;
}), }),
child: ListActionButton('clear_all', 'Clear', () => { child: ListActionButton('clear_all', getString('Clear'), () => {
Notifications.clear(); Notifications.clear();
const kids = notificationList.get_children(); const kids = notificationList.get_children();
for (let i = 0; i < kids.length; i++) { for (let i = 0; i < kids.length; i++) {
@@ -114,7 +115,7 @@ export default (props) => {
attribute: { attribute: {
updateCount: (self) => { updateCount: (self) => {
const count = Notifications.notifications.length; const count = Notifications.notifications.length;
if (count > 0) self.label = `${count} notifications`; if (count > 0) self.label = `${count} ${getString("notifications")}`;
else self.label = ''; else self.label = '';
}, },
}, },
@@ -6,6 +6,7 @@ const { execAsync, exec } = Utils;
import { MaterialIcon } from '../../.commonwidgets/materialicon.js'; import { MaterialIcon } from '../../.commonwidgets/materialicon.js';
import { setupCursorHover } from '../../.widgetutils/cursorhover.js'; import { setupCursorHover } from '../../.widgetutils/cursorhover.js';
import { ConfigToggle } from '../../.commonwidgets/configwidgets.js'; import { ConfigToggle } from '../../.commonwidgets/configwidgets.js';
import { getString } from '../../../i18n/i18n.js';
const MATERIAL_SYMBOL_SIGNAL_STRENGTH = { const MATERIAL_SYMBOL_SIGNAL_STRENGTH = {
'network-wireless-signal-excellent-symbolic': "signal_wifi_4_bar", 'network-wireless-signal-excellent-symbolic': "signal_wifi_4_bar",
@@ -29,7 +30,7 @@ const WifiNetwork = (accessPoint) => {
accessPoint.active ? Label({ accessPoint.active ? Label({
hpack: 'start', hpack: 'start',
className: 'txt-smaller txt-subtext', className: 'txt-smaller txt-subtext',
label: "Selected", label: getString("Selected"),
}) : null, }) : null,
] ]
}); });
@@ -69,7 +70,7 @@ const CurrentNetwork = () => {
Label({ Label({
hpack: 'start', hpack: 'start',
className: 'txt-smaller txt-subtext', className: 'txt-smaller txt-subtext',
label: "Current network", label: getString("Current network"),
}), }),
Label({ Label({
hpack: 'start', hpack: 'start',
@@ -101,7 +102,7 @@ const CurrentNetwork = () => {
Label({ Label({
className: 'margin-left-5', className: 'margin-left-5',
hpack: 'start', hpack: 'start',
label: "Authentication", label: getString("Authentication"),
}), }),
Entry({ Entry({
className: 'sidebar-wifinetworks-auth-entry', className: 'sidebar-wifinetworks-auth-entry',
@@ -199,7 +200,7 @@ export default (props) => {
execAsync(['bash', '-c', userOptions.apps.network]).catch(print); execAsync(['bash', '-c', userOptions.apps.network]).catch(print);
closeEverything(); closeEverything();
}, },
label: 'More', label: getString('More'),
setup: setupCursorHover, setup: setupCursorHover,
})], })],
}) })
+11 -10
View File
@@ -10,10 +10,11 @@ import { BluetoothIndicator, NetworkIndicator } from '../.commonwidgets/statusic
import { setupCursorHover } from '../.widgetutils/cursorhover.js'; import { setupCursorHover } from '../.widgetutils/cursorhover.js';
import { MaterialIcon } from '../.commonwidgets/materialicon.js'; import { MaterialIcon } from '../.commonwidgets/materialicon.js';
import { sidebarOptionsStack } from './sideright.js'; import { sidebarOptionsStack } from './sideright.js';
import { getString } from '../../i18n/i18n.js';
export const ToggleIconWifi = (props = {}) => Widget.Button({ export const ToggleIconWifi = (props = {}) => Widget.Button({
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Wifi | Right-click to configure', tooltipText: getString('Wifi | Right-click to configure'),
onClicked: () => Network.toggleWifi(), onClicked: () => Network.toggleWifi(),
onSecondaryClickRelease: () => { onSecondaryClickRelease: () => {
execAsync(['bash', '-c', `${userOptions.apps.network}`]).catch(print); execAsync(['bash', '-c', `${userOptions.apps.network}`]).catch(print);
@@ -24,7 +25,7 @@ export const ToggleIconWifi = (props = {}) => Widget.Button({
setupCursorHover(self); setupCursorHover(self);
self.hook(Network, button => { self.hook(Network, button => {
button.toggleClassName('sidebar-button-active', [Network.wifi?.internet, Network.wired?.internet].includes('connected')) button.toggleClassName('sidebar-button-active', [Network.wifi?.internet, Network.wired?.internet].includes('connected'))
button.tooltipText = (`${Network.wifi?.ssid} | Right-click to configure` || 'Unknown'); button.tooltipText = (`${Network.wifi?.ssid} | ${getString("Right-click to configure")}` || getString('Unknown'));
}); });
}, },
...props, ...props,
@@ -32,7 +33,7 @@ export const ToggleIconWifi = (props = {}) => Widget.Button({
export const ToggleIconBluetooth = (props = {}) => Widget.Button({ export const ToggleIconBluetooth = (props = {}) => Widget.Button({
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Bluetooth | Right-click to configure', tooltipText: getString('Bluetooth | Right-click to configure'),
onClicked: () => { onClicked: () => {
const status = Bluetooth?.enabled; const status = Bluetooth?.enabled;
if (status) if (status)
@@ -86,7 +87,7 @@ export const ModuleNightLight = async (props = {}) => {
enabled: false, enabled: false,
}, },
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Night Light', tooltipText: getString('Night Light'),
onClicked: (self) => { onClicked: (self) => {
self.attribute.enabled = !self.attribute.enabled; self.attribute.enabled = !self.attribute.enabled;
self.toggleClassName('sidebar-button-active', self.attribute.enabled); self.toggleClassName('sidebar-button-active', self.attribute.enabled);
@@ -122,7 +123,7 @@ export const ModuleCloudflareWarp = async (props = {}) => {
enabled: false, enabled: false,
}, },
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Cloudflare WARP', tooltipText: getString('Cloudflare WARP'),
onClicked: (self) => { onClicked: (self) => {
self.attribute.enabled = !self.attribute.enabled; self.attribute.enabled = !self.attribute.enabled;
self.toggleClassName('sidebar-button-active', self.attribute.enabled); self.toggleClassName('sidebar-button-active', self.attribute.enabled);
@@ -147,7 +148,7 @@ export const ModuleInvertColors = async (props = {}) => {
const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default; const Hyprland = (await import('resource:///com/github/Aylur/ags/service/hyprland.js')).default;
return Widget.Button({ return Widget.Button({
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Color inversion', tooltipText: getString('Color inversion'),
onClicked: (button) => { onClicked: (button) => {
// const shaderPath = JSON.parse(exec('hyprctl -j getoption decoration:screen_shader')).str; // const shaderPath = JSON.parse(exec('hyprctl -j getoption decoration:screen_shader')).str;
Hyprland.messageAsync('j/getoption decoration:screen_shader') Hyprland.messageAsync('j/getoption decoration:screen_shader')
@@ -208,7 +209,7 @@ export const ModuleIdleInhibitor = (props = {}) => Widget.Button({ // TODO: Make
enabled: false, enabled: false,
}, },
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Keep system awake', tooltipText: getString('Keep system awake'),
onClicked: (self) => { onClicked: (self) => {
self.attribute.enabled = !self.attribute.enabled; self.attribute.enabled = !self.attribute.enabled;
self.toggleClassName('sidebar-button-active', self.attribute.enabled); self.toggleClassName('sidebar-button-active', self.attribute.enabled);
@@ -227,7 +228,7 @@ export const ModuleIdleInhibitor = (props = {}) => Widget.Button({ // TODO: Make
export const ModuleReloadIcon = (props = {}) => Widget.Button({ export const ModuleReloadIcon = (props = {}) => Widget.Button({
...props, ...props,
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Reload Environment config', tooltipText: getString('Reload Environment config'),
onClicked: () => { onClicked: () => {
execAsync(['bash', '-c', 'hyprctl reload || swaymsg reload &']); execAsync(['bash', '-c', 'hyprctl reload || swaymsg reload &']);
App.closeWindow('sideright'); App.closeWindow('sideright');
@@ -241,7 +242,7 @@ export const ModuleReloadIcon = (props = {}) => Widget.Button({
export const ModuleSettingsIcon = (props = {}) => Widget.Button({ export const ModuleSettingsIcon = (props = {}) => Widget.Button({
...props, ...props,
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Open Settings', tooltipText: getString('Open Settings'),
onClicked: () => { onClicked: () => {
execAsync(['bash', '-c', `${userOptions.apps.settings}`, '&']); execAsync(['bash', '-c', `${userOptions.apps.settings}`, '&']);
App.closeWindow('sideright'); App.closeWindow('sideright');
@@ -255,7 +256,7 @@ export const ModuleSettingsIcon = (props = {}) => Widget.Button({
export const ModulePowerIcon = (props = {}) => Widget.Button({ export const ModulePowerIcon = (props = {}) => Widget.Button({
...props, ...props,
className: 'txt-small sidebar-iconbutton', className: 'txt-small sidebar-iconbutton',
tooltipText: 'Session', tooltipText: getString('Session'),
onClicked: () => { onClicked: () => {
closeEverything(); closeEverything();
Utils.timeout(1, () => openWindowOnAllMonitors('session')); Utils.timeout(1, () => openWindowOnAllMonitors('session'));
+19 -17
View File
@@ -25,31 +25,32 @@ import { getDistroIcon } from '../.miscutils/system.js';
import { MaterialIcon } from '../.commonwidgets/materialicon.js'; import { MaterialIcon } from '../.commonwidgets/materialicon.js';
import { ExpandingIconTabContainer } from '../.commonwidgets/tabcontainer.js'; import { ExpandingIconTabContainer } from '../.commonwidgets/tabcontainer.js';
import { checkKeybind } from '../.widgetutils/keybind.js'; import { checkKeybind } from '../.widgetutils/keybind.js';
import { getString } from '../../i18n/i18n.js';
const centerWidgets = [ const centerWidgets = [
{ {
name: 'Notifications', name: getString('Notifications'),
materialIcon: 'notifications', materialIcon: 'notifications',
contentWidget: ModuleNotificationList, contentWidget: ModuleNotificationList,
}, },
{ {
name: 'Audio controls', name: getString('Audio controls'),
materialIcon: 'volume_up', materialIcon: 'volume_up',
contentWidget: ModuleAudioControls, contentWidget: ModuleAudioControls,
}, },
{ {
name: 'Bluetooth', name: getString('Bluetooth'),
materialIcon: 'bluetooth', materialIcon: 'bluetooth',
contentWidget: ModuleBluetooth, contentWidget: ModuleBluetooth,
}, },
{ {
name: 'Wifi networks', name: getString('Wifi networks'),
materialIcon: 'wifi', materialIcon: 'wifi',
contentWidget: ModuleWifiNetworks, contentWidget: ModuleWifiNetworks,
onFocus: () => execAsync('nmcli dev wifi list').catch(print), onFocus: () => execAsync('nmcli dev wifi list').catch(print),
}, },
{ {
name: 'Live config', name: getString('Live config'),
materialIcon: 'tune', materialIcon: 'tune',
contentWidget: ModuleConfigure, contentWidget: ModuleConfigure,
}, },
@@ -66,43 +67,44 @@ const timeRow = Box({
hpack: 'center', hpack: 'center',
className: 'txt-small txt', className: 'txt-small txt',
setup: (self) => { setup: (self) => {
const getUptime = async () => { const getUptime = async () => {
try { try {
await execAsync(['bash', '-c', 'uptime -p']); await execAsync(['bash', '-c', 'uptime -p']);
return execAsync(['bash', '-c', `uptime -p | sed -e 's/...//;s/ day\\| days/d/;s/ hour\\| hours/h/;s/ minute\\| minutes/m/;s/,[^,]*//2'`]); return execAsync(['bash', '-c', `uptime -p | sed -e 's/...//;s/ day\\| days/d/;s/ hour\\| hours/h/;s/ minute\\| minutes/m/;s/,[^,]*//2'`]);
} catch { } catch {
return execAsync(['bash', '-c', 'uptime']).then(output => { return execAsync(['bash', '-c', 'uptime']).then(output => {
const uptimeRegex = /up\s+((\d+)\s+days?,\s+)?((\d+):(\d+)),/; const uptimeRegex = /up\s+((\d+)\s+days?,\s+)?((\d+):(\d+)),/;
const matches = uptimeRegex.exec(output); const matches = uptimeRegex.exec(output);
if (matches) { if (matches) {
const days = matches[2] ? parseInt(matches[2]) : 0; const days = matches[2] ? parseInt(matches[2]) : 0;
const hours = matches[4] ? parseInt(matches[4]) : 0; const hours = matches[4] ? parseInt(matches[4]) : 0;
const minutes = matches[5] ? parseInt(matches[5]) : 0; const minutes = matches[5] ? parseInt(matches[5]) : 0;
let formattedUptime = ''; let formattedUptime = '';
if (days > 0) { if (days > 0) {
formattedUptime += `${days} d `; formattedUptime += `${days} d `;
} }
if (hours > 0) { if (hours > 0) {
formattedUptime += `${hours} h `; formattedUptime += `${hours} h `;
} }
formattedUptime += `${minutes} m`; formattedUptime += `${minutes} m`;
return formattedUptime; return formattedUptime;
} else { } else {
throw new Error('Failed to parse uptime output'); throw new Error('Failed to parse uptime output');
} }
}); });
} }
}; };
self.poll(5000, label => { self.poll(5000, label => {
getUptime().then(upTimeString => { getUptime().then(upTimeString => {
label.label = `Uptime: ${upTimeString}`; label.label = `${getString("Uptime:"
)} ${upTimeString}`;
}).catch(err => { }).catch(err => {
console.error(`Failed to fetch uptime: ${err}`); console.error(`Failed to fetch uptime: ${err}`);
}); });
}); });
}, },
+5 -4
View File
@@ -5,6 +5,7 @@ import { MaterialIcon } from '../.commonwidgets/materialicon.js';
import { TabContainer } from '../.commonwidgets/tabcontainer.js'; import { TabContainer } from '../.commonwidgets/tabcontainer.js';
import Todo from "../../services/todo.js"; import Todo from "../../services/todo.js";
import { setupCursorHover } from '../.widgetutils/cursorhover.js'; import { setupCursorHover } from '../.widgetutils/cursorhover.js';
import { getString } from '../../i18n/i18n.js';
const TodoListItem = (task, id, isDone, isEven = false) => { const TodoListItem = (task, id, isDone, isEven = false) => {
const taskName = Widget.Label({ const taskName = Widget.Label({
@@ -108,7 +109,7 @@ const todoItems = (isDone) => Widget.Scrollable({
className: 'txt txt-subtext', className: 'txt txt-subtext',
children: [ children: [
MaterialIcon(`${isDone ? 'checklist' : 'check_circle'}`, 'gigantic'), MaterialIcon(`${isDone ? 'checklist' : 'check_circle'}`, 'gigantic'),
Label({ label: `${isDone ? 'Finished tasks will go here' : 'Nothing here!'}` }) Label({ label: `${isDone ? getString('Finished tasks will go here') : getString('Nothing here!')}` })
] ]
}) })
] ]
@@ -132,7 +133,7 @@ const UndoneTodoList = () => {
className: 'txt-small sidebar-todo-new', className: 'txt-small sidebar-todo-new',
halign: 'end', halign: 'end',
vpack: 'center', vpack: 'center',
label: '+ New task', label: getString('+ New task'),
setup: setupCursorHover, setup: setupCursorHover,
onClicked: (self) => { onClicked: (self) => {
newTaskButton.revealChild = false; newTaskButton.revealChild = false;
@@ -166,7 +167,7 @@ const UndoneTodoList = () => {
// hexpand: true, // hexpand: true,
vpack: 'center', vpack: 'center',
className: 'txt-small sidebar-todo-entry', className: 'txt-small sidebar-todo-entry',
placeholderText: 'Add a task...', placeholderText: getString('Add a task...'),
onAccept: ({ text }) => { onAccept: ({ text }) => {
if (text == '') return; if (text == '') return;
Todo.add(text) Todo.add(text)
@@ -216,7 +217,7 @@ const UndoneTodoList = () => {
export const TodoWidget = () => TabContainer({ export const TodoWidget = () => TabContainer({
icons: ['format_list_bulleted', 'task_alt'], icons: ['format_list_bulleted', 'task_alt'],
names: ['Unfinished', 'Done'], names: [getString('Unfinished'), getString('Done')],
children: [ children: [
UndoneTodoList(), UndoneTodoList(),
todoItems(true), todoItems(true),
+6 -5
View File
@@ -5,12 +5,13 @@ import Gio from 'gi://Gio';
import GLib from 'gi://GLib'; import GLib from 'gi://GLib';
import Soup from 'gi://Soup?version=3.0'; import Soup from 'gi://Soup?version=3.0';
import { fileExists } from '../modules/.miscutils/files.js'; import { fileExists } from '../modules/.miscutils/files.js';
import { getString } from '../i18n/i18n.js';
const PROVIDERS = Object.assign({ // There's this list hmm https://github.com/zukixa/cool-ai-stuff/ const PROVIDERS = Object.assign({ // There's this list hmm https://github.com/zukixa/cool-ai-stuff/
'openai': { 'openai': {
'name': 'OpenAI', 'name': 'OpenAI',
'logo_name': 'openai-symbolic', 'logo_name': 'openai-symbolic',
'description': 'Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.', 'description': getString('Official OpenAI API.\nPricing: Free for the first $5 or 3 months, whichever is less.'),
'base_url': 'https://api.openai.com/v1/chat/completions', 'base_url': 'https://api.openai.com/v1/chat/completions',
'key_get_url': 'https://platform.openai.com/api-keys', 'key_get_url': 'https://platform.openai.com/api-keys',
'key_file': 'openai_key.txt', 'key_file': 'openai_key.txt',
@@ -19,7 +20,7 @@ const PROVIDERS = Object.assign({ // There's this list hmm https://github.com/zu
'ollama': { 'ollama': {
'name': 'Ollama (Llama 3)', 'name': 'Ollama (Llama 3)',
'logo_name': 'ollama-symbolic', 'logo_name': 'ollama-symbolic',
'description': 'Official Ollama API.\nPricing: Free.', 'description': getString('Official Ollama API.\nPricing: Free.'),
'base_url': 'http://localhost:11434/v1/chat/completions', 'base_url': 'http://localhost:11434/v1/chat/completions',
'key_get_url': 'it\'s just ollama', 'key_get_url': 'it\'s just ollama',
'key_file': 'ollama_key.txt', 'key_file': 'ollama_key.txt',
@@ -28,7 +29,7 @@ const PROVIDERS = Object.assign({ // There's this list hmm https://github.com/zu
'openrouter': { 'openrouter': {
'name': 'OpenRouter (Llama-3-70B)', 'name': 'OpenRouter (Llama-3-70B)',
'logo_name': 'openrouter-symbolic', 'logo_name': 'openrouter-symbolic',
'description': 'A unified interface for LLMs', 'description': getString('A unified interface for LLMs'),
'base_url': 'https://openrouter.ai/api/v1/chat/completions', 'base_url': 'https://openrouter.ai/api/v1/chat/completions',
'key_get_url': 'https://openrouter.ai/keys', 'key_get_url': 'https://openrouter.ai/keys',
'key_file': 'openrouter_key.txt', 'key_file': 'openrouter_key.txt',
@@ -37,7 +38,7 @@ const PROVIDERS = Object.assign({ // There's this list hmm https://github.com/zu
'oxygen4o': { 'oxygen4o': {
'name': 'Oxygen (GPT-4o)', 'name': 'Oxygen (GPT-4o)',
'logo_name': 'ai-oxygen-symbolic', 'logo_name': 'ai-oxygen-symbolic',
'description': 'An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key', 'description': getString('An API from Tornado Softwares\nPricing: Free: 100/day\nRequires you to join their Discord for a key'),
'base_url': 'https://app.oxyapi.uk/v1/chat/completions', 'base_url': 'https://app.oxyapi.uk/v1/chat/completions',
'key_get_url': 'https://discord.com/invite/kM6MaCqGKA', 'key_get_url': 'https://discord.com/invite/kM6MaCqGKA',
'key_file': 'oxygen_key.txt', 'key_file': 'oxygen_key.txt',
@@ -46,7 +47,7 @@ const PROVIDERS = Object.assign({ // There's this list hmm https://github.com/zu
'zukijourney': { 'zukijourney': {
'name': 'zukijourney (GPT-3.5)', 'name': 'zukijourney (GPT-3.5)',
'logo_name': 'ai-zukijourney', 'logo_name': 'ai-zukijourney',
'description': 'An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it\'s buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key', 'description': getString("An API from @zukixa on GitHub.\nNote: Keys are IP-locked so it's buggy sometimes\nPricing: Free: 10/min, 800/day.\nRequires you to join their Discord for a key"),
'base_url': 'https://zukijourney.xyzbot.net/v1/chat/completions', 'base_url': 'https://zukijourney.xyzbot.net/v1/chat/completions',
'key_get_url': 'https://discord.com/invite/Y4J6XXnmQ6', 'key_get_url': 'https://discord.com/invite/Y4J6XXnmQ6',
'key_file': 'zuki_key.txt', 'key_file': 'zuki_key.txt',