Sechs Entscheidungen, mit denen sich eine kleine Electron-i18n-Schicht wartbar halten lässt
Ein praxisnahes Electron-i18n-Design für Spracheinstellungen, typisierte Kataloge, Fallback-Verhalten, Intl-Formatierung und die Synchronisierung von Renderer und Main-Prozess.
12 Min. LesezeitAnleitungenVon Temposhot Team
Eine Desktop-App mit fünf bis zehn Sprachen braucht selten ein großes i18n-Framework. Sie braucht aber einige klare Regeln, weil eine Electron-App zwei Prozesse hat, die beide Text anzeigen: Der Renderer zeichnet die Oberfläche, und der Main-Prozess verwaltet Menüs, Dialoge und Benachrichtigungen. Die sechs folgenden Entscheidungen halten eine kleine, handgeschriebene i18n-Schicht korrekt, während die App und ihre Kataloge wachsen.
1. Eine Einstellung speichern, nicht nur ein Locale
Wenn ein Nutzer Deutsch wählt, und "de" gespeichert wird, wirkt das ausreichend, bis jemand möchte, dass die App der Systemsprache folgt. Speichern Sie stattdessen die Absicht des Nutzers und lösen Sie das tatsächliche Locale zur Laufzeit auf:
export const SUPPORTED = ["en", "de", "it", "ja", "ko", "zh-Hans"] as const;
export type Locale = (typeof SUPPORTED)[number];
export type LanguagePreference = "system" | Locale;
const ALIASES: Record<string, Locale> = { "zh-cn": "zh-Hans", "zh-sg": "zh-Hans" };
export function resolveLocale(pref: LanguagePreference, systemLanguages: string[]): Locale {
if (pref !== "system") return pref;
for (const tag of systemLanguages) {
const lower = tag.toLowerCase();
const exact = SUPPORTED.find((l) => lower === l.toLowerCase() || lower.startsWith(l.toLowerCase() + "-"));
if (exact) return exact;
if (ALIASES[lower]) return ALIASES[lower];
}
return "en";
}
Im Main-Prozess liefert app.getPreferredSystemLanguages() die geordnete Liste aus dem Betriebssystem. Ist "system" gespeichert, erhält ein Nutzer, der die Systemsprache ändert, beim nächsten Start die neue Sprache, ohne die Einstellungen der App anzufassen.
Der Resolver durchläuft die gesamte Präferenzliste, nicht nur den ersten Eintrag. Ein Nutzer mit „Portugiesisch, dann Englisch“ erhält Englisch, weil es seine zweite Wahl ist, nicht weil es der Standard ist. Das Präfix-Matching ordnet de-CH dem Deutschen und zh-Hans-CN dem vereinfachten Chinesisch zu. zh-TW passt auf keinen Eintrag und geht zum nächsten Eintrag über, statt stillschweigend zu vereinfachtem Chinesisch zu werden.
Auflösungsreihenfolge
Die Funktion gibt beim ersten Treffer zurück. Die Reihenfolge der Prüfungen ist wichtig, weil eine gespeicherte Locale nie durch die Systemliste überschrieben werden darf.
Wenn zwei Einträge der Systemliste beide unterstützt werden, gewinnt der frühere Eintrag. macOS behält die Liste in der Reihenfolge, die der Nutzer unter Language & Region festgelegt hat. Der erste unterstützte Eintrag ist daher die erste unterstützte Wahl des Nutzers.
Drei gespeicherte Einstellungen in der Praxis
Die Tabelle zeigt, wie dieselbe Funktion drei Nutzer behandelt. Jede Zeile ist ein Aufruf von resolveLocale mit einem gespeicherten Wert und einer Systemliste.
Nutzer 1 spricht zuerst Französisch, die App liefert aber kein Französisch aus. Die Schleife überspringt fr-FR, trifft beim zweiten Eintrag auf de-DE und gibt Deutsch zurück. Nutzer 3 erhält Englisch aus einem anderen Grund: zh-TW ist kein Alias und passt per Präfix nicht auf vereinfachtes Chinesisch. Die Schleife erreicht en-GB und gibt Englisch zurück. Nutzer 2 liest die Systemliste nie, weil der gespeicherte Wert ein Locale und nicht "system" ist.
Gespeicherte Werte nach dem Entfernen einer Sprache
Eine spätere Version kann eine Sprache entfernen. Der gespeicherte Wert erscheint dann nicht mehr in SUPPORTED, und die Katalogsuche findet keine passende Datei. Ordnen Sie unbekannte gespeicherte Werte beim Laden der Einstellungen "system" zu und schreiben Sie den korrigierten Wert einmal zurück, damit die gespeicherte Datei dem Code entspricht. Der Nutzer behält beim ersten Start nach dem Update eine funktionierende Sprache.
2. Sprachauswahl auch nach einer falschen Wahl lesbar halten
Wählt ein Nutzer versehentlich Japanisch und werden danach alle Sprachnamen auf Japanisch angezeigt, ist „English“ nur schwer wiederzufinden. Zeigen Sie jede Sprache in ihrer eigenen Sprache (Endonym), damit die Liste unabhängig von der aktuellen UI-Sprache gleich aussieht:
export const LANGUAGE_NAMES: Record<Locale, string> = {
en: "English",
de: "Deutsch",
it: "Italiano",
ja: "日本語",
ko: "한국어",
"zh-Hans": "简体中文",
};
Intl.DisplayNames kann diese Namen erzeugen, doch die Ausgabe für Schriftvarianten unterscheidet sich zwischen Engines und Versionen. Eine feste Tabelle mit sechs Zeichenketten lässt sich leichter prüfen. Nur die Option „System default“ wird im Katalog übersetzt, da es eine Wendung und kein Sprachname ist.
Dieselbe Regel in Temposhot
Die Mac-App Temposhot verwendet für ihr Menü Language dasselbe Endonym-Muster. Das Menü steht unter Settings auf dem Tab General und hat sieben Einträge. Die Anleitung legt fest, dass jeder Sprachname in der jeweiligen Sprache geschrieben wird.
Die letzte Zeile ist für die Leser dieses Beitrags wichtig. Die App speichert die Auswahl und wechselt sofort das Locale. Einige Oberflächentexte bleiben nach dem Wechsel auf Englisch, bis die Übersetzungen für die anderen sechs Sprachen ausgeliefert werden.
Reihenfolge im Menü
Das Menü folgt der Reihenfolge von SUPPORTED, Englisch steht vorn. Eine feste Reihenfolge lässt sich leicht testen und ändert sich nicht, wenn ein Übersetzer einen Namen bearbeitet. Eine Sortierung nach Endonym würde die Einträge nach den Sortierregeln jeder Schrift anordnen, was in einem Pull Request schwerer zu prüfen ist.
Ein Locale hinzuzufügen bedeutet, es an SUPPORTED anzuhängen. Der Typ Record<Locale, string> von LANGUAGE_NAMES lässt den Build dann fehlschlagen, bis der neue Eintrag einen Namen hat. Ein Locale kann so nicht im Resolver auftauchen, ohne eine sichtbare Bezeichnung im Menü zu haben.
Das Menü vor einem Release prüfen
Ein Sprachmenü bricht auf kleine Weise, die ein Unit-Test nicht erkennt: ein Name in der falschen Schrift, ein fehlender Eintrag oder ein Eintrag, der nicht gespeichert wird. Ein kurzer manueller Durchlauf vor jedem Release findet diese Fehler.
Führen Sie die Prüfung auf einem Mac aus, dessen Systemsprache nicht Englisch ist. Eine Prüfung auf einem englischen System belegt nur, dass der englische Pfad funktioniert.
3. Den englischen Katalog als TypeScript-Vertrag verwenden
Machen Sie Englisch zur Quelle der Wahrheit und leiten Sie den Typ daraus ab:
export const en = {
"settings.language": "Language",
"settings.language.system": "System default",
"capture.count": "{count} screenshots",
} as const;
export type MessageKey = keyof typeof en;
export type Catalog = Record<MessageKey, string>;
Jeder Aufruf von t("settings.language") wird jetzt vom Compiler geprüft. Ein Tippfehler oder ein aus dem Englischen entfernter Schlüssel lässt den Build fehlschlagen. Übersetzer arbeiten an den anderen Katalogen, können aber keinen Schlüssel hinzufügen, den Englisch nicht hat. Die englische Datei listet daher immer alles auf, was die Oberfläche verwendet.
Flache Schlüssel mit Punkten halten den Typ einfach und machen Diffs leicht lesbar. Verschachtelte Objekte funktionieren ebenfalls, benötigen aber rekursive Typen und erschweren die Nachverfolgung fehlender Schlüssel.
Wer welche Datei bearbeitet
Entwickler bearbeiten en.ts. Übersetzer bearbeiten je eine Locale-Datei und ändern en.ts nicht. Ein Pull Request, der nur in en.ts einen Schlüssel ergänzt, besteht den Compiler weiterhin, weil die anderen Kataloge als Partial typisiert sind. Der Vollständigkeitstest listet dann die fehlenden Schlüssel für jedes Locale auf. So sieht das Team an einer Stelle, welche Übersetzungen für ein Release noch offen sind.
Einen Schlüssel hinzufügen
Ein neuer Schlüssel betrifft vier Stellen. Die folgende Reihenfolge hält den Compiler ab dem ersten Schritt nützlich.
Der letzte Schritt wird von Teams oft übersprungen. Deutsche und finnische Texte sind häufig länger als englische, daher kann eine Schaltflächenbeschriftung, die auf Englisch passt, umbrechen oder abgeschnitten werden. Compiler und Tests erkennen das nicht. Deshalb ist eine visuelle Prüfung der längsten Texte nötig.
Aufbau des Katalogordners
Der Ordner enthält eine Datei pro Locale sowie die Hilfsfunktionen, die sie lesen. Ein flacher Aufbau hält Importe kurz und zeigt eindeutig, welche Datei ein Übersetzer bearbeitet.
Nur en.ts exportiert das Objekt mit as const. Die anderen Katalogdateien importieren Partial<Catalog> aus index.ts. Dadurch kann eine Übersetzungsdatei keinen Schlüssel definieren, den Englisch nicht hat.
Benennung der Schlüssel
Stellen Sie jedem Schlüssel den Bildschirm oder Bereich voran, der ihn verwendet. settings.language und capture.count zeigen, wo ein Text liegt, ohne den Code zu öffnen. Eine Suche nach settings. listet jeden Text dieses Bildschirms auf. Vermeiden Sie Schlüssel, die englische Sätze sind. Ein Schlüssel wie "Language" führt bei einer späteren Umformulierung dazu, dass sowohl der Schlüssel als auch der Text geändert werden müssen.
Ein Schlüssel pro Bedeutung
Ein Schlüssel folgt der Bedeutung eines Satzes, nicht der Anzahl der Stellen, an denen er angezeigt wird. Die Beispiel-App zeigt eine Anzahl an Aufnahmen im Ergebniskopf, in der Statusleiste und im Exportdialog. Alle drei verwenden capture.count, und der Aufrufer setzt {count} ein. Ein Übersetzer korrigiert die Formulierung dann einmal für alle drei Stellen. Ein zweiter Schlüssel mit demselben englischen Text würde sich mit der Zeit auseinanderentwickeln.
4. Laufzeit-Fallback und Vollständigkeitsprüfung beibehalten
Andere Kataloge kommen oft als JSON aus einem Übersetzungswerkzeug, daher kann der Compiler für sie nicht bürgen. Typisieren Sie sie als Partial<Catalog> und fallen Sie zur Laufzeit pro Schlüssel auf Englisch zurück:
let current: Partial<Catalog> = {};
export function setCatalog(next: Partial<Catalog>) {
current = next;
}
export function t(key: MessageKey, vars: Record<string, string | number> = {}): string {
const template = current[key] ?? en[key];
return template.replace(/\{(\w+)\}/g, (_, name) => String(vars[name] ?? `{${name}}`));
}
Der Fallback hält ein Release nutzbar, wenn ein einzelner Text spät kommt. Er verdeckt aber auch die Lücke. Deshalb braucht es einen Test, der fehlschlägt, wenn ein ausgeliefertes Locale unvollständig ist. Beides ist nötig: Der Fallback schützt die Nutzer, der Test schützt das Team davor, versehentlich Fallbacks auszuliefern. Der Testabschnitt unten zeigt die Prüfung.
So sieht ein fehlender Text aus
Das Beispiel verwendet einen deutschen Katalog, der abgeschnitten wurde, bevor der Übersetzer den Einstellungsbildschirm fertiggestellt hat. Die Zahlen stammen aus dem Beispiel und nicht aus einem ausgelieferten Build.
Der Nutzer sieht bei drei Bezeichnungen Englisch und überall sonst Deutsch. Ein roher Schlüssel wie settings.language auf dem Bildschirm wäre schlechter. Der Fallback verhindert das, weil Englisch jeden Schlüssel definiert.
Fehlende Variablen bleiben sichtbar
Die Funktion t lässt {name} in der Ausgabe stehen, wenn vars dafür keinen Wert enthält. Die App läuft weiter, und ein Reviewer sieht den nicht ersetzten Platzhalter in einem Screenshot oder einem Testfehler. Der Platzhalter ist leichter zu finden als eine stille leere Zeichenkette, und er blockiert nicht das Rendern des übrigen Bildschirms.
Den Fallback-Pfad testen
Ein Fallback, den kein Test ausführt, kann unbemerkt brechen. Ein kurzer Test mit einem leeren Katalog deckt den Pfad ab:
it("falls back to English for a missing key", () => {
setCatalog({});
expect(t("settings.language")).toBe("Language");
});
Rufen Sie in den anderen Tests setCatalog mit dem echten Katalog auf, damit jeder Test von einem bekannten Zustand startet.
Der Vollständigkeitstest sollte seine Liste der Locales aus SUPPORTED lesen, nicht aus den Dateien auf dem Datenträger. Eine vorhandene Datei, die nicht aufgeführt ist, kann dann nicht versehentlich ausgeliefert werden. Ein aufgeführtes Locale ohne Datei lässt den Test sofort fehlschlagen.
Der Fallback wirkt pro Schlüssel
Der Fallback gilt für jeden Schlüssel einzeln, nicht für einen ganzen Bildschirm. Ein deutscher Katalog mit 40 von 42 übersetzten Einstellungsschlüsseln zeigt für die beiden fehlenden Bezeichnungen Englisch und für die übrigen 40 Deutsch. Ein Fallback pro Bildschirm würde 40 fertige Texte wegen zweier fehlender auf Englisch zeigen, und das wäre für den Nutzer das schlechtere Ergebnis.
5. Datum und Zahlen außerhalb des Nachrichtenkatalogs formatieren
Kataloge sollten Sätze enthalten, keine Formatierungsregeln. Datum, Zahlen, Dateigrößen und Plurale stammen aus Intl und verwenden das aufgelöste Locale:
const date = new Intl.DateTimeFormat(locale, { dateStyle: "medium", timeStyle: "short" });
const number = new Intl.NumberFormat(locale);
const plural = new Intl.PluralRules(locale);
Ein Katalogtext enthält dann einen Platzhalter wie {date} oder {count}, und der Aufrufer formatiert den Wert, bevor er ihn übergibt. Das hält Übersetzer von Datumsmustern fern. Ein US-englischer Nutzer sieht dadurch „Mar 2, 2026“, ein deutscher Nutzer „02.03.2026“, ohne dass jemand eines der beiden Muster schreibt. Plurale unterscheiden sich je Sprache in der Anzahl ihrer Formen. Wählen Sie die Nachrichtenvariante daher mit Intl.PluralRules und nicht mit count === 1.
Pluralkategorien unterscheiden sich nach Sprache
Intl.PluralRules liefert eine von höchstens sechs Kategorien: zero, one, two, few, many und other. Englisch verwendet zwei davon, Russisch vier. Eine Prüfung auf count === 1 gilt für Englisch und bricht bei Russisch.
Der Katalog enthält eine Variante je Kategorie, die das Locale verwendet. Der Helfer liest plural.select(count) und sucht den passenden Schlüssel, etwa capture.count.one oder capture.count.few. Fehlt eine Kategorie, fällt er auf other zurück, sodass ein teilweise übersetzter Plural nutzbar bleibt.
Einheiten gehören zum Wert
Intl.NumberFormat übernimmt Gruppierung und Dezimaltrennzeichen. Daher stammen 1.2 MB auf Englisch und 1,2 MB auf Deutsch aus demselben Codepfad. Die Einheit ist Teil des formatierten Werts, nicht des Katalogs. Ein Eintrag wie "{size} saved" erhält die formatierte Größe vom Aufrufer, und der Übersetzer ändert nur den Satz um den Wert herum.
Die genaue Datumsausgabe hängt von der Laufzeitumgebung ab
Die Ausgabe von Intl.DateTimeFormat folgt den ICU-Daten der Laufzeitumgebung. Der genaue String kann sich daher zwischen Electron-Versionen ändern. Ein Test, der "Mar 2, 2026, 9:05 AM" fest codiert, schlägt nach einem Upgrade aus einem Grund fehl, der mit der App nichts zu tun hat. Vergleichen Sie die Ausgabe mit dem Ergebnis desselben Intl-Aufrufs im Test, und fixieren Sie die Zeitzone, damit der Test auf jedem Rechner besteht.
6. Die Auswahl im Renderer mit dem Main-Prozess synchronisieren
Der Einstellungsbildschirm liegt im Renderer. Native Menüs, Dialoge, das Tray und Benachrichtigungen werden jedoch im Main-Prozess erstellt. Machen Sie den Main-Prozess zum alleinigen Verwalter der Einstellung:
// preload.ts
contextBridge.exposeInMainWorld("i18n", {
setPreference: (pref: LanguagePreference) => ipcRenderer.invoke("i18n:set", pref),
onChange: (cb: (locale: Locale) => void) =>
ipcRenderer.on("i18n:changed", (_e, locale: Locale) => cb(locale)),
});
// main.ts
ipcMain.handle("i18n:set", (_e, pref: unknown) => {
if (!isPreference(pref)) throw new Error("invalid language preference");
store.set("language", pref);
const locale = resolveLocale(pref, app.getPreferredSystemLanguages());
rebuildMenu(locale);
for (const win of BrowserWindow.getAllWindows()) win.webContents.send("i18n:changed", locale);
return locale;
});
Der Renderer fragt an, der Main-Prozess entscheidet, speichert und sendet an alle Fenster. Jedes Fenster, auch ein später geöffnetes, liest dasselbe aufgelöste Locale. Der Handler prüft den eingehenden Wert, weil IPC-Eingaben nicht vertrauenswürdig sind.
Die Ablage der Auswahl im localStorage des Renderers ist eine übliche Abkürzung, weil der Einstellungsbildschirm dort läuft. Der Wert liegt dann im Speicher eines einzelnen Fensters, und der Main-Prozess kann ihn vor dem Öffnen eines Fensters nicht lesen. Menü und Tray werden jedoch vor dem ersten Fenster erstellt und benötigen den Wert aus dem Speicher des Main-Prozesses.
Der Weg einer Sprachänderung
Eine einzelne Änderung läuft durch beide Prozesse. Die folgende Abfolge zeigt, welcher Prozess jeden Schritt verantwortet.
Der Renderer löst "system" nicht selbst auf. Würde jeder Prozess die Einstellung getrennt auflösen, könnte ein Fenster nach einer Änderung der Systemsprache eine andere Sprache zeigen als das Menü. Ein einziger Resolver im Main-Prozess hält beide gleich.
Den Wert im Handler validieren
Das Preload-Skript typisiert das Argument, aber ein Renderer kann über ipcRenderer.invoke jeden beliebigen Wert senden. Der Main-Prozess prüft den Wert deshalb gegen dieselbe Liste, aus der der Typ stammt:
const isPreference = (value: unknown): value is LanguagePreference =>
value === "system" || (typeof value === "string" && (SUPPORTED as readonly string[]).includes(value));
Ein abgelehnter Wert wirft einen Fehler, und der Speicher wird nicht beschrieben. Nur Werte aus den beiden Listen können store.set erreichen.
Fenster, die nach der Änderung geöffnet werden
Ein Fenster, das nach der Änderung erstellt wird, wartet nicht auf eine Übertragung. Es fragt beim Laden den Main-Prozess ab:
ipcMain.handle("i18n:get", () =>
resolveLocale(store.get("language", "system") as LanguagePreference, app.getPreferredSystemLanguages()),
);
Der Renderer ruft i18n:get einmal beim Start auf und verwendet danach i18n:changed. Beide Wege rufen denselben Resolver auf, daher können sich ein neues und ein altes Fenster nicht widersprechen.
Fenster, die während einer Änderung geschlossen werden
Ein Fenster, das vor der Übertragung geschlossen wird, ist nicht mehr in BrowserWindow.getAllWindows() enthalten, und die Schleife überspringt es. Ein Fenster, das neu lädt, ruft i18n:get erneut auf und erhält den aktuellen Wert. Die Übertragung arbeitet nach dem Best-Effort-Prinzip, und der Ladepfad liefert den korrekten Wert.
Tests, die die Grenzen absichern
- Resolver-Tabelle. Eingaben wie
["de-CH", "en-US"](Deutsch),["zh-TW", "en"](Englisch) und[](Englisch) ergeben die erwarteten Locales. - Vollständigkeit. Für jedes ausgelieferte Locale existiert jeder Schlüssel aus
enund ist nicht leer. - Platzhalter-Parität. Jede Übersetzung verwendet dieselben Platzhalter wie Englisch, daher geht
{count}nie verloren und wird nie umbenannt. - Formatierung. Die Datumsausgabe wird mit einer festen Zeitzone geprüft, damit die Tests auf jedem Rechner bestehen.
- IPC-Handler. Eine ungültige Einstellung wird abgelehnt, und eine gültige löst einen Neuaufbau des Menüs und eine Übertragung aus.
for (const [locale, catalog] of Object.entries(catalogs)) {
for (const key of Object.keys(en) as MessageKey[]) {
expect(catalog[key], `${locale}: ${key}`).toBeTruthy();
}
}
Jeder Test deckt eine Grenze ab. Die Tabelle zeigt, worauf ein fehlgeschlagener Test hinweist.
| Test | Ein Fehler bedeutet |
|---|---|
| Resolver-Tabelle | Die Reihenfolge der Prüfungen oder die Alias-Tabelle wurde geändert |
| Vollständigkeit | Einem ausgelieferten Katalog fehlt ein Schlüssel, den Englisch definiert |
| Platzhalter-Parität | Eine Übersetzung hat eine Variable umbenannt oder entfernt |
| Formatierung | Die Datums- oder Zahlenausgabe hängt vom Rechner ab, nicht vom Locale |
| IPC-Handler | Ein ungültiger Wert hat den Speicher erreicht, oder ein Fenster wurde nicht benachrichtigt |
Führen Sie die Suite bei jeder Änderung an einem Katalog aus, nicht erst vor einem Release. Eine Übersetzung, die einen Platzhalter umbenennt, lässt sich im Pull Request, der sie einführt, am günstigsten korrigieren. Ein Release-Schnitt ist die teuerste Stelle, an der ein solcher Fehler gefunden wird.
Auch eine kleine i18n-Schicht braucht klare Grenzen
Jede Entscheidung zieht eine Linie: Absicht gegenüber aufgelöstem Locale, Namen gegenüber übersetzten Bezeichnungen, Englisch als Vertrag, Fallback gegenüber Vollständigkeit, Sätze gegenüber Formatierung und Renderer gegenüber Main-Prozess. Halten Sie diese Linien ein, dann bleibt eine handgeschriebene Schicht von einigen hundert Zeilen leichter nachvollziehbar als ein Framework, das dasselbe leistet.
Ein Framework lohnt sich, wenn die Kataloge Funktionen benötigen, die die Schicht nicht bietet. Dazu gehören das Extrahieren von Nachrichten aus dem Quellcode, Übersetzungswerkzeuge, die den Prüfstatus verfolgen, oder das Laden von Katalogen zur Laufzeit, die getrennt von der App ausgeliefert werden. Solange kein solcher Bedarf besteht, decken die sechs Entscheidungen oben die häufigen Fehler ab.
Dieselben Grenzen gelten für andere Fenster, die Text anzeigen, etwa eine Web-View oder ein Einstellungsblatt. Jedes davon liest das aufgelöste Locale aus dem Main-Prozess, verwendet denselben Katalogtyp und besteht denselben Vollständigkeitstest. Eine neue Oberfläche braucht dann keine neuen Regeln, nur einen neuen Aufruf von t.
Temposhot, die Mac-App, über die diese Website handelt, ist eine native macOS-App, die mit Xcode gebaut wurde, keine Electron-App. Ihre Spracheinstellung bietet 7 Optionen: System default und sechs Sprachen, die jeweils mit ihrem eigenen Namen angezeigt werden.
Klicks in eine klare Schritt-für-Schritt-Anleitung verwandeln
Um eine Einstellungsänderung wie die oben zu dokumentieren, zeichnen Sie sie mit Action Capture auf. Temposhot kann auf Apple-Silicon-Macs mit macOS 14 oder neuer kostenlos heruntergeladen werden.
electroni18ntypescriptengineering
Verwandeln Sie wiederholbare Screenshots in fertige Ergebnisse
Temposhot erstellt Screenshots per Timer oder bei jedem Klick und exportiert das Ergebnis als PDF, Bilder, ZIP oder MP4.
Ähnliche Beiträge
- Screenshots auf dem Mac mit der Kommandozeile automatisierenWiederholte Vollbild-, Bereichs- und Seitenwechsel-Screenshots mit macOS screencapture aufnehmen, mit sicheren Dateinamen und Fehlerbehebung.
- Website-Screenshots mit Playwright automatisierenWebsite-Screenshots mit Playwright und JavaScript automatisieren. Eine Seite, vollständige Seiten, mobile Ansichten und URL-Batches mit Wiederholungsversuchen aufnehmen.
- Website-Screenshots mit Puppeteer automatisierenWebsite-Screenshots mit Puppeteer und JavaScript automatisieren. Eine Seite, vollständige Seiten, URL-Batches und mobile Ansichten mit einem wiederverwendbaren Skript aufnehmen.
- Die besten Xnapper-Alternativen für den Mac im Jahr 2026Vergleich von Xnapper-Alternativen für den Mac: wiederholte Aufnahme, Scroll-Aufnahme und Aufzeichnung, kostenlose Hintergründe, plattformübergreifende Anleitungen und die eingebaute App.