The interface is fully Russified

This commit is contained in:
2026-04-06 09:43:22 +07:00
parent b68b962128
commit ec6880abd4

View File

@@ -196,7 +196,7 @@ func (u *ui) handleClicks(gtx layout.Context) {
u.refresh() u.refresh()
} }
for u.disconnectBtn.Clicked(gtx) { for u.disconnectBtn.Clicked(gtx) {
u.runAction("Disconnecting...", func() error { u.runAction("Отключение...", func() error {
return vpn.Disconnect(config.LogsDir) return vpn.Disconnect(config.LogsDir)
}) })
} }
@@ -223,7 +223,7 @@ func (u *ui) handleClicks(gtx layout.Context) {
for u.vlessConnectBtns[i].Clicked(gtx) { for u.vlessConnectBtns[i].Clicked(gtx) {
if i < len(u.configs.VLESS) { if i < len(u.configs.VLESS) {
name := u.configs.VLESS[i].Name name := u.configs.VLESS[i].Name
u.runAction("Connecting to "+name+"...", func() error { u.runAction("Подключение к "+name+"...", func() error {
return vless.Connect(name, config.LogsDir, config.XrayDir) return vless.Connect(name, config.LogsDir, config.XrayDir)
}) })
} }
@@ -237,15 +237,15 @@ func (u *ui) handleClicks(gtx layout.Context) {
for u.vlessPingBtns[i].Clicked(gtx) { for u.vlessPingBtns[i].Clicked(gtx) {
if i < len(u.configs.VLESS) { if i < len(u.configs.VLESS) {
cfg := u.configs.VLESS[i] cfg := u.configs.VLESS[i]
u.runAction("Testing "+cfg.Name+"...", func() error { u.runAction("Тестирование "+cfg.Name+"...", func() error {
ok, latency, err := vless.PingServer(cfg.URL, 4*time.Second) ok, latency, err := vless.PingServer(cfg.URL, 4*time.Second)
if err != nil { if err != nil {
return err return err
} }
if !ok { if !ok {
return fmt.Errorf("server is unreachable") return fmt.Errorf("сервер не найден")
} }
return fmt.Errorf("latency %.0f ms", latency) return fmt.Errorf("пинг %.0f мс", latency)
}) })
} }
} }
@@ -255,7 +255,7 @@ func (u *ui) handleClicks(gtx layout.Context) {
for u.wgConnectBtns[i].Clicked(gtx) { for u.wgConnectBtns[i].Clicked(gtx) {
if i < len(u.configs.WireGuard) { if i < len(u.configs.WireGuard) {
name := u.configs.WireGuard[i].Name name := u.configs.WireGuard[i].Name
u.runAction("Connecting WireGuard "+name+"...", func() error { u.runAction("Подключение WireGuard "+name+"...", func() error {
return wireguard.Connect(name, config.LogsDir) return wireguard.Connect(name, config.LogsDir)
}) })
} }
@@ -272,7 +272,7 @@ func (u *ui) handleClicks(gtx layout.Context) {
for u.subUpdateBtns[i].Clicked(gtx) { for u.subUpdateBtns[i].Clicked(gtx) {
if i < len(u.subs.Subscriptions) { if i < len(u.subs.Subscriptions) {
name := u.subs.Subscriptions[i].Name name := u.subs.Subscriptions[i].Name
u.runAction("Updating "+name+"...", func() error { u.runAction("Обновление "+name+"...", func() error {
return subscription.UpdateSubscription(name, config.LogsDir) return subscription.UpdateSubscription(name, config.LogsDir)
}) })
} }
@@ -286,7 +286,7 @@ func (u *ui) handleClicks(gtx layout.Context) {
for u.subTestBtns[i].Clicked(gtx) { for u.subTestBtns[i].Clicked(gtx) {
if i < len(u.subs.Subscriptions) { if i < len(u.subs.Subscriptions) {
name := u.subs.Subscriptions[i].Name name := u.subs.Subscriptions[i].Name
u.runAction("Testing configs from "+name+"...", func() error { u.runAction("Тестирование конфигов из "+name+"...", func() error {
return u.testSubscriptionConfigs(name) return u.testSubscriptionConfigs(name)
}) })
} }
@@ -309,7 +309,7 @@ func (u *ui) runAction(progress string, fn func() error) {
u.async <- func() { u.async <- func() {
u.busy = false u.busy = false
if err != nil { if err != nil {
if strings.HasPrefix(err.Error(), "latency ") { if strings.HasPrefix(err.Error(), "задержка ") {
u.message = err.Error() u.message = err.Error()
u.messageColor = successColor u.messageColor = successColor
} else { } else {
@@ -317,7 +317,7 @@ func (u *ui) runAction(progress string, fn func() error) {
u.messageColor = dangerColor u.messageColor = dangerColor
} }
} else { } else {
u.message = "Action completed." u.message = "Действие выполнено."
u.messageColor = successColor u.messageColor = successColor
} }
u.refresh() u.refresh()
@@ -365,12 +365,12 @@ func (u *ui) addVLESSConfig() {
name := strings.TrimSpace(u.configNameEditor.Text()) name := strings.TrimSpace(u.configNameEditor.Text())
rawURL := strings.TrimSpace(u.configURLEditor.Text()) rawURL := strings.TrimSpace(u.configURLEditor.Text())
if name == "" || rawURL == "" { if name == "" || rawURL == "" {
u.message = "Name and VLESS URL are required." u.message = "Имя и URL VLESS не заполнены."
u.messageColor = dangerColor u.messageColor = dangerColor
return return
} }
if _, err := url.Parse(rawURL); err != nil { if _, err := url.Parse(rawURL); err != nil {
u.message = "The VLESS URL is not valid." u.message = "VLESS URL не действителен."
u.messageColor = dangerColor u.messageColor = dangerColor
return return
} }
@@ -384,7 +384,7 @@ func (u *ui) addVLESSConfig() {
for _, item := range cfgs.VLESS { for _, item := range cfgs.VLESS {
if item.Name == name { if item.Name == name {
u.message = "A config with this name already exists." u.message = "Конфиг с таким именем уже существует"
u.messageColor = dangerColor u.messageColor = dangerColor
return return
} }
@@ -403,7 +403,7 @@ func (u *ui) addVLESSConfig() {
u.configNameEditor.SetText("") u.configNameEditor.SetText("")
u.configURLEditor.SetText("vless://") u.configURLEditor.SetText("vless://")
u.message = "VLESS config added." u.message = "VLESS конфиг добавлен."
u.messageColor = successColor u.messageColor = successColor
u.refresh() u.refresh()
} }
@@ -427,7 +427,7 @@ func (u *ui) deleteVLESSConfig(name string) {
} }
cfgs.VLESS = filtered cfgs.VLESS = filtered
if !found { if !found {
u.message = "Config was already removed." u.message = "Конфиг уже удалён."
u.messageColor = warningColor u.messageColor = warningColor
return return
} }
@@ -437,7 +437,7 @@ func (u *ui) deleteVLESSConfig(name string) {
return return
} }
u.message = "Config removed." u.message = "Конфиг удалён."
u.messageColor = successColor u.messageColor = successColor
u.refresh() u.refresh()
} }
@@ -446,12 +446,12 @@ func (u *ui) addSubscription() {
name := strings.TrimSpace(u.subNameEditor.Text()) name := strings.TrimSpace(u.subNameEditor.Text())
rawURL := strings.TrimSpace(u.subURLEditor.Text()) rawURL := strings.TrimSpace(u.subURLEditor.Text())
if name == "" || rawURL == "" { if name == "" || rawURL == "" {
u.message = "Subscription name and URL are required." u.message = "Имя и URL подписки не заполнены."
u.messageColor = dangerColor u.messageColor = dangerColor
return return
} }
if _, err := url.Parse(rawURL); err != nil { if _, err := url.Parse(rawURL); err != nil {
u.message = "The subscription URL is not valid." u.message = "URL подписки не действителен."
u.messageColor = dangerColor u.messageColor = dangerColor
return return
} }
@@ -465,7 +465,7 @@ func (u *ui) addSubscription() {
for _, item := range subs.Subscriptions { for _, item := range subs.Subscriptions {
if item.Name == name { if item.Name == name {
u.message = "A subscription with this name already exists." u.message = "Подписка с таким именем уже существует."
u.messageColor = dangerColor u.messageColor = dangerColor
return return
} }
@@ -483,7 +483,7 @@ func (u *ui) addSubscription() {
u.subNameEditor.SetText("") u.subNameEditor.SetText("")
u.subURLEditor.SetText("") u.subURLEditor.SetText("")
u.message = "Subscription added." u.message = "Подписка добавлена."
u.messageColor = successColor u.messageColor = successColor
u.refresh() u.refresh()
} }
@@ -507,7 +507,7 @@ func (u *ui) deleteSubscription(name string) {
} }
subs.Subscriptions = filtered subs.Subscriptions = filtered
if !found { if !found {
u.message = "Subscription was already removed." u.message = "Подписка уже удалена."
u.messageColor = warningColor u.messageColor = warningColor
return return
} }
@@ -517,7 +517,7 @@ func (u *ui) deleteSubscription(name string) {
return return
} }
u.message = "Subscription removed." u.message = "Подписка удалена."
u.messageColor = successColor u.messageColor = successColor
u.refresh() u.refresh()
} }
@@ -525,20 +525,20 @@ func (u *ui) deleteSubscription(name string) {
func (u *ui) testURL() { func (u *ui) testURL() {
rawURL := strings.TrimSpace(u.testURLEditor.Text()) rawURL := strings.TrimSpace(u.testURLEditor.Text())
if rawURL == "" { if rawURL == "" {
u.message = "Paste a VLESS URL to test." u.message = "Вставьте VLESS ссылку для проверки."
u.messageColor = dangerColor u.messageColor = dangerColor
return return
} }
u.runAction("Testing custom URL...", func() error { u.runAction("Пингуем кастомный URL...", func() error {
ok, latency, err := vless.PingServer(rawURL, 4*time.Second) ok, latency, err := vless.PingServer(rawURL, 4*time.Second)
if err != nil { if err != nil {
return err return err
} }
if !ok { if !ok {
return fmt.Errorf("server is unreachable") return fmt.Errorf("сервер не найден")
} }
return fmt.Errorf("latency %.0f ms", latency) return fmt.Errorf("пинг %.0f мс", latency)
}) })
} }
@@ -588,7 +588,7 @@ func (u *ui) layoutHeader(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical}.Layout( return layout.Flex{Axis: layout.Vertical}.Layout(
gtx, gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lbl := material.Label(u.theme, unit.Sp(15), "GIO DESKTOP") lbl := material.Label(u.theme, unit.Sp(15), "POWERED BY NEVETIME")
lbl.Color = accentColor lbl.Color = accentColor
return lbl.Layout(gtx) return lbl.Layout(gtx)
}), }),
@@ -598,7 +598,7 @@ func (u *ui) layoutHeader(gtx layout.Context) layout.Dimensions {
return lbl.Layout(gtx) return lbl.Layout(gtx)
}), }),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lbl := material.Body1(u.theme, "A modern control surface for VLESS, subscriptions, and live connection state.") lbl := material.Body1(u.theme, "Современный клиент на Go для особой производительности и удобства")
lbl.Color = mutedColor lbl.Color = mutedColor
return lbl.Layout(gtx) return lbl.Layout(gtx)
}), }),
@@ -608,11 +608,11 @@ func (u *ui) layoutHeader(gtx layout.Context) layout.Dimensions {
return layout.Flex{Alignment: layout.Middle}.Layout( return layout.Flex{Alignment: layout.Middle}.Layout(
gtx, gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.refreshBtn, "Refresh", accentSoftColor) return u.layoutButton(gtx, &u.refreshBtn, "Обновить", accentSoftColor)
}), }),
layout.Rigid(spacerW(10)), layout.Rigid(spacerW(10)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.openLogsBtn, "Logs", panelAltColor) return u.layoutButton(gtx, &u.openLogsBtn, "Логи", panelAltColor)
}), }),
) )
}), }),
@@ -624,12 +624,12 @@ func (u *ui) layoutStatusBanner(gtx layout.Context) layout.Dimensions {
inset := layout.UniformInset(unit.Dp(18)) inset := layout.UniformInset(unit.Dp(18))
return inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions { return inset.Layout(gtx, func(gtx layout.Context) layout.Dimensions {
connected := u.statusState != nil && u.statusState.Connected connected := u.statusState != nil && u.statusState.Connected
statusText := "Offline" statusText := "Оффлайн"
statusColor := warningColor statusColor := warningColor
details := "No active tunnel. Open the VLESS or WireGuard tab and press Connect on a saved config." details := "Нет активных туннелей. Откройте VLESS или WireGuard и подключитесь к одному из сохранённых конфигов."
if connected { if connected {
statusText = "Connected" statusText = "Подключен"
statusColor = successColor statusColor = successColor
details = fmt.Sprintf("%s via %s", u.statusState.ConfigName, strings.ToUpper(u.statusState.ConfigType)) details = fmt.Sprintf("%s via %s", u.statusState.ConfigName, strings.ToUpper(u.statusState.ConfigType))
} }
@@ -657,7 +657,7 @@ func (u *ui) layoutStatusBanner(gtx layout.Context) layout.Dimensions {
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
msg := u.message msg := u.message
if msg == "" { if msg == "" {
msg = "Ready." msg = "Готов."
} }
lbl := material.Body2(u.theme, msg) lbl := material.Body2(u.theme, msg)
lbl.Color = u.messageColor lbl.Color = u.messageColor
@@ -669,7 +669,7 @@ func (u *ui) layoutStatusBanner(gtx layout.Context) layout.Dimensions {
) )
}), }),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.disconnectBtn, "Disconnect", dangerColor) return u.layoutButton(gtx, &u.disconnectBtn, "Отключиться", dangerColor)
}), }),
) )
}) })
@@ -700,7 +700,7 @@ func (u *ui) layoutTabs(gtx layout.Context) layout.Dimensions {
return layout.Flex{}.Layout( return layout.Flex{}.Layout(
gtx, gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutTab(gtx, tabDashboard, "Overview") return u.layoutTab(gtx, tabDashboard, "Главная")
}), }),
layout.Rigid(spacerW(10)), layout.Rigid(spacerW(10)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
@@ -712,7 +712,7 @@ func (u *ui) layoutTabs(gtx layout.Context) layout.Dimensions {
}), }),
layout.Rigid(spacerW(10)), layout.Rigid(spacerW(10)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutTab(gtx, tabSubscriptions, "Subscriptions") return u.layoutTab(gtx, tabSubscriptions, "Подписки")
}), }),
) )
} }
@@ -734,15 +734,15 @@ func (u *ui) layoutDashboard(gtx layout.Context) layout.Dimensions {
return layout.Flex{Spacing: layout.SpaceBetween}.Layout( return layout.Flex{Spacing: layout.SpaceBetween}.Layout(
gtx, gtx,
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions { layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
return u.metricCard(gtx, "VLESS configs", fmt.Sprintf("%d", len(u.configs.VLESS)), accentColor) return u.metricCard(gtx, "VLESS конфиги", fmt.Sprintf("%d", len(u.configs.VLESS)), accentColor)
}), }),
layout.Rigid(spacerW(12)), layout.Rigid(spacerW(12)),
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions { layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
return u.metricCard(gtx, "WireGuard configs", fmt.Sprintf("%d", len(u.configs.WireGuard)), accentSoftColor) return u.metricCard(gtx, "WireGuard конфиги", fmt.Sprintf("%d", len(u.configs.WireGuard)), accentSoftColor)
}), }),
layout.Rigid(spacerW(12)), layout.Rigid(spacerW(12)),
layout.Flexed(1, func(gtx layout.Context) layout.Dimensions { layout.Flexed(1, func(gtx layout.Context) layout.Dimensions {
return u.metricCard(gtx, "Subscriptions", fmt.Sprintf("%d", len(u.subs.Subscriptions)), successColor) return u.metricCard(gtx, "Подписки", fmt.Sprintf("%d", len(u.subs.Subscriptions)), successColor)
}), }),
) )
}), }),
@@ -753,17 +753,17 @@ func (u *ui) layoutDashboard(gtx layout.Context) layout.Dimensions {
return layout.Flex{Axis: layout.Vertical}.Layout( return layout.Flex{Axis: layout.Vertical}.Layout(
gtx, gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
lbl := material.H5(u.theme, "Quick latency probe") lbl := material.H5(u.theme, "Быстрый пинг")
lbl.Color = textColor lbl.Color = textColor
return lbl.Layout(gtx) return lbl.Layout(gtx)
}), }),
layout.Rigid(spacerH(10)), layout.Rigid(spacerH(10)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutEditor(gtx, &u.testURLEditor, "Paste a VLESS URL") return u.layoutEditor(gtx, &u.testURLEditor, "Вставьте VLESS ссылку")
}), }),
layout.Rigid(spacerH(12)), layout.Rigid(spacerH(12)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.testURLBtn, "Test URL", accentColor) return u.layoutButton(gtx, &u.testURLBtn, "Протестировать подключение", accentColor)
}), }),
) )
}) })
@@ -833,15 +833,15 @@ func (u *ui) layoutVLESS(gtx layout.Context) layout.Dimensions {
return layout.Flex{}.Layout( return layout.Flex{}.Layout(
gtx, gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.vlessConnectBtns[i], "Connect", accentColor) return u.layoutButton(gtx, &u.vlessConnectBtns[i], "Подключение", accentColor)
}), }),
layout.Rigid(spacerW(8)), layout.Rigid(spacerW(8)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.vlessPingBtns[i], "Ping", accentSoftColor) return u.layoutButton(gtx, &u.vlessPingBtns[i], "Пинг", accentSoftColor)
}), }),
layout.Rigid(spacerW(8)), layout.Rigid(spacerW(8)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.vlessDeleteBtns[i], "Delete", dangerColor) return u.layoutButton(gtx, &u.vlessDeleteBtns[i], "Удалить", dangerColor)
}), }),
) )
}), }),
@@ -911,11 +911,11 @@ func (u *ui) layoutSubscriptions(gtx layout.Context) layout.Dimensions {
return layout.Flex{}.Layout( return layout.Flex{}.Layout(
gtx, gtx,
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.subUpdateBtns[i], "Update configs", accentColor) return u.layoutButton(gtx, &u.subUpdateBtns[i], "Обновить конфиги", accentColor)
}), }),
layout.Rigid(spacerW(8)), layout.Rigid(spacerW(8)),
layout.Rigid(func(gtx layout.Context) layout.Dimensions { layout.Rigid(func(gtx layout.Context) layout.Dimensions {
return u.layoutButton(gtx, &u.subDeleteBtns[i], "Delete", dangerColor) return u.layoutButton(gtx, &u.subDeleteBtns[i], "Удалить", dangerColor)
}), }),
) )
}), }),