ags(i18n): finally use i18n system!

This commit is contained in:
retrozinndev
2025-03-09 16:04:48 -03:00
parent 59ef5e4aa7
commit 03813021a8
11 changed files with 113 additions and 44 deletions
+18 -11
View File
@@ -1,33 +1,32 @@
//TODO use I18n system >.< import { Binding, GLib } from "astal";
import en_US from "./lang/en_US"; import en_US from "./lang/en_US";
import pt_BR from "./lang/pt_BR"; import pt_BR from "./lang/pt_BR";
import { GLib } from "astal";
export type i18nStruct = Record<string, string|object|Binding<string| undefined>>;
const i18nKeys = { const i18nKeys = {
"en_US": en_US, "en_US": en_US,
"pt_BR": pt_BR "pt_BR": pt_BR
}; };
const languages: Array<string> = Object.keys(i18nKeys); const languages: Array<string> = Object.keys(i18nKeys);
const defaultLanguage: string = languages[0];
let language: string = getSystemLanguage(); let language: string = getSystemLanguage();
export function getSystemLanguage(): string { export function getSystemLanguage(): string {
const sysLanguage: (string|null|undefined) = GLib.getenv("LANG") || GLib.getenv("LANGUAGE"); const sysLanguage: (string|null|undefined) = GLib.getenv("LANG") || GLib.getenv("LANGUAGE");
if(!sysLanguage) { if(!sysLanguage) {
console.log(`[WARNING] Couldn't get system language, fallback to default ${defaultLanguage}`); console.log(`[WARNING] Couldn't get system language, fallback to default ${languages[0]}`);
console.log("[TIP] Please set the LANG or LANGUAGE environment variable"); console.log("[TIP] Please set the LANG or LANGUAGE environment variable");
return "en_US"; return languages[0];
} }
return sysLanguage.split('.')[0]; return sysLanguage.split('.')[0];
} }
export function setLanguage(lang: keyof typeof i18nKeys): string { export function setLanguage(lang: string): string {
languages.map((cur: string) => { languages.map((cur: string) => {
if(cur === lang) { if(cur === lang) {
language = lang; language = lang;
@@ -42,12 +41,20 @@ export function setLanguage(lang: keyof typeof i18nKeys): string {
export function tr(key: string): string { export function tr(key: string): string {
let result = i18nKeys[language as keyof typeof i18nKeys], let result = i18nKeys[language as keyof typeof i18nKeys],
defResult = i18nKeys[defaultLanguage as keyof typeof i18nKeys]; defResult = i18nKeys[languages[0] as keyof typeof i18nKeys];
for(const keyString in key.split('.')) { for(const keyString of key.split('.')) {
result = result[keyString as keyof typeof result] as never; result = result[keyString as keyof typeof result] as never;
defResult = defResult[keyString as keyof typeof defResult] as never; defResult = defResult[keyString as keyof typeof defResult] as never;
} }
return (result as never) || (defResult as never) || "couldn't find i18n key"; return (typeof result == "string") ?
result
: ((typeof defResult == "string") ?
defResult
: "not found / is not of type \"string\"");
}
export function trGet() {
return i18nKeys[getSystemLanguage() as keyof typeof i18nKeys];
} }
+33 -5
View File
@@ -1,8 +1,36 @@
import { i18nStruct } from "../intl";
export default { export default {
"language": "English (United States)", language: "English (United States)",
"bar": { bar: {
"logo": { apps: {
"tooltip": "Applications" tooltip: "Applications"
}
},
control_center: {
tiles: {
more: "More",
network: {
network: "Network",
connected: "Connected",
disconnected: "Disconnected",
unknown: "Unknown",
connecting: "Connecting",
wireless: "Wireless",
wired: "Wired"
},
recording: {
title: "Screen Recording",
disabled_description: "Start recording",
enabled_description: "Stop recording",
}
}
},
ask_popup: {
title: "Question",
options: {
cancel: "Cancel",
accept: "Ok"
} }
} }
} } as i18nStruct;
+34 -5
View File
@@ -1,8 +1,37 @@
import { i18nStruct } from "../intl";
export default { export default {
"language": "Português (Brasil)", language: "Português (Brasil)",
"bar": { bar: {
"logo": { apps: {
"tooltip": "Aplicativos" tooltip: "Aplicativos"
}
},
control_center: {
tiles: {
more: "Mais",
network: {
network: "Rede",
connected: "Conectado",
disconnected: "Desconectado",
unknown: "Desconhecido",
connecting: "Conectando",
wireless: "Wireless",
wired: "Cabeado"
},
recording: {
title: "Gravação de Tela",
disabled_description: "Iniciar gravação",
enabled_description: "Parar gravação",
}
}
},
ask_popup: {
title: "Pergunta",
options: {
cancel: "Cancelar",
accept: "Ok"
} }
} }
} } as i18nStruct;
+4 -3
View File
@@ -2,6 +2,7 @@ import { Binding } from "astal";
import { PopupWindow, PopupWindowProps } from "./PopupWindow"; import { PopupWindow, PopupWindowProps } from "./PopupWindow";
import { Astal, Gtk, Widget } from "astal/gtk3"; import { Astal, Gtk, Widget } from "astal/gtk3";
import { Separator } from "./Separator"; import { Separator } from "./Separator";
import { tr } from "../i18n/intl";
export type AskPopupProps = { export type AskPopupProps = {
title?: string | Binding<string | undefined>; title?: string | Binding<string | undefined>;
@@ -22,7 +23,7 @@ export function AskPopup(props: AskPopupProps) {
new Widget.Button({ new Widget.Button({
className: "cancel", className: "cancel",
hexpand: true, hexpand: true,
label: props.cancelText || "Cancel", label: props.cancelText || tr("ask_popup.options.cancel") || "Cancel",
onClick: (_) => { onClick: (_) => {
window.destroy(); window.destroy();
props.onCancel && props.onCancel(); props.onCancel && props.onCancel();
@@ -31,7 +32,7 @@ export function AskPopup(props: AskPopupProps) {
new Widget.Button({ new Widget.Button({
className: "accept", className: "accept",
hexpand: true, hexpand: true,
label: props.acceptText || "Ok", label: props.acceptText || tr("ask_popup.options.accept") || "Ok",
onClick: (_) => { onClick: (_) => {
window.destroy(); window.destroy();
props.onAccept && props.onAccept(); props.onAccept && props.onAccept();
@@ -57,7 +58,7 @@ export function AskPopup(props: AskPopupProps) {
new Widget.Label({ new Widget.Label({
className: "title", className: "title",
visible: Boolean(props.title), visible: Boolean(props.title),
label: props.title || "" label: props.title || tr("ask_popup.title") || "Question"
} as Widget.LabelProps), } as Widget.LabelProps),
Separator({ Separator({
alpha: .2, alpha: .2,
-4
View File
@@ -1,4 +0,0 @@
import { astalify, Gtk } from "astal/gtk3";
// TODO
export class FlowBox extends astalify(Gtk.FlowBox) {}
+5 -2
View File
@@ -1,6 +1,7 @@
import { Astal, Gtk, Widget } from "astal/gtk3"; import { Astal, Gtk, Widget } from "astal/gtk3";
import AstalNotifd from "gi://AstalNotifd"; import AstalNotifd from "gi://AstalNotifd";
import { Separator } from "./Separator"; import { Separator } from "./Separator";
import Pango from "gi://Pango";
export function getUrgencyString(notif: AstalNotifd.Notification) { export function getUrgencyString(notif: AstalNotifd.Notification) {
switch(notif.urgency) { switch(notif.urgency) {
@@ -78,6 +79,7 @@ export function NotificationWidget(notification: AstalNotifd.Notification|number
new Widget.Box({ new Widget.Box({
className: "text", className: "text",
orientation: Gtk.Orientation.VERTICAL, orientation: Gtk.Orientation.VERTICAL,
expand: true,
children: [ children: [
new Widget.Label({ new Widget.Label({
className: "summary", className: "summary",
@@ -89,9 +91,10 @@ export function NotificationWidget(notification: AstalNotifd.Notification|number
new Widget.Label({ new Widget.Label({
className: "body", className: "body",
useMarkup: true, useMarkup: true,
xalign: 0, halign: Gtk.Align.START,
expand: true, truncate: false,
wrap: true, wrap: true,
wrapMode: Pango.WrapMode.WORD,
label: notification.body label: notification.body
} as Widget.LabelProps) } as Widget.LabelProps)
] ]
+2
View File
@@ -1,5 +1,6 @@
import { Gtk, Widget } from "astal/gtk3"; import { Gtk, Widget } from "astal/gtk3";
import AstalHyprland from "gi://AstalHyprland"; import AstalHyprland from "gi://AstalHyprland";
import { trGet } from "../../i18n/intl";
export function Logo(): Gtk.Widget { export function Logo(): Gtk.Widget {
return new Widget.EventBox({ return new Widget.EventBox({
@@ -8,6 +9,7 @@ export function Logo(): Gtk.Widget {
child: new Widget.Box({ child: new Widget.Box({
child: new Widget.Label({ child: new Widget.Label({
className: "nf", className: "nf",
tooltipText: trGet()["bar"]["apps"]["tooltip"],
label: "" label: ""
} as Widget.LabelProps) } as Widget.LabelProps)
} as Widget.BoxProps) } as Widget.BoxProps)
+12 -11
View File
@@ -2,8 +2,9 @@ import { bind, execAsync, Variable } from "astal";
import { Tile, TileProps } from "./Tile"; import { Tile, TileProps } from "./Tile";
import AstalNetwork from "gi://AstalNetwork"; import AstalNetwork from "gi://AstalNetwork";
import { Widget } from "astal/gtk3"; import { Widget } from "astal/gtk3";
import { showPages, togglePage } from "../Pages"; import { togglePage } from "../Pages";
import { PageNetwork } from "../pages/Network"; import { PageNetwork } from "../pages/Network";
import { tr } from "../../../i18n/intl";
export const TileNetwork = new Widget.Box({ export const TileNetwork = new Widget.Box({
child: Variable.derive([ child: Variable.derive([
@@ -14,18 +15,18 @@ export const TileNetwork = new Widget.Box({
(primary: AstalNetwork.Primary, wired: AstalNetwork.Wired, wifi: AstalNetwork.Wifi) => { (primary: AstalNetwork.Primary, wired: AstalNetwork.Wired, wifi: AstalNetwork.Wifi) => {
if(primary === AstalNetwork.Primary.WIFI) { if(primary === AstalNetwork.Primary.WIFI) {
return Tile({ return Tile({
title: "Wireless", title: tr("control_center.tiles.network.wireless") || "Wireless",
description: Variable.derive( description: Variable.derive(
[ bind(wifi, "ssid"), bind(wifi, "internet") ], [ bind(wifi, "ssid"), bind(wifi, "internet") ],
(ssid: string, internet: AstalNetwork.Internet) => (ssid: string, internet: AstalNetwork.Internet) =>
ssid ? ssid : (() => { ssid ? ssid : (() => {
switch(internet) { switch(internet) {
case AstalNetwork.Internet.CONNECTED: case AstalNetwork.Internet.CONNECTED:
return "Connected"; return tr("control_center.tiles.network.connected") || "Connected";
case AstalNetwork.Internet.DISCONNECTED: case AstalNetwork.Internet.DISCONNECTED:
return "Disconnected"; return tr("control_center.tiles.network.disconnected") || "Disconnected";
case AstalNetwork.Internet.CONNECTING: case AstalNetwork.Internet.CONNECTING:
return "Connecting..."; return tr("control_center.tiles.network.connecting") + "..." || "Connecting...";
} }
})() })()
)(), )(),
@@ -39,15 +40,15 @@ export const TileNetwork = new Widget.Box({
} else if(primary === AstalNetwork.Primary.WIRED) { } else if(primary === AstalNetwork.Primary.WIRED) {
return Tile({ return Tile({
title: "Wired", title: tr("control_center.tiles.network.wired") || "Wired",
description: bind(wired, "internet").as((internet: AstalNetwork.Internet) => { description: bind(wired, "internet").as((internet: AstalNetwork.Internet) => {
switch(internet) { switch(internet) {
case AstalNetwork.Internet.CONNECTED: case AstalNetwork.Internet.CONNECTED:
return "Connected"; return tr("control_center.tiles.network.connected") || "Connected";
case AstalNetwork.Internet.DISCONNECTED: case AstalNetwork.Internet.DISCONNECTED:
return "Disconnected"; return tr("control_center.tiles.network.disconnected") || "Disconnected";
case AstalNetwork.Internet.CONNECTING: case AstalNetwork.Internet.CONNECTING:
return "Connecting..."; return tr("control_center.tiles.network.connecting") + "..." || "Connecting...";
} }
}), }),
onToggledOn: () => execAsync("nmcli n on"), onToggledOn: () => execAsync("nmcli n on"),
@@ -72,8 +73,8 @@ export const TileNetwork = new Widget.Box({
} }
return Tile({ return Tile({
title: "Network", title: tr("control_center.tiles.network.network") || "Network",
description: "Disconnected", description: tr("control_center.tiles.network.disconnected") || "Disconnected",
onToggledOn: () => execAsync("nmcli n on"), onToggledOn: () => execAsync("nmcli n on"),
onToggledOff: () => execAsync("nmcli n off"), onToggledOff: () => execAsync("nmcli n off"),
onClickMore: () => togglePage(PageNetwork), onClickMore: () => togglePage(PageNetwork),
+3 -2
View File
@@ -1,13 +1,14 @@
import { Tile, TileProps } from "./Tile"; import { Tile, TileProps } from "./Tile";
import { Recording } from "../../../scripts/recording"; import { Recording } from "../../../scripts/recording";
import { bind } from "astal"; import { bind } from "astal";
import { tr } from "../../../i18n/intl";
export const TileRecording = Tile({ export const TileRecording = Tile({
title: "Screen Recording", title: tr("control_center.tiles.recording.title") || "Screen Recording",
description: bind(Recording.getDefault(), "recording").as( description: bind(Recording.getDefault(), "recording").as(
(isRecording: boolean) => isRecording ? (isRecording: boolean) => isRecording ?
"Recording {time}" "Recording {time}"
: "Start a Screen Record" : tr("control_center.tiles.recording.disabled_description") || "Start recording"
), ),
icon: "󰻂", icon: "󰻂",
onToggledOff: () => Recording.getDefault().stopRecording(), onToggledOff: () => Recording.getDefault().stopRecording(),
+2
View File
@@ -1,5 +1,6 @@
import { Binding, Variable } from "astal"; import { Binding, Variable } from "astal";
import { Gtk, Widget } from "astal/gtk3"; import { Gtk, Widget } from "astal/gtk3";
import { tr } from "../../../i18n/intl";
export type TileProps = { export type TileProps = {
className?: string | Binding<string | undefined>; className?: string | Binding<string | undefined>;
@@ -99,6 +100,7 @@ export function Tile(props: TileProps): Widget.EventBox {
className: "more icon", className: "more icon",
visible: props.onClickMore !== undefined, visible: props.onClickMore !== undefined,
halign: Gtk.Align.END, halign: Gtk.Align.END,
tooltipText: tr("control_center.tiles.more") || "More",
image: new Widget.Icon({ image: new Widget.Icon({
icon: "go-next-symbolic", icon: "go-next-symbolic",
css: "icon { font-size: 16px; }" css: "icon { font-size: 16px; }"
-1
View File
@@ -6,7 +6,6 @@ import { handleShell } from "../scripts/runner/shell";
import { handleWebSearch } from "../scripts/runner/websearch"; import { handleWebSearch } from "../scripts/runner/websearch";
import { handleApplications } from "../scripts/runner/apps"; import { handleApplications } from "../scripts/runner/apps";
import { ResultWidget, ResultWidgetProps } from "../widget/runner/ResultWidget"; import { ResultWidget, ResultWidgetProps } from "../widget/runner/ResultWidget";
import Wp05 from "gi://Wp";
export let runnerInstance: (Widget.Window|null) = null; export let runnerInstance: (Widget.Window|null) = null;