Compare commits

..

4 Commits

Author SHA1 Message Date
Anders Kaseorg
3956252309 xo: Fix unicorn/prefer-event-target.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2025-10-02 00:43:33 -07:00
Anders Kaseorg
5eccd49fef Switch i18next-parser to i18next-cli.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2025-10-02 00:13:55 -07:00
Anders Kaseorg
c08bbf49ab release: New release v5.12.2.
Signed-off-by: Anders Kaseorg <anders@zulip.com>
2025-09-01 10:49:56 -07:00
Hosted Weblate
913eda8b1e translations: Update translations from Weblate. 2025-09-01 19:39:02 +02:00
13 changed files with 1200 additions and 1669 deletions

View File

@@ -1,4 +1,4 @@
import {EventEmitter} from "node:events";
import * as z from "zod";
import {
type ClipboardDecrypter,
@@ -7,11 +7,11 @@ import {
import {type NotificationData, newNotification} from "./notification/index.ts";
import {ipcRenderer} from "./typed-ipc-renderer.ts";
type ListenerType = (...arguments_: any[]) => void;
type ListenerType = (...arguments_: unknown[]) => void;
/* eslint-disable @typescript-eslint/naming-convention */
export type ElectronBridge = {
send_event: (eventName: string | symbol, ...arguments_: unknown[]) => boolean;
send_event: (eventName: string, ...arguments_: unknown[]) => boolean;
on_event: (eventName: string, listener: ListenerType) => void;
new_notification: (
title: string,
@@ -32,15 +32,26 @@ let idle = false;
// Indicates the time at which user was last active
let lastActive = Date.now();
export const bridgeEvents = new EventEmitter(); // eslint-disable-line unicorn/prefer-event-target
export const bridgeEvents = new EventTarget();
export class BridgeEvent extends Event {
constructor(
type: string,
public readonly arguments_: unknown[] = [],
) {
super(type);
}
}
/* eslint-disable @typescript-eslint/naming-convention */
const electron_bridge: ElectronBridge = {
send_event: (eventName: string | symbol, ...arguments_: unknown[]): boolean =>
bridgeEvents.emit(eventName, ...arguments_),
send_event: (eventName: string, ...arguments_: unknown[]): boolean =>
bridgeEvents.dispatchEvent(new BridgeEvent(eventName, arguments_)),
on_event(eventName: string, listener: ListenerType): void {
bridgeEvents.on(eventName, listener);
bridgeEvents.addEventListener(eventName, (event) => {
listener(...z.instanceof(BridgeEvent).parse(event).arguments_);
});
},
new_notification: (
@@ -65,28 +76,25 @@ const electron_bridge: ElectronBridge = {
};
/* eslint-enable @typescript-eslint/naming-convention */
bridgeEvents.on("total_unread_count", (unreadCount: unknown) => {
if (typeof unreadCount !== "number") {
throw new TypeError("Expected string for unreadCount");
}
bridgeEvents.addEventListener("total_unread_count", (event) => {
const [unreadCount] = z
.tuple([z.number()])
.parse(z.instanceof(BridgeEvent).parse(event).arguments_);
ipcRenderer.send("unread-count", unreadCount);
});
bridgeEvents.on("realm_name", (realmName: unknown) => {
if (typeof realmName !== "string") {
throw new TypeError("Expected string for realmName");
}
bridgeEvents.addEventListener("realm_name", (event) => {
const [realmName] = z
.tuple([z.string()])
.parse(z.instanceof(BridgeEvent).parse(event).arguments_);
const serverUrl = location.origin;
ipcRenderer.send("realm-name-changed", serverUrl, realmName);
});
bridgeEvents.on("realm_icon_url", (iconUrl: unknown) => {
if (typeof iconUrl !== "string") {
throw new TypeError("Expected string for iconUrl");
}
bridgeEvents.addEventListener("realm_icon_url", (event) => {
const [iconUrl] = z
.tuple([z.string()])
.parse(z.instanceof(BridgeEvent).parse(event).arguments_);
const serverUrl = location.origin;
ipcRenderer.send(
"realm-icon-changed",

View File

@@ -1,21 +1,21 @@
import {contextBridge} from "electron/renderer";
import electron_bridge, {bridgeEvents} from "./electron-bridge.ts";
import electron_bridge, {BridgeEvent, bridgeEvents} from "./electron-bridge.ts";
import * as NetworkError from "./pages/network.ts";
import {ipcRenderer} from "./typed-ipc-renderer.ts";
contextBridge.exposeInMainWorld("electron_bridge", electron_bridge);
ipcRenderer.on("logout", () => {
bridgeEvents.emit("logout");
bridgeEvents.dispatchEvent(new BridgeEvent("logout"));
});
ipcRenderer.on("show-keyboard-shortcuts", () => {
bridgeEvents.emit("show-keyboard-shortcuts");
bridgeEvents.dispatchEvent(new BridgeEvent("show-keyboard-shortcuts"));
});
ipcRenderer.on("show-notification-settings", () => {
bridgeEvents.emit("show-notification-settings");
bridgeEvents.dispatchEvent(new BridgeEvent("show-notification-settings"));
});
window.addEventListener("load", () => {

View File

@@ -2,6 +2,12 @@
All notable changes to the Zulip desktop app are documented in this file.
### v5.12.2 --2025-09-01
**Fixes**:
- Corrected broken translations in Chinese (simplified), Finnish, German, Greek, and Tamil that crashed the app.
### v5.12.1 --2025-08-29
**Enhancements**:

View File

@@ -1,18 +0,0 @@
import type {UserConfig} from "i18next-parser";
const config: UserConfig = {
createOldCatalogs: false,
defaultValue: (locale, namespace, key, value) =>
locale === "en" ? key! : value!,
indentation: "\t" as unknown as number,
input: ["app/**/*.ts"],
keySeparator: false,
lexers: {
ts: [{lexer: "JavascriptLexer", functions: ["t.__", "t.__mf"]}],
},
locales: ["en"],
namespaceSeparator: false,
output: "public/translations/$LOCALE.json",
sort: (a, b) => (a < b ? -1 : a > b ? 1 : 0),
};
export default config;

14
i18next.config.ts Normal file
View File

@@ -0,0 +1,14 @@
import {defineConfig} from "i18next-cli";
export default defineConfig({
locales: ["en"],
extract: {
input: ["app/**/*.ts"],
output: "public/translations/{{language}}.json",
functions: ["t.__", "t.__mf"],
keySeparator: false,
nsSeparator: false,
sort: (a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0),
indentation: "\t",
},
});

2731
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "zulip",
"productName": "Zulip",
"version": "5.12.1",
"version": "5.12.2",
"main": "./dist-electron/index.cjs",
"description": "Zulip Desktop App",
"license": "Apache-2.0",
@@ -178,7 +178,7 @@
"eslint-import-resolver-typescript": "^4.4.4",
"htmlhint": "^1.1.2",
"i18n": "^0.15.1",
"i18next-parser": "^9.3.0",
"i18next-cli": "^1.2.1",
"node-json-db": "^1.3.0",
"p-fifo": "^1.0.0",
"playwright-core": "^1.41.0-alpha-jan-9-2024",

View File

@@ -14,7 +14,7 @@ Within that Weblate project, if you'd like to focus on Zulip Desktop, look
at the **Desktop** component. The other components are for the Zulip web/mobile
app, where translations are also very welcome.
(\*) One file is an exception: `en.json` is maintained by `i18next-parser` as a
(\*) One file is an exception: `en.json` is maintained by `i18next-cli extract` as a
list of (English) messages in the source code, and is used by Weblate as
a list of strings to be translated. It doesn't contain any
translations.

View File

@@ -113,14 +113,14 @@
"OK": "OK",
"OR": "ODER",
"On macOS, the OS spellchecker is used.": "In macOS wird die OS Rechtschreibprüfung verwendet.",
"Opening {{{link}}}…": "Öffne {{{link}}…",
"Opening {{{link}}}…": "Öffne {{{link}}}…",
"Organization URL": "Organisations-URL",
"Organizations": "Organisationen",
"PAC script": "PAC-Skript",
"Paste": "Einfügen",
"Paste and Match Style": "Ohne Formatierung einfügen",
"Please contact your system administrator.": "Bitte kontaktiere deinen Systemadministrator.",
"Press {{{exitKey}}} to exit full screen": "Drücke {{{exitKey}} um den Vollbildmodus zu beenden",
"Press {{{exitKey}}} to exit full screen": "Drücke {{{exitKey}}} um den Vollbildmodus zu beenden",
"Proxy": "Proxy",
"Proxy bypass rules": "Proxy-Ausnahmen",
"Proxy rules": "Proxy-Regeln",
@@ -132,7 +132,7 @@
"Redo": "Wiederholen",
"Release Notes": "Hinweise zur Versionsfreigabe",
"Reload": "Neu laden",
"Removing {{{url}}} is a restricted operation.": "Entfernung von {{{url}} ist eine eingeschränkte Operation.",
"Removing {{{url}}} is a restricted operation.": "Entfernung von {{{url}}} ist eine eingeschränkte Operation.",
"Report an Issue": "Ein Problem melden",
"Reset App Settings": "App-Einstellungen zurücksetzen",
"Reset the application, thus deleting all the connected organizations and accounts.": "Die Anwendung zurücksetzen. Dabei werden alle verbundenen Organisationen und Konten gelöscht.",

View File

@@ -1,7 +1,7 @@
{
"A new update {{{version}}} has been downloaded.": "Έχει ληφθεί μια νέα ενημέρωση {{{version}}}.",
"A new version {{{version}}} is available. Please update using your package manager.": "Μια νέα έκδοση {{{version}}} είναι διαθέσιμη. Παρακαλούμε ενημερώστε χρησιμοποιώντας τον διαχειριστή πακέτων.",
"A new version {{{version}}} of Zulip Desktop is available.": "Μια νέα έκδοση {{{version}} του Zulip Desktop είναι διαθέσιμη.",
"A new version {{{version}}} of Zulip Desktop is available.": "Μια νέα έκδοση {{{version}}} του Zulip Desktop είναι διαθέσιμη.",
"About": "Περί",
"About Zulip": "Περί Zulip",
"Actual Size": "Πραγματικό μέγεθος",
@@ -30,7 +30,7 @@
"Change": "Αλλαγή",
"Change the language from System Preferences → Keyboard → Text → Spelling.": "Αλλάξτε τη γλώσσα από τις Προτιμήσεις Συστήματος → Πληκτρολόγιο → Κείμενο → Γραφή.",
"Check for Updates": "Έλεγχος για Ενημερώσεις",
"Click to show {{{fileName}}} in folder": "Κάνετε κλικ για την εμφάνιση του {{{fileName}} στο φάκελο",
"Click to show {{{fileName}}} in folder": "Κάνετε κλικ για την εμφάνιση του {{{fileName}}} στο φάκελο",
"Close": "Κλείσιμο",
"Connect": "Σύνδεση",
"Connect to another organization": "Σύνδεση με διαφορετικό οργανισμό",

View File

@@ -1,6 +1,6 @@
{
"A new update {{{version}}} has been downloaded.": "Uusi päivitys {{{version}}} on ladattu.",
"A new version {{{version}}} is available. Please update using your package manager.": "Uusi versio {{{version}} saatavilla. Päivitä paketinhallinasta.",
"A new version {{{version}}} is available. Please update using your package manager.": "Uusi versio {{{version}}} saatavilla. Päivitä paketinhallinasta.",
"A new version {{{version}}} of Zulip Desktop is available.": "Uusi versio {{{version}}} Zulip Desktopista on saatavilla.",
"About": "Tietoja",
"About Zulip": "Tietoa Zulipista",
@@ -30,7 +30,7 @@
"Change": "Muuta",
"Change the language from System Preferences → Keyboard → Text → Spelling.": "Change the language from System Preferences → Keyboard → Text → Spelling.",
"Check for Updates": "Tarkista päivitykset",
"Click to show {{{fileName}}} in folder": "Paina nähdäksesis tiedoston {{{fileName}} kansiossaan",
"Click to show {{{fileName}}} in folder": "Paina nähdäksesis tiedoston {{{fileName}}} kansiossaan",
"Close": "Sulje",
"Connect": "Yhdistä",
"Connect to another organization": "Yhdistä toiseen organisaatioon",
@@ -42,7 +42,7 @@
"Copy Image URL": "Kopioi kuvan URL",
"Copy Link": "Kopioi linkki",
"Copy Zulip URL": "Kopioi Zulip-URL",
"Could not add {{{domain}}}. Please contact your system administrator.": "Ei voitu lisätä kohdetta {{{domain}}. Ota yhteys järjesstelmänvalvojaan.",
"Could not add {{{domain}}}. Please contact your system administrator.": "Ei voitu lisätä kohdetta {{{domain}}}. Ota yhteys järjesstelmänvalvojaan.",
"Create a new organization": "Luo uusi organisaatio",
"Custom CSS file deleted": "Mukautettu CSS-tiedosto poistettu",
"Cut": "Leikkaa",
@@ -113,14 +113,14 @@
"OK": "OK",
"OR": "TAI",
"On macOS, the OS spellchecker is used.": "On macOS, the OS spellchecker is used.",
"Opening {{{link}}}…": "Avataan {{{link}}…",
"Opening {{{link}}}…": "Avataan {{{link}}}…",
"Organization URL": "Organisaation URL",
"Organizations": "Organisaatiot",
"PAC script": "PAC-skripti",
"Paste": "Liitä",
"Paste and Match Style": "Liitä ja täsmää tyylit",
"Please contact your system administrator.": "Ota yhteys järjestelmänvalvojaan.",
"Press {{{exitKey}}} to exit full screen": "Paina {{{exitKey}} poistuaksesi koko näytön tilasta",
"Press {{{exitKey}}} to exit full screen": "Paina {{{exitKey}}} poistuaksesi koko näytön tilasta",
"Proxy": "Välityspalvelin",
"Proxy bypass rules": "Välityspalvelimen ohituksen säännöt",
"Proxy rules": "Välityspalvelimen-säännöt",
@@ -132,7 +132,7 @@
"Redo": "Tee uudelleen",
"Release Notes": "Julkaisutiedot",
"Reload": "Lataa uudelleen",
"Removing {{{url}}} is a restricted operation.": "Osoitteen {{{url}} poisto on rajoitettu operaatio.",
"Removing {{{url}}} is a restricted operation.": "Osoitteen {{{url}}} poisto on rajoitettu operaatio.",
"Report an Issue": "Raportoi ongelmasta",
"Reset App Settings": "Nollaa asetukset",
"Reset the application, thus deleting all the connected organizations and accounts.": "Nollaa sovelluksen, ja poistaa kaikki liitetyt organisaatiot ja tilit.",

View File

@@ -86,7 +86,7 @@
"Log Out": "வெளியேறு",
"Log Out of Organization": "நிறுவனத்திலிருந்து வெளியேறு",
"Look Up": "பாருங்கள்",
"Maintained by {{{link}}}Zulip{{{endLink}}}": "{{{link}}} Zulip {{{endLink}} by ஆல் பராமரிக்கப்படுகிறது",
"Maintained by {{{link}}}Zulip{{{endLink}}}": "{{{link}}} Zulip {{{endLink}}} by ஆல் பராமரிக்கப்படுகிறது",
"Manual proxy configuration": "கையேடு ப்ராக்ஸி உள்ளமைவு",
"Minimize": "குறைத்தல்",
"Mute all sounds from Zulip": "ஜூலிப்பிலிருந்து எல்லா ஒலிகளையும் முடக்கு",

View File

@@ -42,7 +42,7 @@
"Copy Image URL": "复制图片链接",
"Copy Link": "复制链接",
"Copy Zulip URL": "复制Zulip地址",
"Could not add {{{domain}}}. Please contact your system administrator.": "无法添加{{{domain}},请联系您的系统管理员。",
"Could not add {{{domain}}}. Please contact your system administrator.": "无法添加{{{domain}}},请联系您的系统管理员。",
"Create a new organization": "创建新的组织",
"Custom CSS file deleted": "自定义CSS文件已删除",
"Cut": "剪切",
@@ -113,14 +113,14 @@
"OK": "确定",
"OR": "或",
"On macOS, the OS spellchecker is used.": "在 macOS 上,使用操作系统的拼写检查器。",
"Opening {{{link}}}…": "正在打开{{{link}}…",
"Opening {{{link}}}…": "正在打开{{{link}}}…",
"Organization URL": "组织 URL",
"Organizations": "组织",
"PAC script": "PAC 配置文件",
"Paste": "粘贴",
"Paste and Match Style": "粘贴并匹配格式",
"Please contact your system administrator.": "请联系您的系统管理员。",
"Press {{{exitKey}}} to exit full screen": "按{{{exitKey}}退出全屏",
"Press {{{exitKey}}} to exit full screen": "按{{{exitKey}}}退出全屏",
"Proxy": "代理",
"Proxy bypass rules": "代理绕过规则",
"Proxy rules": "代理规则",
@@ -132,7 +132,7 @@
"Redo": "撤销",
"Release Notes": "发行说明",
"Reload": "重新加载",
"Removing {{{url}}} is a restricted operation.": "移除{{{url}}是受限操作。",
"Removing {{{url}}} is a restricted operation.": "移除{{{url}}}是受限操作。",
"Report an Issue": "反馈问题",
"Reset App Settings": "重置应用设置",
"Reset the application, thus deleting all the connected organizations and accounts.": "重置应用程序,将删除所有已连接的组织、账号和证书。",
@@ -189,7 +189,7 @@
"Zulip Update": "Zulip 更新",
"keyboard shortcuts": "快捷键",
"your-organization.zulipchat.com or zulip.your-organization.com": "your-organization.zulipchat.com 或 zulip.your-organization.com",
"{number, plural, one {# unread message} other {# unread messages}}": "{number, plural, one {# 条未读消息} other {# 条未读消息}",
"{number, plural, one {# unread message} other {# unread messages}}": "{number, plural, one {# 条未读消息} other {# 条未读消息}}",
"{number, plural, one {Could not add # organization} other {Could not add # organizations}}": "{number, plural, one {无法添加 # 个组织} other {无法添加 # 个组织}}",
"{{{server}}} runs an outdated Zulip Server version {{{version}}}. It may not fully work in this app.": "{{{server}}}在过时的{{{version}}}版Zulip服务器上运行。在该应用中可能无法正常运作。"
}