diff --git a/CLAUDE.md b/CLAUDE.md index 13bfff9..a42746d 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -116,7 +116,7 @@ i18n is **global, URL-driven infrastructure**, not a per-section feature. `src/l 3. Add the locale's chrome strings. `en` and `zh-Hans` live inline in the `strings` dict in `i18n.ts`; every other locale keeps its `UIStrings` in its own file `src/lib/ui/.ts` (imported into the dict) so locales can be authored independently without colliding on one file. Keep each locale's `UIStrings` complete — page body copy lives in the page, only shared chrome lives here. 4. Keep localized JSON-LD in sync: set the localized `url` and add `inLanguage` (see `zh/voice/index.astro`). -**Blog posts** are localized via the content collection: English posts live at `src/content/blog/*.md`; translations live under `src/content/blog//*.md` with a `lang:` frontmatter field (schema in `content.config.ts`). The default-locale blog routes filter to `data.lang === 'en'`; each `/​/blog/` route filters to its own language and strips the `/` id prefix for the URL. **Data-driven pages** (e.g. `voice/alternatives/`) keep one template per locale and read locale-keyed datasets via `getAlternatives(locale)` in `voice-alternatives.ts`; `en` and `zh-Hans` are inline there, every other locale's dataset lives in `src/lib/alternatives/.ts` and is imported (same per-locale-file pattern as the UI strings). +**Blog posts** are localized via the content collection: English posts live at `src/content/blog/*.md`; translations live under `src/content/blog//*.md` with a `lang:` frontmatter field (schema in `content.config.ts`). The default-locale blog routes filter to `data.lang === 'en'`; each `/​/blog/` route filters to its own language and strips the `/` id prefix for the URL. Every blog route (listings, per-post pages, RSS) filters through **`blogFilter(lang)` in `src/lib/blog.ts`**, the single place that drops `draft: true` posts — so drafts vanish everywhere at once. Drafts are hidden in normal builds; to preview one locally set `DRAFTS=1` (`make dev-draft` for the dev server, `make build-draft` for a production build). The var is read in Node at build/dev time, never ships to the client, and is unset in CI/Cloudflare so drafts can never leak to production. **Data-driven pages** (e.g. `voice/alternatives/`) keep one template per locale and read locale-keyed datasets via `getAlternatives(locale)` in `voice-alternatives.ts`; `en` and `zh-Hans` are inline there, every other locale's dataset lives in `src/lib/alternatives/.ts` and is imported (same per-locale-file pattern as the UI strings). To add a whole new language: add its `localeDefs` entry (with `slug` and any `hreflangAliases`), add its base paths to `translatedRoutes`, add its slug↔code to both the `i18n` and `sitemap` maps in `astro.config.mjs`, create `src/lib/ui/.ts` + `src/lib/alternatives/.ts`, and create the `src/pages//**` page tree + `src/content/blog//*.md` posts. diff --git a/Makefile b/Makefile index 88d70fc..7271a0a 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ SHELL := /bin/bash NVM := . ~/.nvm/nvm.sh && nvm use 22 && -.PHONY: dev build preview sync screenshots install clean cf-build help +.PHONY: dev dev-draft build build-draft preview sync screenshots install clean cf-build help .DEFAULT_GOAL := help # Copy needed assets from wavekat-brand submodule → public/ @@ -17,10 +17,18 @@ screenshots: dev: $(NVM) npm run dev +# Start dev server with draft blog posts visible (local only — never deploy this) +dev-draft: + $(NVM) DRAFTS=1 npm run dev + # Build for production → dist/ build: $(NVM) npm run build +# Build including draft blog posts (local preview only — drafts must NOT ship) +build-draft: + $(NVM) DRAFTS=1 npm run build + # Preview production build locally preview: build $(NVM) npm run preview @@ -41,7 +49,9 @@ help: @echo "Usage: make " @echo "" @echo " dev Start dev server" + @echo " dev-draft Start dev server with draft blog posts visible" @echo " build Build for production → dist/" + @echo " build-draft Build including draft posts (local preview only)" @echo " preview Build and preview locally" @echo " sync Copy assets from wavekat-brand submodule" @echo " screenshots Refresh framed app screenshots → public/screenshots/" diff --git a/public/screenshots/in-call-hold/de.webp b/public/screenshots/in-call-hold/de.webp new file mode 100644 index 0000000..bff13c9 Binary files /dev/null and b/public/screenshots/in-call-hold/de.webp differ diff --git a/public/screenshots/in-call-hold/en.webp b/public/screenshots/in-call-hold/en.webp new file mode 100644 index 0000000..9b33896 Binary files /dev/null and b/public/screenshots/in-call-hold/en.webp differ diff --git a/public/screenshots/in-call-hold/es.webp b/public/screenshots/in-call-hold/es.webp new file mode 100644 index 0000000..812db53 Binary files /dev/null and b/public/screenshots/in-call-hold/es.webp differ diff --git a/public/screenshots/in-call-hold/fr.webp b/public/screenshots/in-call-hold/fr.webp new file mode 100644 index 0000000..457eabf Binary files /dev/null and b/public/screenshots/in-call-hold/fr.webp differ diff --git a/public/screenshots/in-call-hold/it.webp b/public/screenshots/in-call-hold/it.webp new file mode 100644 index 0000000..1315a40 Binary files /dev/null and b/public/screenshots/in-call-hold/it.webp differ diff --git a/public/screenshots/in-call-hold/ja.webp b/public/screenshots/in-call-hold/ja.webp new file mode 100644 index 0000000..0b40b62 Binary files /dev/null and b/public/screenshots/in-call-hold/ja.webp differ diff --git a/public/screenshots/in-call-hold/ko.webp b/public/screenshots/in-call-hold/ko.webp new file mode 100644 index 0000000..21b3283 Binary files /dev/null and b/public/screenshots/in-call-hold/ko.webp differ diff --git a/public/screenshots/in-call-hold/zh-Hans.webp b/public/screenshots/in-call-hold/zh-Hans.webp new file mode 100644 index 0000000..955fd04 Binary files /dev/null and b/public/screenshots/in-call-hold/zh-Hans.webp differ diff --git a/public/screenshots/in-call-hold/zh-Hant.webp b/public/screenshots/in-call-hold/zh-Hant.webp new file mode 100644 index 0000000..7a346a8 Binary files /dev/null and b/public/screenshots/in-call-hold/zh-Hant.webp differ diff --git a/public/screenshots/in-call-transfer/de.webp b/public/screenshots/in-call-transfer/de.webp new file mode 100644 index 0000000..305ba2d Binary files /dev/null and b/public/screenshots/in-call-transfer/de.webp differ diff --git a/public/screenshots/in-call-transfer/en.webp b/public/screenshots/in-call-transfer/en.webp new file mode 100644 index 0000000..8bab46a Binary files /dev/null and b/public/screenshots/in-call-transfer/en.webp differ diff --git a/public/screenshots/in-call-transfer/es.webp b/public/screenshots/in-call-transfer/es.webp new file mode 100644 index 0000000..9ec7aee Binary files /dev/null and b/public/screenshots/in-call-transfer/es.webp differ diff --git a/public/screenshots/in-call-transfer/fr.webp b/public/screenshots/in-call-transfer/fr.webp new file mode 100644 index 0000000..b05a81c Binary files /dev/null and b/public/screenshots/in-call-transfer/fr.webp differ diff --git a/public/screenshots/in-call-transfer/it.webp b/public/screenshots/in-call-transfer/it.webp new file mode 100644 index 0000000..a14c673 Binary files /dev/null and b/public/screenshots/in-call-transfer/it.webp differ diff --git a/public/screenshots/in-call-transfer/ja.webp b/public/screenshots/in-call-transfer/ja.webp new file mode 100644 index 0000000..eb75470 Binary files /dev/null and b/public/screenshots/in-call-transfer/ja.webp differ diff --git a/public/screenshots/in-call-transfer/ko.webp b/public/screenshots/in-call-transfer/ko.webp new file mode 100644 index 0000000..a0eac22 Binary files /dev/null and b/public/screenshots/in-call-transfer/ko.webp differ diff --git a/public/screenshots/in-call-transfer/zh-Hans.webp b/public/screenshots/in-call-transfer/zh-Hans.webp new file mode 100644 index 0000000..f9dd3ab Binary files /dev/null and b/public/screenshots/in-call-transfer/zh-Hans.webp differ diff --git a/public/screenshots/in-call-transfer/zh-Hant.webp b/public/screenshots/in-call-transfer/zh-Hant.webp new file mode 100644 index 0000000..52cccd1 Binary files /dev/null and b/public/screenshots/in-call-transfer/zh-Hant.webp differ diff --git a/public/screenshots/in-call-waiting/de.webp b/public/screenshots/in-call-waiting/de.webp new file mode 100644 index 0000000..9220632 Binary files /dev/null and b/public/screenshots/in-call-waiting/de.webp differ diff --git a/public/screenshots/in-call-waiting/en.webp b/public/screenshots/in-call-waiting/en.webp new file mode 100644 index 0000000..20afa2b Binary files /dev/null and b/public/screenshots/in-call-waiting/en.webp differ diff --git a/public/screenshots/in-call-waiting/es.webp b/public/screenshots/in-call-waiting/es.webp new file mode 100644 index 0000000..2a80d6a Binary files /dev/null and b/public/screenshots/in-call-waiting/es.webp differ diff --git a/public/screenshots/in-call-waiting/fr.webp b/public/screenshots/in-call-waiting/fr.webp new file mode 100644 index 0000000..6bb9b56 Binary files /dev/null and b/public/screenshots/in-call-waiting/fr.webp differ diff --git a/public/screenshots/in-call-waiting/it.webp b/public/screenshots/in-call-waiting/it.webp new file mode 100644 index 0000000..72cca85 Binary files /dev/null and b/public/screenshots/in-call-waiting/it.webp differ diff --git a/public/screenshots/in-call-waiting/ja.webp b/public/screenshots/in-call-waiting/ja.webp new file mode 100644 index 0000000..983889b Binary files /dev/null and b/public/screenshots/in-call-waiting/ja.webp differ diff --git a/public/screenshots/in-call-waiting/ko.webp b/public/screenshots/in-call-waiting/ko.webp new file mode 100644 index 0000000..d8ec488 Binary files /dev/null and b/public/screenshots/in-call-waiting/ko.webp differ diff --git a/public/screenshots/in-call-waiting/zh-Hans.webp b/public/screenshots/in-call-waiting/zh-Hans.webp new file mode 100644 index 0000000..6f1fec2 Binary files /dev/null and b/public/screenshots/in-call-waiting/zh-Hans.webp differ diff --git a/public/screenshots/in-call-waiting/zh-Hant.webp b/public/screenshots/in-call-waiting/zh-Hant.webp new file mode 100644 index 0000000..a621670 Binary files /dev/null and b/public/screenshots/in-call-waiting/zh-Hant.webp differ diff --git a/scripts/sync-screenshots.js b/scripts/sync-screenshots.js index 3dcea61..384fda6 100644 --- a/scripts/sync-screenshots.js +++ b/scripts/sync-screenshots.js @@ -62,6 +62,9 @@ const destRoot = join(root, "public/screenshots"); // the Mac build. Defaults to "ubuntu" when omitted. const SCENES = [ { name: "in-call", source: "voice", frame: "ubuntu" }, // a placed call + { name: "in-call-hold", source: "voice", frame: "ubuntu" }, // parked call, amber banner + { name: "in-call-waiting", source: "voice", frame: "ubuntu" }, // switcher, two held + { name: "in-call-transfer", source: "voice", frame: "ubuntu" }, // Complete transfer { name: "settings-automation", source: "voice", frame: "ubuntu" }, // enable CLI { name: "settings-automation-agents", source: "voice", frame: "ubuntu" }, // connect { name: "provider-picker-2talk", source: "voice", frame: "ubuntu" }, // pick 2talk (providers/2talk) diff --git a/src/content/blog/de/hold-switch-and-transfer-calls.md b/src/content/blog/de/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..0fd2980 --- /dev/null +++ b/src/content/blog/de/hold-switch-and-transfer-calls.md @@ -0,0 +1,85 @@ +--- +title: "Anrufe halten, wechseln und weiterleiten wie eine Telefonzentrale" +description: "WaveKat Voice kann Anrufe jetzt halten, einen zweiten Anruf während des ersten annehmen und Anrufer weiterleiten — ohne oder mit Rückfrage — auf Mac und Linux, und die Aufnahme pausiert beim Halten automatisch." +date: 2026-07-05 +author: Eason Guo +tags: [Sprach-KI, Anrufe] +lang: "de" +--- + +WaveKat Voice — das SIP-Softphone für Mac und Linux, das jeden Anruf aufzeichnet und transkribiert — kann jetzt die drei Dinge, die ein Empfang den ganzen Tag tut: einen Anrufer in die Warteschleife legen, einen zweiten Anruf annehmen, während der erste wartet, und einen Anrufer an jemand anderen weiterleiten — entweder sofort oder erst nach Rücksprache. Sie erscheinen mit WaveKat Voice [0.0.42](/de/voice/changelog/#0.0.42). + +Das ist der bislang wörtlichste Schritt hin zu unserem Ziel, [jedem kleinen Unternehmen die Stimme eines großen zu geben](/de/blog/hello-world/). Wer bei einem großen Unternehmen anruft, hört „Einen Moment, ich stelle Sie durch" — und es funktioniert, weil dort eine Empfangskraft mit einer Telefonzentrale sitzt. Jetzt gibt [WaveKat Voice](/de/voice/) — das bereits jeden Anruf aufzeichnet und transkribiert — einem Ein-Personen-Betrieb dieselben Handgriffe. Halten, Anklopfen und Weiterleiten sind die Bedienelemente, nach denen am Empfang ständig gegriffen wird, und jedes ernstzunehmende [Softphone](/de/voice/alternatives/) muss sie haben — WaveKat Voice hat sie jetzt, mit einer eigenen Besonderheit: Was während des Haltens passiert, bleibt aus der Aufnahme heraus. + +## Einen Anrufer halten + +Wer in WaveKat Voice einen Anrufer hält, pausiert die Aufnahme und das Live-Transkript für die gesamte Zeit, in der der Anruf geparkt ist — nichts, was während eines Haltens neben Ihrem Schreibtisch gesagt wird, landet in der Aufnahme oder im Transkript. Auf dem Anrufbildschirm gibt es einen **Halten**-Knopf, zwischen Stummschalten und Wähltastatur; ein Druck darauf pausiert den Anruf in beide Richtungen, sodass Sie die Gegenseite nicht hören und sie Sie nicht hört. + +WaveKat Voice teilt dem Telefonsystem der Gegenseite auf dem SIP-Standardweg mit, dass der Anruf gehalten wird, sodass die meisten Systeme ihre eigene Wartemusik vorspielen — der Anrufer hört „Sie werden gehalten", keine Totenstille. Das ist mehr als beidseitiges lokales Stummschalten: Das entfernte System weiß, dass der Anruf geparkt ist, nicht nur still. Mit **Fortsetzen** laufen Gespräch, Aufnahme und Transkript weiter. + +![WaveKat Voice auf Ubuntu — ein gehaltener Anruf: das Warteschleifen-Banner mit Fortsetzen, die Transkription pausiert.](/screenshots/in-call-hold/de.webp) + +## Anklopfen: einen zweiten Anruf annehmen, während Sie telefonieren + +Wenn ein zweiter Anruf klingelt, während Sie schon sprechen, müssen Sie sich nicht mehr entscheiden. Nehmen Sie ihn an, und der erste Anruf legt sich von selbst in die Warteschleife — genau wie das Anklopfen auf dem Mobiltelefon. Eine Umschaltleiste auf dem Anrufbildschirm listet jeden laufenden Anruf, und Sie wechseln per Klick zwischen ihnen. + +Nur ein Anruf ist jeweils live. Der Anruf, den Sie gerade ansehen, ist der, auf dem Sie sprechen; jeder andere Anruf wird gehalten, und seine Aufnahme und sein Live-Transkript pausieren, bis Sie zu ihm zurückwechseln. Standardmäßig wird ein gehaltener Anruf beim Umschalten sofort fortgesetzt; wer jeden Anruf lieber bewusst fortsetzt, findet in **Einstellungen → Allgemein** einen Schalter („Anruf beim Umschalten fortsetzen"), und jeder gehaltene Anruf trägt ein deutliches Banner, damit eine stille Leitung nie wie eine abgebrochene wirkt. + +![WaveKat Voice auf Ubuntu — ein laufender Anruf, während zwei weitere Anrufer in der Umschaltleiste in der Warteschleife warten.](/screenshots/in-call-waiting/de.webp) + +## Einen Anrufer weiterleiten — sofort oder nach Rückfrage + +Der **Weiterleiten**-Knopf schickt einen laufenden Anrufer zu jemand anderem — eine andere Nummer, eine andere Durchwahl, eine andere SIP-Adresse. Es gibt zwei Wege, und WaveKat Voice beherrscht beide: + +| | Ohne Rückfrage (Blind Transfer) | Mit Rückfrage (Attended Transfer) | +|---|---|---| +| **Was passiert** | Der Anrufer wird sofort zur neuen Nummer geschickt | Sie rufen die neue Person zuerst an, sprechen mit ihr und verbinden dann beide | +| **Sprechen Sie zuerst mit dem Empfänger?** | Nein | Ja — der Anrufer wartet in der Warteschleife, während Sie nachfragen | +| **Wenn der Empfänger nicht abnimmt** | Der Anrufer bleibt bei Ihnen; nichts geht verloren | Sie legen das Rückfrage-Gespräch auf und kehren zum Anrufer zurück | +| **Wann sinnvoll** | Sie wissen, dass die Person übernehmen soll: „Ich stelle Sie zur Buchhaltung durch" | Sie wollen den Anrufer ankündigen oder sind unsicher, ob jemand erreichbar ist | + +Für eine Weiterleitung ohne Rückfrage drücken Sie Weiterleiten, geben das Ziel ein — fertig; sobald die neue Person abnimmt, endet Ihre Seite des Anrufs. Für eine Weiterleitung mit Rückfrage wählen Sie **Erst sprechen**: Der Anrufer wird gehalten, WaveKat Voice ruft das Ziel als zweiten Anruf an, und Sie sprechen ungestört („Ich habe einen Kunden mit einer Frage zur Rechnung — können Sie übernehmen?"). Wenn alles passt, drücken Sie **Weiterleitung abschließen**, die beiden werden verbunden, und Sie steigen aus. Ist die Person beschäftigt, lehnt ab oder ist doch die falsche, legen Sie einfach das Rückfrage-Gespräch auf und setzen Ihren Anrufer fort — er erfährt nie, dass der erste Versuch nicht geklappt hat. + +![WaveKat Voice auf Ubuntu — eine Weiterleitung mit Rückfrage: der Anrufer gehalten, daneben der Knopf Weiterleitung abschließen.](/screenshots/in-call-transfer/de.webp) + +Auch in Ihrer Anrufliste bleiben Weiterleitungen ehrlich. Ein weitergeleiteter Anruf endet als **Weitergeleitet**, und die Detailseite zeigt genau, wohin er ging — „Weitergeleitet an …" — statt so zu tun, als hätten Sie aufgelegt. + +## Häufige Fragen + +### Wie leite ich in WaveKat Voice einen Anruf weiter? + +Drücken Sie auf dem Anrufbildschirm Weiterleiten und geben Sie eine Nummer, Durchwahl oder SIP-Adresse ein. Sofortiges Senden ist eine Weiterleitung ohne Rückfrage; **Erst sprechen** hält den Anrufer und ruft das Ziel an, damit Sie ihn ankündigen können — **Weiterleitung abschließen** verbindet dann beide. + +### Was ist der Unterschied zwischen einer Weiterleitung mit und ohne Rückfrage? + +Ohne Rückfrage (Blind Transfer) wird der Anrufer sofort zum neuen Ziel geschickt, ohne dass Sie mit dem Empfänger sprechen. Mit Rückfrage (Attended Transfer) bleibt der Anrufer in der Warteschleife, während Sie den Empfänger selbst anrufen, und erst nach Ihrer Bestätigung werden beide verbunden — Sie können also zurück, wenn der Empfänger beschäftigt ist oder ablehnt. WaveKat Voice unterstützt beides. + +### Braucht die Person, an die ich weiterleite, WaveKat Voice? + +Nein. WaveKat Voice nutzt den SIP-Standardmechanismus für Weiterleitungen (ein REFER, RFC 3515), das Ziel erhält also einen ganz gewöhnlichen Anruf — jedes Telefon, jedes Softphone, jede Durchwahl, die Ihr Anbieter erreicht. + +### Funktionieren Halten und Weiterleiten mit jedem SIP-Anbieter? + +Ja. Halten nutzt das SIP-Standard-re-INVITE (RFC 3264) und Weiterleiten das SIP-REFER (RFC 3515), sodass beide mit jedem SIP-konformen Anbieter oder jeder SIP-konformen Telefonanlage funktionieren — mit dem Konto, das Sie bereits haben, ohne anbieterspezifische Einrichtung. + +### Kann ich zwei Anrufe zu einer Telefonkonferenz zusammenführen? + +Noch nicht. WaveKat Voice kann zwei oder mehr Anrufe gleichzeitig halten und zwischen ihnen wechseln, aber nur einer ist jeweils live. Dreierkonferenzen sind eine eigene Funktion, die wir noch nicht gebaut haben. + +### Was hört ein Anrufer in der Warteschleife? + +Ein in WaveKat Voice gehaltener Anrufer hört das, was sein eigenes Telefonsystem für die Warteschleife abspielt — meist dessen Wartemusik, nicht Stille oder einen Ton von WaveKat Voice. WaveKat Voice signalisiert das Halten auf dem SIP-Standardweg (ein re-INVITE, RFC 3264) und überlässt so das Warteschleifen-Erlebnis dem eigenen System des Anrufers, sodass er hört, was er erwartet. + +### Wird ein Anruf aufgezeichnet, während er gehalten wird? + +Nein. Aufnahme und Live-Transkript pausieren für die Dauer des Haltens auf beiden Seiten und laufen mit dem Anruf weiter. Die Zeitleiste der gespeicherten Aufnahme bleibt korrekt — gehaltene Zeit erscheint als Stille, nicht als Schnitt. + +### Auf welchen Plattformen gibt es Halten, Anklopfen und Weiterleiten? + +WaveKat Voice läuft heute auf Mac und Linux; Windows folgt, wenn die Nachfrage da ist. Halten, Anklopfen und beide Arten der Weiterleitung funktionieren auf beiden unterstützten Plattformen, mit dem SIP-Konto, das Sie schon nutzen — ohne Aufpreis, ohne Einrichtung. + +## Probieren Sie es aus + +[Laden Sie WaveKat Voice herunter](/de/voice/download/) — oder aktualisieren Sie auf [0.0.42](/de/voice/changelog/#0.0.42) — und die Bedienelemente sind auf jedem Anrufbildschirm: Halten neben Stummschalten, Weiterleiten daneben, und Anklopfen, das einfach passiert, wenn der zweite Anruf klingelt. Nichts zu konfigurieren, nichts extra zu bezahlen. + +Legen Sie einen Anrufer in die Warteschleife, nehmen Sie die zweite Leitung an und stellen Sie jemanden durch, als gäbe es einen Empfang — denn jetzt gibt es einen. diff --git a/src/content/blog/es/hold-switch-and-transfer-calls.md b/src/content/blog/es/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..d34fb67 --- /dev/null +++ b/src/content/blog/es/hold-switch-and-transfer-calls.md @@ -0,0 +1,85 @@ +--- +title: "Retenga, alterne y transfiera llamadas como una recepción" +description: "WaveKat Voice ahora pone llamadas en espera, contesta una segunda llamada mientras atiende la primera y transfiere llamadas — de forma ciega o atendida — en Mac y Linux, y la grabación se pausa automáticamente durante la espera." +date: 2026-07-05 +author: Eason Guo +tags: [voz-ia, llamadas] +lang: "es" +--- + +WaveKat Voice — el softphone SIP para Mac y Linux que graba y transcribe cada llamada — ahora puede hacer las tres cosas que una recepción hace todo el día: poner a quien llama en espera, contestar una segunda llamada mientras la primera espera y transferir a quien llama a otra persona — ya sea de inmediato o después de consultarlo primero. Llega con WaveKat Voice [0.0.42](/es/voice/changelog/#0.0.42). + +Es el paso más literal hasta ahora hacia [dar a cada pequeño negocio la voz de uno grande](/es/blog/hello-world/). Cuando usted llama a una gran empresa, alguien dice «un momento, le comunico» — y funciona, porque hay una recepcionista con un conmutador. Ahora [WaveKat Voice](/es/voice/), que ya graba y transcribe cada llamada, le da a un negocio de una sola persona los mismos movimientos. Retener, la llamada en espera y la transferencia son los controles que quien atiende un escritorio usa constantemente, y cualquier [softphone](/es/voice/alternatives/) serio debe tenerlos — WaveKat Voice ya los tiene, con un matiz propio: lo que ocurre durante la espera queda fuera de la grabación. + +## Poner a quien llama en espera + +Poner a quien llama en espera en WaveKat Voice pausa la grabación y la transcripción en vivo durante todo el tiempo que la llamada quede aparcada — nada de lo que se diga cerca de su escritorio durante una espera termina en la grabación ni en la transcripción. Hay un botón de **Retener** en la pantalla de llamada, entre Silenciar y el teclado; al pulsarlo, la llamada se pausa en ambas direcciones, así que usted no oye a quien llama y ellos no lo oyen a usted. + +WaveKat Voice le indica al sistema telefónico del otro lado que la llamada está retenida por la vía estándar de SIP, así que la mayoría de los sistemas reproducen su propia música de espera — quien llama oye «está usted en espera», no un silencio muerto. Es más que un silenciado local: el sistema remoto sabe que la llamada está aparcada, no solo en silencio. Pulse **Reanudar** y la conversación, la grabación y la transcripción continúan. + +![WaveKat Voice en Ubuntu — una llamada retenida: el aviso de llamada en espera con Reanudar y la transcripción en pausa.](/screenshots/in-call-hold/es.webp) + +## Llamada en espera: conteste una segunda llamada durante la primera + +Cuando suena una segunda llamada mientras ya está hablando, ya no tiene que elegir entre las dos. Contéstela y la primera pasa a espera por sí sola — exactamente como la llamada en espera de un teléfono móvil. Una barra de cambio en la pantalla de llamada lista cada llamada en curso, y usted se mueve entre ellas con un clic. + +Solo una llamada está en vivo en cada momento. La llamada que está mirando es en la que está hablando; todas las demás están retenidas, con su grabación y su transcripción en vivo en pausa hasta que vuelva a ellas. De forma predeterminada, cambiar a una llamada retenida la reanuda de inmediato; si prefiere reanudar cada llamada deliberadamente, hay un interruptor en **Ajustes → General** («Reanudar una llamada al cambiar a ella»), y toda llamada retenida muestra un aviso claro para que una línea en silencio nunca parezca una línea caída. + +![WaveKat Voice en Ubuntu — una llamada en curso con dos personas más esperando retenidas en la barra de cambio.](/screenshots/in-call-waiting/es.webp) + +## Transferir a quien llama — de inmediato o consultando primero + +El botón **Transferir** envía a quien llama a otra persona — otro número, otra extensión, otra dirección SIP. Hay dos maneras de hacerlo, y WaveKat Voice tiene ambas: + +| | Transferencia ciega | Transferencia atendida | +|---|---|---| +| **Qué ocurre** | Quien llama es enviado al nuevo número de inmediato | Usted llama primero a la nueva persona, habla con ella y luego conecta a las dos | +| **¿Habla primero con el destinatario?** | No | Sí — quien llama espera retenido mientras usted consulta | +| **Si el destinatario no contesta** | Quien llama sigue con usted; no se pierde nada | Cuelga la llamada de consulta y vuelve con quien llamó | +| **Cuándo usarla** | Sabe que deben atenderla: «le comunico con facturación» | Quiere anunciar a quien llama, o no está seguro de que estén disponibles | + +Para una transferencia ciega, pulse Transferir, escriba el destino y listo — en cuanto la nueva persona contesta, su lado de la llamada termina. Para una atendida, elija **Hablar primero**: quien llama pasa a espera, WaveKat Voice marca el destino como una segunda llamada y usted habla en privado («tengo un cliente preguntando por la factura, ¿puede atenderlo?»). Cuando estén listos, pulse **Completar transferencia** y los dos quedan conectados mientras usted se retira. Si la persona está ocupada, rechaza o resulta no ser la indicada, simplemente cuelgue la llamada de consulta y reanude a quien llamó — nunca sabrá que el primer intento no funcionó. + +![WaveKat Voice en Ubuntu — una transferencia atendida: quien llama en espera y el botón Completar transferencia para conectarlos.](/screenshots/in-call-transfer/es.webp) + +Las transferencias también quedan registradas con honestidad en su historial. Una llamada transferida termina como **Transferida**, y la página de detalle muestra exactamente adónde fue — «Transferida a …» — en lugar de fingir que usted colgó. + +## Preguntas frecuentes + +### ¿Cómo transfiero una llamada en WaveKat Voice? + +Pulse Transferir en la pantalla de llamada e introduzca un número, extensión o dirección SIP. Enviarla de inmediato es una transferencia ciega; elegir **Hablar primero** retiene a quien llama y marca el destino para que usted pueda anunciarlo, y **Completar transferencia** conecta a los dos. + +### ¿Cuál es la diferencia entre una transferencia ciega y una atendida? + +La transferencia ciega envía a quien llama al nuevo destino de inmediato, sin hablar antes con el destinatario. La atendida retiene a quien llama mientras usted llama al destinatario, y solo conecta a los dos cuando usted confirma — así puede echarse atrás si el destinatario está ocupado o declina. WaveKat Voice admite ambas. + +### ¿La persona a la que transfiero necesita WaveKat Voice? + +No. WaveKat Voice usa el mecanismo estándar de transferencia de SIP (un REFER, RFC 3515), así que el destino solo recibe una llamada telefónica normal — cualquier teléfono, cualquier softphone, cualquier extensión que su proveedor pueda alcanzar. + +### ¿Funcionan la retención y la transferencia con cualquier proveedor SIP? + +Sí. La retención usa el re-INVITE estándar de SIP (RFC 3264) y la transferencia usa SIP REFER (RFC 3515), así que ambas funcionan con cualquier proveedor o centralita PBX compatible con SIP, usando la cuenta que usted ya tiene — sin configuración específica del proveedor. + +### ¿Puedo unir dos llamadas en una llamada de conferencia? + +Todavía no. WaveKat Voice puede retener dos o más llamadas a la vez y alternar entre ellas, pero solo una está en vivo en cada momento. La llamada a tres es una función aparte que aún no hemos construido. + +### ¿Qué oye quien llama mientras está en espera? + +Quien es puesto en espera en WaveKat Voice oye lo que su propio sistema telefónico reproduzca para la espera — normalmente su música de espera, no un silencio ni un tono de WaveKat Voice. WaveKat Voice señaliza la retención por la vía estándar de SIP (un re-INVITE, RFC 3264), lo que deja la experiencia de espera en manos del sistema de quien llama, así que oye lo que esperaría oír. + +### ¿Se graba una llamada mientras está en espera? + +No. La grabación y la transcripción en vivo se pausan mientras dura la espera, en ambos sentidos, y se reanudan con la llamada. La línea de tiempo de la grabación guardada sigue siendo exacta — el tiempo en espera aparece como silencio, no como un corte. + +### ¿Qué plataformas admiten retener, la llamada en espera y la transferencia? + +WaveKat Voice funciona hoy en Mac y Linux, y llegará a Windows cuando haya demanda. Retener, la llamada en espera y los dos tipos de transferencia funcionan en ambas plataformas compatibles, con la cuenta SIP que usted ya usa — sin costo adicional y sin configuración. + +## Pruébelo + +[Descargue WaveKat Voice](/es/voice/download/) — o actualice a [0.0.42](/es/voice/changelog/#0.0.42) — y los controles están en cada pantalla de llamada: Retener junto a Silenciar, Transferir al lado, y una llamada en espera que simplemente ocurre cuando suena la segunda llamada. Nada que configurar, nada extra que pagar. + +Ponga a quien llama en espera, atienda la segunda línea y comunique a alguien como si hubiera una recepción — porque ahora la hay. diff --git a/src/content/blog/fr/hold-switch-and-transfer-calls.md b/src/content/blog/fr/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..93ed983 --- /dev/null +++ b/src/content/blog/fr/hold-switch-and-transfer-calls.md @@ -0,0 +1,85 @@ +--- +title: "Mettre en attente, basculer et transférer des appels comme un standard" +description: "WaveKat Voice sait désormais mettre un appel en attente, répondre à un second appel pendant le premier et transférer un appelant — en aveugle ou avec supervision — sur Mac et Linux, et l'enregistrement se met en pause automatiquement pendant la mise en attente." +date: 2026-07-05 +author: Eason Guo +tags: [ia-vocale, appels] +lang: "fr" +--- + +WaveKat Voice — le softphone SIP pour Mac et Linux qui enregistre et transcrit chaque appel — sait désormais faire les trois choses qu'un accueil fait toute la journée : mettre un appelant en attente, répondre à un second appel pendant que le premier patiente, et transférer un appelant vers quelqu'un d'autre — soit directement, soit après l'avoir consulté. Elles arrivent avec WaveKat Voice [0.0.42](/fr/voice/changelog/#0.0.42). + +C'est le pas le plus littéral à ce jour vers notre objectif : [donner à chaque petite entreprise la voix d'une grande](/fr/blog/hello-world/). Quand vous appelez une grande entreprise, quelqu'un dit « un instant, je vous mets en relation » — et ça marche, parce qu'il y a une standardiste devant un standard. Désormais, [WaveKat Voice](/fr/voice/), qui enregistre et transcrit déjà chaque appel, donne les mêmes gestes à un commerce tenu par une seule personne. La mise en attente, le double appel et le transfert sont les commandes qu'une personne à l'accueil utilise sans cesse, et tout [softphone](/fr/voice/alternatives/) sérieux est censé les avoir — WaveKat Voice les a maintenant, avec sa touche à lui : ce qui se passe pendant l'attente reste hors de l'enregistrement. + +## Mettre un appelant en attente + +Mettre un appelant en attente dans WaveKat Voice met en pause l'enregistrement et la transcription en direct pendant toute la durée où l'appel patiente — rien de ce qui se dit près de votre bureau pendant une mise en attente ne finit dans l'enregistrement ni dans la transcription. Un bouton **Attente** figure sur l'écran d'appel, entre Muet et le clavier ; appuyez dessus et l'appel se met en pause dans les deux sens : vous n'entendez plus l'appelant et il ne vous entend plus. + +WaveKat Voice signale la mise en attente au système téléphonique d'en face à la manière standard de SIP, si bien que la plupart des systèmes diffusent leur propre musique d'attente — l'appelant entend « vous êtes en attente », pas un silence de mort. C'est plus qu'une simple coupure du son en local : le système distant sait que l'appel est en attente, et pas seulement silencieux. Appuyez sur **Reprendre** et la conversation, l'enregistrement et la transcription repartent. + +![WaveKat Voice sur Ubuntu — un appel en attente : la bannière de mise en attente avec Reprendre, la transcription en pause.](/screenshots/in-call-hold/fr.webp) + +## Double appel : répondre à un second appel pendant le premier + +Quand un second appel sonne alors que vous êtes déjà en ligne, vous n'avez plus à choisir entre les deux. Répondez-y, et le premier appel se met en attente tout seul — exactement comme le double appel sur un téléphone mobile. Une barre de bascule sur l'écran d'appel liste chaque appel en cours, et vous passez de l'un à l'autre d'un clic. + +Un seul appel a de l'audio en direct à la fois. L'appel que vous regardez est celui sur lequel vous parlez ; tous les autres sont en attente, avec leur enregistrement et leur transcription en direct en pause jusqu'à ce que vous y reveniez. Par défaut, basculer vers un appel en attente le reprend immédiatement ; si vous préférez reprendre chaque appel délibérément, un réglage existe dans **Réglages → Général** (« Reprendre un appel quand vous basculez dessus »), et tout appel en attente porte une bannière bien visible, pour qu'une ligne silencieuse ne passe jamais pour une ligne coupée. + +![WaveKat Voice sur Ubuntu — un appel en cours, avec deux autres appelants en attente dans la barre de bascule.](/screenshots/in-call-waiting/fr.webp) + +## Transférer un appelant — directement, ou après vérification + +Le bouton **Transférer** envoie un appelant en ligne vers quelqu'un d'autre — un autre numéro, un autre poste, une autre adresse SIP. Il y a deux façons de faire, et WaveKat Voice propose les deux : + +| | Transfert aveugle | Transfert supervisé | +|---|---|---| +| **Ce qui se passe** | L'appelant est envoyé immédiatement vers le nouveau numéro | Vous appelez d'abord la nouvelle personne, lui parlez, puis connectez les deux | +| **Parlez-vous d'abord au destinataire ?** | Non | Oui — l'appelant patiente en attente pendant que vous vérifiez | +| **Si le destinataire ne décroche pas** | L'appelant reste avec vous ; rien n'est perdu | Vous raccrochez l'appel de consultation et revenez à l'appelant | +| **Quand l'utiliser** | Vous savez que c'est pour lui : « je vous passe la facturation » | Vous voulez annoncer l'appelant, ou n'êtes pas sûr qu'il soit disponible | + +Pour un transfert aveugle, appuyez sur Transférer, saisissez la destination, et c'est terminé — dès que la nouvelle personne décroche, votre côté de l'appel prend fin. Pour un transfert supervisé, choisissez **Parler d'abord** : l'appelant passe en attente, WaveKat Voice compose la destination comme un second appel, et vous lui parlez en privé (« j'ai un client qui a une question sur la facture — vous pouvez le prendre ? »). Quand tout est prêt, appuyez sur **Finaliser le transfert** : les deux sont connectés et vous vous retirez. Si la personne est occupée, refuse, ou n'est finalement pas la bonne, raccrochez simplement l'appel de consultation et reprenez votre appelant — il ne saura jamais que la première tentative n'a pas abouti. + +![WaveKat Voice sur Ubuntu — un transfert supervisé : l'appelant en attente et le bouton Finaliser le transfert pour les connecter.](/screenshots/in-call-transfer/fr.webp) + +Les transferts sont aussi consignés honnêtement dans votre historique. Un appel transféré se termine en **Transféré**, et sa page de détail montre exactement où il est parti — « Transféré vers … » — au lieu de faire comme si vous aviez raccroché. + +## Questions fréquentes + +### Comment transférer un appel dans WaveKat Voice ? + +Appuyez sur Transférer sur l'écran d'appel et saisissez un numéro, un poste ou une adresse SIP. L'envoyer directement est un transfert aveugle ; choisir **Parler d'abord** met l'appelant en attente et compose la destination pour que vous puissiez l'annoncer, puis **Finaliser le transfert** connecte les deux. + +### Quelle est la différence entre un transfert aveugle et un transfert supervisé ? + +Un transfert aveugle envoie l'appelant vers la nouvelle destination immédiatement, sans parler d'abord au destinataire. Un transfert supervisé met l'appelant en attente pendant que vous appelez vous-même le destinataire, et ne connecte les deux qu'une fois que vous confirmez — vous pouvez donc faire marche arrière si le destinataire est occupé ou refuse. WaveKat Voice prend en charge les deux. + +### La personne à qui je transfère l'appel a-t-elle besoin de WaveKat Voice ? + +Non. WaveKat Voice utilise le mécanisme de transfert standard de SIP (un REFER, RFC 3515) : la destination reçoit simplement un appel téléphonique ordinaire — n'importe quel téléphone, n'importe quel softphone, n'importe quel poste que votre opérateur peut joindre. + +### L'attente et le transfert fonctionnent-ils avec n'importe quel opérateur SIP ? + +Oui. La mise en attente utilise le re-INVITE standard de SIP (RFC 3264) et le transfert utilise le REFER de SIP (RFC 3515), si bien que les deux fonctionnent avec n'importe quel opérateur ou PBX conforme à SIP, avec le compte que vous avez déjà — sans configuration propre à l'opérateur. + +### Puis-je fusionner deux appels en conférence téléphonique ? + +Pas encore. WaveKat Voice peut garder deux appels ou plus en attente et basculer entre eux, mais un seul est en direct à la fois. La conférence à trois est une fonction à part que nous n'avons pas encore construite. + +### Qu'entend un appelant pendant qu'il est en attente ? + +Un appelant mis en attente dans WaveKat Voice entend ce que son propre système téléphonique diffuse pour l'attente — le plus souvent sa musique d'attente, pas un silence ni une tonalité venant de WaveKat Voice. WaveKat Voice signale la mise en attente à la manière standard de SIP (un re-INVITE, RFC 3264), ce qui confie l'expérience d'attente au système de l'appelant lui-même, si bien qu'il entend ce à quoi il s'attend. + +### Un appel est-il enregistré pendant qu'il est en attente ? + +Non. L'enregistrement et la transcription en direct se mettent en pause pendant toute la durée de l'attente, dans les deux sens, et reprennent avec l'appel. La chronologie de l'enregistrement sauvegardé reste exacte — le temps d'attente apparaît comme du silence, pas comme une coupure. + +### Quelles plateformes prennent en charge l'attente, le double appel et le transfert ? + +WaveKat Voice fonctionne aujourd'hui sur Mac et Linux ; Windows viendra quand la demande sera là. L'attente, le double appel et les deux types de transfert fonctionnent sur les deux plateformes prises en charge, avec le compte SIP que vous utilisez déjà — sans surcoût, sans configuration. + +## Essayez + +[Téléchargez WaveKat Voice](/fr/voice/download/) — ou mettez à jour vers la [0.0.42](/fr/voice/changelog/#0.0.42) — et les commandes sont sur chaque écran d'appel : Attente à côté de Muet, Transférer juste à côté, et un double appel qui se déclenche tout seul quand le second appel sonne. Rien à configurer, rien de plus à payer. + +Mettez un appelant en attente, prenez la seconde ligne et passez quelqu'un comme s'il y avait un accueil — parce que maintenant, il y en a un. diff --git a/src/content/blog/hold-switch-and-transfer-calls.md b/src/content/blog/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..71aab05 --- /dev/null +++ b/src/content/blog/hold-switch-and-transfer-calls.md @@ -0,0 +1,84 @@ +--- +title: "Hold, Switch, and Transfer Calls Like a Front Desk" +description: "WaveKat Voice now puts callers on hold, answers a second call, and transfers them — blind or attended — on Mac and Linux. Recording pauses automatically on hold." +date: 2026-07-05 +author: Eason Guo +tags: [voice-ai, calls] +--- + +WaveKat Voice — the SIP softphone for Mac and Linux that records and transcribes every call — can now do the three things a front desk does all day: put a caller on hold, answer a second call while the first one waits, and transfer a caller to someone else, either straight away or after checking with them first. It lands in [0.0.42](/voice/changelog/#0.0.42). + +This is the most literal step yet toward [giving every small business the voice of a big one](/blog/hello-world/). When you call a big company, someone says "one moment, let me put you through" — and it works, because there's a receptionist with a switchboard. Now [WaveKat Voice](/voice/), which already records and transcribes every call, gives a one-person shop the same moves. Hold, call waiting, and transfer are the controls a desk worker reaches for constantly, and any serious [softphone](/voice/alternatives/) is expected to have them — WaveKat Voice now does, with its own twist: what happens on hold stays out of the recording. + +## Put a caller on hold + +Putting a caller on hold in WaveKat Voice pauses the recording and the live transcript for as long as the call is parked — nothing said near your desk during a hold ends up in the recording or the transcript. There's a **Hold** button on the call screen, between Mute and the keypad; press it and the call pauses in both directions, so you can't hear the caller and they can't hear you. + +WaveKat Voice signals the hold to the other side's phone system the standard SIP way, so most systems play their own hold music to the caller — they hear "you're on hold", not dead air. That's more than a local mute: the remote system knows the call is parked, not just quiet. Press **Resume** and the conversation, the recording, and the transcript pick back up. + +![WaveKat Voice on Ubuntu — a call on hold: the on-hold banner with Resume, and transcription paused.](/screenshots/in-call-hold/en.webp) + +## Call waiting: answer a second call while you're on one + +When a second call rings while you're already talking, you no longer have to choose between them. Answer it, and the first call goes on hold by itself — exactly like call waiting on a mobile phone. A switcher bar on the call screen lists every call in progress, and you move between them with a click. + +Only one call is live at a time. The call you're looking at is the one you're talking on; every other call is on hold, with its recording and live transcript paused until you switch back to it. By default, switching to a held call resumes it immediately; if you'd rather resume each call deliberately, there's a toggle in **Settings → General** ("Resume a call when you switch to it"), and a clear banner on any held call so a silent line never reads as a dropped one. + +![WaveKat Voice on Ubuntu — a live call with two more callers waiting on hold in the call switcher.](/screenshots/in-call-waiting/en.webp) + +## Transfer a caller — straight away, or after checking + +The **Transfer** button sends a live caller to someone else — another number, another extension, another SIP address. There are two ways to do it, and WaveKat Voice has both: + +| | Blind transfer | Attended transfer | +|---|---|---| +| **What happens** | The caller is sent to the new number immediately | You call the new person first, talk to them, then connect the two | +| **Do you talk to the recipient first?** | No | Yes — the caller waits on hold while you check | +| **If the recipient doesn't pick up** | The caller stays with you; nothing is lost | You hang up the consult call and go back to the caller | +| **When to use it** | You know they should take it: "putting you through to billing" | You want to announce the caller, or aren't sure they're available | + +For a blind transfer, press Transfer, enter the destination, and you're done — once the new person answers, your side of the call ends. For an attended transfer, choose **Talk first**: the caller goes on hold, WaveKat Voice dials the destination as a second call, and you talk to them privately ("I've got a customer asking about the invoice — can you take it?"). When they're ready, press **Complete transfer** and the two are connected while you drop out. If they're busy, decline, or turn out to be the wrong person, just hang up the consult call and resume your caller — they never know the first attempt didn't work out. + +![WaveKat Voice on Ubuntu — an attended transfer: the caller on hold and a Complete transfer button to connect them.](/screenshots/in-call-transfer/en.webp) + +Transfers are recorded honestly in your history, too. A transferred call ends as **Transferred**, and the call's detail page shows exactly where it went — "Transferred to …" — instead of pretending you hung up. + +## Frequently asked questions + +### How do I transfer a call in WaveKat Voice? + +Press Transfer on the call screen and enter a number, extension, or SIP address. Sending it right away is a blind transfer; choosing **Talk first** holds the caller and dials the destination so you can announce them, then **Complete transfer** connects the two. + +### What is the difference between a blind and an attended transfer? + +A blind transfer sends the caller to the new destination immediately, without talking to the recipient first. An attended transfer holds the caller while you call the recipient yourself, and only connects the two once you confirm — so you can back out if the recipient is busy or declines. WaveKat Voice supports both. + +### Does the person I transfer a call to need WaveKat Voice? + +No. WaveKat Voice uses the standard SIP transfer mechanism (a REFER, RFC 3515), so the destination just receives an ordinary phone call — any phone, any softphone, any extension your provider can reach. + +### Does hold and transfer work with any SIP provider? + +Yes. Hold uses the standard SIP re-INVITE (RFC 3264) and transfer uses SIP REFER (RFC 3515), so both work with any SIP-compliant provider or PBX, using the account you already have — no provider-specific setup. + +### Can I merge two calls into a conference call? + +Not yet. WaveKat Voice can hold two or more calls at once and switch between them, but only one is live at a time. Three-way calling is a separate feature we haven't built. + +### What does a caller hear while on hold? + +A caller placed on hold in WaveKat Voice hears whatever their own phone system plays for hold — usually its hold music, not silence or a tone from WaveKat Voice. WaveKat Voice signals the hold the standard SIP way (a re-INVITE, RFC 3264), which hands the hold experience to the caller's own system, so they hear what they'd expect. + +### Is a call recorded while it's on hold? + +No. The recording and the live transcript pause for the duration of the hold, on both sides, and resume with the call. The saved recording's timeline stays accurate — held time appears as silence, not as a cut. + +### Which platforms support hold, call waiting, and transfer? + +WaveKat Voice runs on Mac and Linux today, with Windows coming when there's demand. Hold, call waiting, and both kinds of transfer work on both supported platforms, with the SIP account you already use — no extra cost, no setup. + +## Try it + +[Download WaveKat Voice](/voice/download/) — or update to [0.0.42](/voice/changelog/#0.0.42) — and the controls are on every call screen: Hold next to Mute, Transfer beside it, and call waiting that just happens when the second call rings. Nothing to configure, nothing extra to pay for. + +Put a caller on hold, take the second line, and put someone through like there's a front desk — because now there is. diff --git a/src/content/blog/it/hold-switch-and-transfer-calls.md b/src/content/blog/it/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..0977b07 --- /dev/null +++ b/src/content/blog/it/hold-switch-and-transfer-calls.md @@ -0,0 +1,85 @@ +--- +title: "Metti in attesa, passa tra le chiamate e trasferisci come una reception" +description: "WaveKat Voice ora mette le chiamate in attesa, risponde a una seconda chiamata mentre sei sulla prima e trasferisce chi chiama — trasferimento cieco o assistito — su Mac e Linux, e la registrazione si mette in pausa automaticamente durante l'attesa." +date: 2026-07-05 +author: Eason Guo +tags: [voice-ai, chiamate] +lang: "it" +--- + +WaveKat Voice — il softphone SIP per Mac e Linux che registra e trascrive ogni chiamata — ora sa fare le tre cose che una reception fa tutto il giorno: mettere in attesa chi chiama, rispondere a una seconda chiamata mentre la prima aspetta e trasferire chi chiama a qualcun altro — subito, oppure dopo averlo prima consultato. Arriva con WaveKat Voice [0.0.42](/it/voice/changelog/#0.0.42). + +È il passo più letterale finora verso il nostro obiettivo: [dare a ogni piccola attività la voce di una grande](/it/blog/hello-world/). Quando chiami una grande azienda, qualcuno dice «un attimo, la metto in linea» — e funziona, perché c'è una centralinista con un centralino. Ora [WaveKat Voice](/it/voice/), che già registra e trascrive ogni chiamata, dà a un negozio con una sola persona le stesse mosse. Attesa, avviso di chiamata e trasferimento sono i comandi che chi sta a una scrivania usa di continuo, e qualsiasi [softphone](/it/voice/alternatives/) serio deve averli — WaveKat Voice ora li ha, con un tocco tutto suo: quello che succede durante l'attesa resta fuori dalla registrazione. + +## Mettere in attesa chi chiama + +Mettere in attesa chi chiama in WaveKat Voice mette in pausa la registrazione e la trascrizione dal vivo per tutto il tempo in cui la chiamata resta parcheggiata — nulla di ciò che viene detto vicino alla tua scrivania durante l'attesa finisce nella registrazione o nella trascrizione. Sulla schermata di chiamata c'è un pulsante **Attesa**, tra Muto e il tastierino; premilo e la chiamata si mette in pausa in entrambe le direzioni, così tu non senti chi chiama e loro non sentono te. + +WaveKat Voice segnala l'attesa al sistema telefonico dall'altra parte nel modo standard di SIP, così la maggior parte dei sistemi fa sentire a chi chiama la propria musica di attesa — sente «sei in attesa», non un silenzio di tomba. È più di un semplice muto locale: il sistema remoto sa che la chiamata è parcheggiata, non solo silenziosa. Premi **Riprendi** e la conversazione, la registrazione e la trascrizione ripartono. + +![WaveKat Voice su Ubuntu — una chiamata in attesa: il banner di attesa con Riprendi e la trascrizione in pausa.](/screenshots/in-call-hold/it.webp) + +## Avviso di chiamata: rispondi a una seconda chiamata mentre sei sulla prima + +Quando una seconda chiamata squilla mentre stai già parlando, non devi più scegliere tra le due. Rispondi, e la prima chiamata va in attesa da sola — esattamente come l'avviso di chiamata sul cellulare. Una barra di scambio sulla schermata di chiamata elenca ogni chiamata in corso, e passi dall'una all'altra con un clic. + +Solo una chiamata alla volta ha l'audio dal vivo. La chiamata che stai guardando è quella su cui stai parlando; ogni altra chiamata è in attesa, con la sua registrazione e la sua trascrizione dal vivo in pausa finché non ci torni sopra. Per impostazione predefinita, passare a una chiamata in attesa la riprende subito; se preferisci riprendere ogni chiamata di proposito, c'è un'opzione in **Impostazioni → Generali** («Riprendi una chiamata quando ci passi»), e ogni chiamata in attesa mostra un avviso ben visibile, così una linea silenziosa non sembra mai una linea caduta. + +![WaveKat Voice su Ubuntu — una chiamata in corso con altri due chiamanti in attesa nella barra di scambio.](/screenshots/in-call-waiting/it.webp) + +## Trasferire chi chiama — subito, o dopo aver verificato + +Il pulsante **Trasferisci** manda chi è in linea da qualcun altro — un altro numero, un altro interno, un altro indirizzo SIP. Ci sono due modi per farlo, e WaveKat Voice li ha entrambi: + +| | Trasferimento cieco | Trasferimento assistito | +|---|---|---| +| **Cosa succede** | Chi chiama viene inviato subito al nuovo numero | Prima chiami tu la nuova persona, le parli, poi colleghi i due | +| **Parli prima con il destinatario?** | No | Sì — chi chiama aspetta in attesa mentre verifichi | +| **Se il destinatario non risponde** | Chi chiama resta con te; non si perde nulla | Riagganci la chiamata di consultazione e torni da chi chiamava | +| **Quando usarlo** | Sai che deve prenderla lui: «la passo alla fatturazione» | Vuoi annunciare chi chiama, o non sei sicuro che sia disponibile | + +Per un trasferimento cieco, premi Trasferisci, inserisci la destinazione e hai finito — appena la nuova persona risponde, il tuo lato della chiamata termina. Per un trasferimento assistito, scegli **Parla prima**: chi chiama va in attesa, WaveKat Voice compone la destinazione come seconda chiamata e tu le parli in privato («ho un cliente che chiede della fattura — puoi prenderlo tu?»). Quando è tutto pronto, premi **Completa trasferimento** e i due vengono collegati mentre tu esci. Se la persona è occupata, rifiuta o si rivela quella sbagliata, ti basta riagganciare la chiamata di consultazione e riprendere chi chiamava — non saprà mai che il primo tentativo non è andato a buon fine. + +![WaveKat Voice su Ubuntu — un trasferimento assistito: chi chiama è in attesa e il pulsante Completa trasferimento li collega.](/screenshots/in-call-transfer/it.webp) + +Anche nella cronologia i trasferimenti restano onesti. Una chiamata trasferita si chiude come **Trasferita**, e la pagina di dettaglio mostra esattamente dov'è andata — «Trasferita a …» — invece di fingere che tu abbia riagganciato. + +## Domande frequenti + +### Come trasferisco una chiamata in WaveKat Voice? + +Premi Trasferisci sulla schermata di chiamata e inserisci un numero, un interno o un indirizzo SIP. Inviarla subito è un trasferimento cieco; scegliendo **Parla prima** chi chiama viene messo in attesa e viene composta la destinazione, così puoi annunciarlo, poi **Completa trasferimento** collega i due. + +### Qual è la differenza tra trasferimento cieco e assistito? + +Il trasferimento cieco manda chi chiama alla nuova destinazione subito, senza parlare prima con il destinatario. Quello assistito tiene chi chiama in attesa mentre chiami tu stesso il destinatario, e collega i due solo quando confermi — così puoi tirarti indietro se il destinatario è occupato o rifiuta. WaveKat Voice li supporta entrambi. + +### La persona a cui trasferisco la chiamata deve avere WaveKat Voice? + +No. WaveKat Voice usa il meccanismo di trasferimento standard di SIP (un REFER, RFC 3515), quindi la destinazione riceve solo una normale telefonata — qualsiasi telefono, qualsiasi softphone, qualsiasi interno che il tuo operatore possa raggiungere. + +### Attesa e trasferimento funzionano con qualsiasi operatore SIP? + +Sì. L'attesa usa il re-INVITE standard di SIP (RFC 3264) e il trasferimento usa SIP REFER (RFC 3515), quindi entrambi funzionano con qualsiasi operatore o centralino conforme a SIP, usando l'account che già hai — senza configurazione specifica dell'operatore. + +### Posso unire due chiamate in una conferenza? + +Non ancora. WaveKat Voice può tenere due o più chiamate in attesa contemporaneamente e passare dall'una all'altra, ma solo una alla volta è dal vivo. La chiamata a tre è una funzione a parte che non abbiamo ancora costruito. + +### Cosa sente chi chiama mentre è in attesa? + +Chi viene messo in attesa in WaveKat Voice sente quello che il suo sistema telefonico riproduce per l'attesa — di solito la sua musica di attesa, non silenzio o un tono da WaveKat Voice. WaveKat Voice segnala l'attesa nel modo standard di SIP (un re-INVITE, RFC 3264), che affida l'esperienza di attesa al sistema di chi chiama, così sente ciò che si aspetta. + +### Una chiamata viene registrata mentre è in attesa? + +No. La registrazione e la trascrizione dal vivo si fermano per tutta la durata dell'attesa, in entrambe le direzioni, e riprendono con la chiamata. La linea temporale della registrazione salvata resta accurata — il tempo in attesa appare come silenzio, non come un taglio. + +### Su quali piattaforme funzionano attesa, avviso di chiamata e trasferimento? + +WaveKat Voice oggi funziona su Mac e Linux, e arriverà su Windows quando ci sarà richiesta. Attesa, avviso di chiamata ed entrambi i tipi di trasferimento funzionano su entrambe le piattaforme supportate, con l'account SIP che già usi — senza costi extra e senza configurazione. + +## Provalo + +[Scarica WaveKat Voice](/it/voice/download/) — o aggiorna alla [0.0.42](/it/voice/changelog/#0.0.42) — e i comandi sono su ogni schermata di chiamata: Attesa accanto a Muto, Trasferisci lì di fianco, e un avviso di chiamata che scatta da solo quando squilla la seconda chiamata. Niente da configurare, niente di più da pagare. + +Metti in attesa chi chiama, prendi la seconda linea e passa qualcuno come se ci fosse una reception — perché adesso c'è. diff --git a/src/content/blog/ja/hold-switch-and-transfer-calls.md b/src/content/blog/ja/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..e044786 --- /dev/null +++ b/src/content/blog/ja/hold-switch-and-transfer-calls.md @@ -0,0 +1,85 @@ +--- +title: "受付のように通話を保留・切り替え・転送する" +description: "WaveKat Voice が通話の保留、通話中の 2 本目の着信への応答、そしてブラインド転送・取り次ぎ転送による通話の転送に対応。保留中は録音が自動的に一時停止し、Mac と Linux で使えます。" +date: 2026-07-05 +author: Eason Guo +tags: [音声AI, 通話] +lang: "ja" +--- + +WaveKat Voice——通話をすべて録音・文字起こしする Mac・Linux 向けの SIP ソフトフォン——が、受付係が一日中こなしている 3 つのことをできるようになりました。通話を保留にする、最初の通話を待たせたまま 2 本目の着信に出る、そして通話を別の人へ転送する — すぐに転送することも、先に相手と話して確認してからつなぐこともできます。この機能は WaveKat Voice [0.0.42](/ja/voice/changelog/#0.0.42) で提供されます。 + +これは、[すべての小規模ビジネスに大企業のような声を](/ja/blog/hello-world/)という目標に向けた、これまでで最も文字どおりの一歩です。大きな会社に電話をかけると、「少々お待ちください、おつなぎします」と言われ、実際につながります。受付係と電話交換機があるからです。いまや、[WaveKat Voice](/ja/voice/)——すでにすべての通話を録音し文字起こしするアプリ——が、ひとりで営むお店にも同じ動きを与えます。保留、キャッチホン、転送は、電話番の人が絶えず手を伸ばす操作であり、まともな[ソフトフォン](/ja/voice/alternatives/)なら備えていて当然の機能です。WaveKat Voice はそれらを備えたうえで、独自のこだわりをひとつ加えました。保留中に起きたことは、録音に残りません。 + +## 通話を保留にする + +WaveKat Voice で発信者を保留にすると、通話が保留されている間ずっと録音とリアルタイムの文字起こしが一時停止します — 保留中にデスクのそばで話したことが、録音や文字起こしに残ることはありません。通話画面のミュートとキーパッドの間には**保留**ボタンがあり、押すと通話は双方向で一時停止します。あなたには相手が聞こえず、相手にもあなたが聞こえません。 + +WaveKat Voice は(SIP の標準的な方法で)相手側の電話システムに通話が保留中であることを伝えるので、多くのシステムは発信者に自前の保留音を流します。相手に聞こえるのは「保留中です」であって、無音ではありません。これは、両端をローカルでミュートするだけの機能ではありません。相手側のシステムは、通話がただ静かになっているのではなく、保留されていることを認識しています。**再開**を押せば、会話も録音も文字起こしも再び動き出します。 + +![Ubuntu 上の WaveKat Voice — 保留中の通話:保留バナーと再開ボタンが表示され、文字起こしは一時停止。](/screenshots/in-call-hold/ja.webp) + +## キャッチホン:通話中に 2 本目の着信に出る + +すでに話している最中に 2 本目の電話が鳴っても、もうどちらかを選ぶ必要はありません。応答すると、最初の通話はひとりでに保留になります — 携帯電話のキャッチホンとまったく同じです。通話画面のスイッチャーバーに進行中のすべての通話が並び、クリックひとつで行き来できます。 + +ライブの音声を持つ通話は常に 1 本だけです。いま見ている通話が、いま話している通話です。ほかの通話はすべて保留になり、その録音とリアルタイムの文字起こしは、あなたがその通話に切り替えるまで一時停止します。既定では、保留中の通話に切り替えるとすぐに再開されます。1 本ずつ意図的に再開したい場合は、**設定 → 一般**にトグルがあります(「切り替えた通話を再開する」)。保留中の通話にははっきりしたバナーが表示されるので、静かな回線が切れた回線に見えることはありません。 + +![Ubuntu 上の WaveKat Voice — 通話中の画面。スイッチャーにはさらに 2 件の通話が保留で待機。](/screenshots/in-call-waiting/ja.webp) + +## 通話を転送する — すぐに、または確認してから + +**転送**ボタンは、通話中の相手を別の誰かへ送ります — 別の番号、別の内線、別の SIP アドレスへ。やり方は 2 つあり、WaveKat Voice はどちらにも対応しています。 + +| | ブラインド転送 | 取り次ぎ転送 | +|---|---|---| +| **何が起こるか** | 発信者はすぐに新しい番号へ送られる | まず自分が相手に電話して話し、それから 2 人をつなぐ | +| **転送先と先に話すか?** | いいえ | はい — 確認する間、発信者は保留で待つ | +| **転送先が出なかったら** | 発信者はあなたのもとに残り、何も失われない | 取り次ぎの通話を切って発信者のところへ戻る | +| **使いどころ** | 相手が受けるべきだと分かっている:「経理におつなぎします」 | 発信者を先に紹介したい、または相手が空いているか不確かなとき | + +ブラインド転送は、転送を押して宛先を入力するだけで完了します。新しい相手が応答した時点で、あなた側の通話は終わります。取り次ぎ転送では**先に話す**を選びます。発信者は保留になり、WaveKat Voice が 2 本目の通話として宛先に発信するので、相手とだけ話せます(「請求書の件でお客様からお電話です — 対応できますか?」)。準備ができたら**転送を完了**を押すと 2 人がつながり、あなたは通話から抜けます。相手が忙しい、出ない、あるいは実は別の人だった場合は、取り次ぎの通話を切って発信者を再開するだけです。最初の試みがうまくいかなかったことを、発信者が知ることはありません。 + +![Ubuntu 上の WaveKat Voice — 取り次ぎ転送の途中:発信者は保留中で、「転送を完了」ボタンで 2 人をつなげる。](/screenshots/in-call-transfer/ja.webp) + +転送は履歴にも正直に記録されます。転送された通話は**転送済み**として終了し、通話の詳細ページにはどこへ送られたかが正確に表示されます —「… へ転送」— あなたが切ったことにはなりません。 + +## よくある質問 + +### WaveKat Voice で通話を転送するには? + +通話画面で転送を押し、番号・内線・SIP アドレスを入力します。そのまま送ればブラインド転送。**先に話す**を選ぶと、発信者を保留にして宛先へ発信するので、相手に取り次いでから**転送を完了**で 2 人をつなげます。 + +### ブラインド転送と取り次ぎ転送の違いは? + +ブラインド転送は、転送先と話すことなく、発信者をすぐに新しい宛先へ送ります。取り次ぎ転送は、発信者を保留にしたまま自分で転送先に電話をかけ、確認が取れてから 2 人をつなぎます。転送先が忙しければ引き返せます。WaveKat Voice は両方に対応しています。 + +### 転送先の相手にも WaveKat Voice が必要ですか? + +いいえ。WaveKat Voice は SIP 標準の転送メカニズム(RFC 3515 の REFER)を使うので、転送先にはごく普通の電話がかかるだけです。どんな電話機でも、どんなソフトフォンでも、プロバイダーがつなげる内線ならどこでも構いません。 + +### 保留と転送は、どの SIP プロバイダーでも使えますか? + +はい。保留は SIP 標準の re-INVITE(RFC 3264)、転送は SIP の REFER(RFC 3515)を使うので、どちらも SIP に準拠したプロバイダーや PBX なら、いまお使いのアカウントのまま動作します — プロバイダーごとの特別な設定は必要ありません。 + +### 2 本の通話を電話会議にまとめられますか? + +まだできません。WaveKat Voice は 2 本以上の通話を同時に保留して切り替えられますが、ライブなのは常に 1 本だけです。三者通話は別の機能で、まだ作っていません。 + +### 保留中、発信者には何が聞こえますか? + +WaveKat Voice で保留にされた発信者には、その発信者自身の電話システムが保留用に流すものが聞こえます — たいていはその保留音であって、WaveKat Voice からの無音やトーンではありません。WaveKat Voice は SIP の標準的な方法(RFC 3264 の re-INVITE)で保留を伝え、保留中の体験を発信者自身のシステムに委ねます。だから発信者には、いつもどおりに期待するものが聞こえるのです。 + +### 保留中の通話は録音されますか? + +いいえ。録音とリアルタイムの文字起こしは、保留の間、双方向で一時停止し、通話とともに再開します。保存された録音のタイムラインは正確なままです — 保留の時間はカットではなく無音として残ります。 + +### 保留・キャッチホン・転送はどのプラットフォームで使えますか? + +WaveKat Voice は現在 Mac と Linux で動作し、Windows は需要に応じて対応予定です。保留、キャッチホン、2 種類の転送は、いまお使いの SIP アカウントのまま、対応する両プラットフォームで使えます — 追加費用も設定も不要です。 + +## 試してみる + +[WaveKat Voice をダウンロード](/ja/voice/download/)するか、[0.0.42](/ja/voice/changelog/#0.0.42) に更新してください。コントロールはすべての通話画面にあります。保留はミュートの隣、転送はそのそば、そしてキャッチホンは 2 本目の着信が鳴れば自動的に働きます。設定するものも、追加で支払うものもありません。 + +通話を保留にして、2 本目の回線に出て、受付がいるかのように電話を取り次ぐ — なぜなら、いまはもう、いるのですから。 diff --git a/src/content/blog/ko/hold-switch-and-transfer-calls.md b/src/content/blog/ko/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..fb716c8 --- /dev/null +++ b/src/content/blog/ko/hold-switch-and-transfer-calls.md @@ -0,0 +1,85 @@ +--- +title: "안내 데스크처럼 통화를 보류하고, 전환하고, 돌려주세요" +description: "WaveKat Voice가 이제 통화 보류, 통화 중 두 번째 전화 받기, 그리고 블라인드·협의 방식의 호전환을 지원합니다 — Mac과 Linux에서. 보류 중에는 녹음이 자동으로 일시 정지됩니다." +date: 2026-07-05 +author: Eason Guo +tags: [음성AI, 통화] +lang: "ko" +--- + +WaveKat Voice——모든 통화를 녹음하고 받아 적는 Mac·Linux용 SIP 소프트폰——가 이제 안내 데스크가 하루 종일 하는 세 가지 일을 할 수 있습니다. 전화를 보류하고, 첫 번째 통화가 기다리는 동안 두 번째 전화를 받고, 전화를 다른 사람에게 돌려줍니다 — 바로 넘길 수도 있고, 먼저 상대와 이야기해 확인한 뒤 넘길 수도 있습니다. 이 기능은 WaveKat Voice [0.0.42](/ko/voice/changelog/#0.0.42)에서 제공됩니다. + +이것은 [모든 작은 비즈니스에 큰 기업의 목소리를](/ko/blog/hello-world/) 주겠다는 목표를 향한, 지금까지 중 가장 문자 그대로의 한 걸음입니다. 큰 회사에 전화를 걸면 누군가 "잠시만요, 연결해 드리겠습니다"라고 말하고 — 실제로 연결됩니다. 교환대를 갖춘 안내 직원이 있기 때문입니다. 이제 [WaveKat Voice](/ko/voice/)——이미 모든 통화를 녹음하고 받아 적는 이 앱——가 1인 가게에도 같은 능력을 줍니다. 보류, 통화 중 대기, 호전환은 데스크에서 일하는 사람이 쉴 새 없이 쓰는 조작이고, 제대로 된 [소프트폰](/ko/voice/alternatives/)이라면 당연히 갖춰야 할 기능입니다. WaveKat Voice는 이제 이 기능들을 갖췄고, 거기에 자신만의 원칙을 하나 더했습니다. 보류 중에 일어난 일은 녹음에 남지 않습니다. + +## 전화를 보류하기 + +WaveKat Voice에서 발신자를 보류하면 통화가 멈춰 있는 동안 녹음과 실시간 받아 적기도 함께 멈춥니다 — 보류 중에 책상 근처에서 한 말은 녹음에도, 받아 적기에도 남지 않습니다. 통화 화면의 음소거와 키패드 사이에 **보류** 버튼이 있습니다. 누르면 통화가 양방향으로 멈춰, 당신에게는 상대가 들리지 않고 상대에게도 당신이 들리지 않습니다. + +WaveKat Voice는 SIP 표준 방식으로 상대편 전화 시스템에 통화가 보류 중임을 알리므로, 대부분의 시스템은 발신자에게 자체 대기 음악을 들려줍니다 — 상대가 듣는 것은 "보류 중입니다"이지, 죽은 정적이 아닙니다. 이것은 단순히 양쪽을 로컬에서 음소거하는 것 이상입니다. 상대편 시스템은 통화가 그저 조용해진 것이 아니라 보류되었음을 압니다. **재개**를 누르면 대화도, 녹음도, 받아 적기도 다시 이어집니다. + +![Ubuntu의 WaveKat Voice — 보류 중인 통화: 보류 배너와 재개 버튼이 표시되고 받아 적기는 일시 정지된 상태.](/screenshots/in-call-hold/ko.webp) + +## 통화 중 대기: 통화하면서 두 번째 전화 받기 + +이미 통화하는 중에 두 번째 전화가 울려도, 이제 둘 중 하나를 고를 필요가 없습니다. 받으면 첫 번째 통화는 저절로 보류됩니다 — 휴대폰의 통화 중 대기와 똑같습니다. 통화 화면의 전환 바에 진행 중인 모든 통화가 나열되고, 클릭 한 번으로 오갈 수 있습니다. + +라이브 오디오를 가진 통화는 언제나 하나뿐입니다. 지금 보고 있는 통화가 지금 말하고 있는 통화입니다. 나머지는 모두 보류 상태이며, 그 녹음과 실시간 받아 적기는 다시 전환할 때까지 일시 정지됩니다. 기본적으로는 보류된 통화로 전환하면 즉시 재개됩니다. 통화마다 직접 재개하고 싶다면 **설정 → 일반**에 토글이 있습니다("전환한 통화를 자동으로 재개"). 보류 중인 통화에는 뚜렷한 배너가 표시되므로, 조용한 회선이 끊긴 회선으로 오해받는 일은 없습니다. + +![Ubuntu의 WaveKat Voice — 통화 중 화면. 전환 바에는 두 명의 발신자가 보류 상태로 대기 중.](/screenshots/in-call-waiting/ko.webp) + +## 전화 돌려주기 — 바로, 또는 확인한 뒤에 + +**호전환** 버튼은 통화 중인 상대를 다른 사람에게 보냅니다 — 다른 번호, 다른 내선, 다른 SIP 주소로. 방법은 두 가지이며, WaveKat Voice는 둘 다 지원합니다. + +| | 블라인드 전환 | 협의 전환 | +|---|---|---| +| **무슨 일이 일어나나** | 발신자가 즉시 새 번호로 연결됩니다 | 먼저 당신이 상대에게 전화해 이야기한 뒤, 두 사람을 연결합니다 | +| **받을 사람과 먼저 통화하나요?** | 아니요 | 네 — 확인하는 동안 발신자는 보류 상태로 기다립니다 | +| **받을 사람이 전화를 받지 않으면** | 발신자는 그대로 당신 곁에 남고, 아무것도 잃지 않습니다 | 협의 통화를 끊고 발신자에게 돌아가면 됩니다 | +| **언제 쓰나** | 상대가 받아야 한다고 확신할 때: "청구 담당으로 연결해 드릴게요" | 발신자를 먼저 소개하고 싶거나, 상대가 가능한지 확실치 않을 때 | + +블라인드 전환은 호전환을 누르고 대상을 입력하면 끝입니다. 새 상대가 받는 순간 당신 쪽 통화는 종료됩니다. 협의 전환은 **먼저 통화하기**를 선택합니다. 발신자는 보류되고, WaveKat Voice가 두 번째 통화로 대상에게 전화를 걸어 당신이 상대와 따로 이야기할 수 있습니다("인보이스 문의하시는 고객이 계신데 — 받아 주실 수 있나요?"). 준비가 되면 **전환 완료**를 누르세요. 두 사람이 연결되고 당신은 빠집니다. 상대가 바쁘거나, 거절하거나, 알고 보니 다른 사람이라면 협의 통화를 끊고 발신자를 재개하면 됩니다. 첫 시도가 실패했다는 사실을 발신자는 전혀 알지 못합니다. + +![Ubuntu의 WaveKat Voice — 협의 전환 진행 중: 발신자는 보류 상태이고, 전환 완료 버튼으로 두 사람을 연결.](/screenshots/in-call-transfer/ko.webp) + +호전환도 기록에 정직하게 남습니다. 전환된 통화는 **전환됨**으로 종료되고, 통화 상세 페이지에는 어디로 갔는지가 정확히 표시됩니다 — "…(으)로 전환됨" — 당신이 끊은 것처럼 꾸미지 않습니다. + +## 자주 묻는 질문 + +### WaveKat Voice에서 전화를 어떻게 돌려주나요? + +통화 화면에서 호전환을 누르고 번호, 내선 또는 SIP 주소를 입력하세요. 바로 보내면 블라인드 전환입니다. **먼저 통화하기**를 선택하면 발신자를 보류한 채 대상에게 전화를 걸어 소개할 수 있고, **전환 완료**를 누르면 두 사람이 연결됩니다. + +### 블라인드 전환과 협의 전환의 차이는 무엇인가요? + +블라인드 전환은 받을 사람과 먼저 통화하지 않고 발신자를 즉시 새 대상으로 보냅니다. 협의 전환은 발신자를 보류한 채 당신이 직접 받을 사람에게 전화를 걸고, 확인한 뒤에야 두 사람을 연결합니다 — 상대가 바쁘거나 거절하면 언제든 되돌아갈 수 있습니다. WaveKat Voice는 둘 다 지원합니다. + +### 제가 전화를 돌려주는 사람도 WaveKat Voice가 필요한가요? + +아니요. WaveKat Voice는 SIP 표준 호전환 메커니즘(RFC 3515의 REFER)을 사용하므로, 받는 쪽에는 그저 평범한 전화가 걸려올 뿐입니다. 어떤 전화기든, 어떤 소프트폰이든, 통신사가 연결할 수 있는 어떤 내선이든 상관없습니다. + +### 보류와 호전환은 어떤 SIP 통신사에서도 작동하나요? + +네. 보류는 SIP 표준 re-INVITE(RFC 3264)를, 호전환은 SIP REFER(RFC 3515)를 사용하므로, 둘 다 SIP 표준을 따르는 어떤 통신사나 PBX에서도 지금 쓰고 있는 계정 그대로 작동합니다 — 통신사별 설정은 필요 없습니다. + +### 두 통화를 합쳐 전화 회의로 만들 수 있나요? + +아직은 안 됩니다. WaveKat Voice는 두 개 이상의 통화를 동시에 보류하고 오갈 수 있지만, 라이브인 통화는 언제나 하나뿐입니다. 3자 통화는 아직 만들지 않은 별개의 기능입니다. + +### 보류 중에 발신자에게는 무엇이 들리나요? + +WaveKat Voice에서 보류된 발신자는 자신의 전화 시스템이 보류용으로 들려주는 것을 듣습니다 — 보통은 그 시스템의 대기 음악이며, WaveKat Voice가 내는 정적이나 신호음이 아닙니다. WaveKat Voice는 SIP 표준 방식(RFC 3264의 re-INVITE)으로 보류를 알려, 보류 경험을 발신자 자신의 시스템에 맡깁니다. 그래서 상대는 예상한 대로 듣게 됩니다. + +### 통화가 보류된 동안에도 녹음되나요? + +아니요. 녹음과 실시간 받아 적기는 보류 동안 양쪽 모두 멈추고, 통화가 재개될 때 함께 이어집니다. 저장된 녹음의 타임라인은 그대로 정확합니다 — 보류된 시간은 잘려 나가는 대신 무음으로 남습니다. + +### 보류, 통화 중 대기, 호전환은 어떤 플랫폼에서 지원되나요? + +WaveKat Voice는 현재 Mac과 Linux에서 실행되며, Windows는 수요가 있을 때 지원할 예정입니다. 보류, 통화 중 대기, 두 가지 호전환 모두 지원되는 두 플랫폼에서, 지금 쓰고 있는 SIP 계정 그대로 작동합니다 — 추가 비용도, 설정도 없습니다. + +## 직접 써 보세요 + +[WaveKat Voice를 다운로드](/ko/voice/download/)하거나 [0.0.42](/ko/voice/changelog/#0.0.42)로 업데이트하세요. 컨트롤은 모든 통화 화면에 있습니다. 보류는 음소거 옆에, 호전환은 그 곁에, 그리고 통화 중 대기는 두 번째 전화가 울리면 저절로 작동합니다. 설정할 것도, 추가로 낼 돈도 없습니다. + +전화를 보류하고, 두 번째 회선을 받고, 안내 데스크가 있는 것처럼 사람을 연결해 주세요 — 이제 정말로 있으니까요. diff --git a/src/content/blog/zh-hant/hold-switch-and-transfer-calls.md b/src/content/blog/zh-hant/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..7bdf963 --- /dev/null +++ b/src/content/blog/zh-hant/hold-switch-and-transfer-calls.md @@ -0,0 +1,85 @@ +--- +title: "像總機一樣保留、切換與轉接來電" +description: "WaveKat Voice 現在可以將通話保留、在通話中接聽第二通來電,並以盲轉或詢問轉接的方式轉接來電——Mac 和 Linux 均可用,且錄音在保留期間會自動暫停。" +date: 2026-07-05 +author: Eason Guo +tags: [語音AI, 通話] +lang: "zh-Hant" +--- + +WaveKat Voice——一款可在 Mac 和 Linux 上執行、會記錄並轉寫每一通通話的 SIP 軟體電話——現在可以做總機每天都在做的三件事:把來電者保留、在第一通電話等待時接聽第二通來電,以及把來電者轉接給其他人——可以直接轉過去,也可以先和對方溝通確認。該功能隨 WaveKat Voice [0.0.42](/zh-hant/voice/changelog/#0.0.42) 推出。 + +這是我們朝著[讓每一家小企業都擁有大企業的聲音](/zh-hant/blog/hello-world/)邁出的最直觀的一步。當你致電一家大公司時,會有人說「請稍候,我幫您轉過去」——之所以能做到,是因為有一位總機和一台話務台。現在,[WaveKat Voice](/zh-hant/voice/)——這款已經記錄並轉寫每一通通話的應用程式——讓一個人的小店也擁有同樣的能力。保留、話中插接和轉接是接線員每天都離不開的操作,也是任何一款像樣的[軟體電話](/zh-hant/voice/alternatives/)都應具備的功能——WaveKat Voice 現在不僅有了它們,還多了一層自己的堅持:保留期間發生的一切,不會進入錄音。 + +## 將來電者保留 + +在 WaveKat Voice 中把來電者保留,只要通話仍處於保留狀態,錄音和即時轉寫就會一直暫停——保留期間你桌邊說的任何話,都不會進入錄音或轉寫。通話畫面上有一個**保留**按鈕,位於靜音和撥號鍵盤之間;按下它,通話會在兩個方向上同時暫停:你聽不到對方,對方也聽不到你。 + +WaveKat Voice 會以標準 SIP 方式告知對方的電話系統這通電話正被保留,所以大多數系統會播放自己的等待音樂——對方聽到的是「您正在等待」,而不是一片死寂。這不只是把兩端在本地靜音:對方的系統知道這通電話正被保留,而不只是安靜下來。按下**恢復**,對話、錄音和轉寫就會繼續。 + +![Ubuntu 上的 WaveKat Voice —— 一通處於保留狀態的通話:顯示保留橫幅和恢復按鈕,轉寫已暫停。](/screenshots/in-call-hold/zh-Hant.webp) + +## 話中插接:通話中接聽第二通來電 + +當你正在通話時又有第二通電話打進來,你不再需要二選一。接聽它,第一通電話會自動進入保留狀態——就像手機上的話中插接(插撥)一樣。通話畫面上的切換列會列出每一通進行中的通話,點一下即可在它們之間切換。 + +任何時刻只有一通電話是即時的。你正在看的那通電話就是你正在講的那通;其他每一通都處於保留狀態,它們的錄音和即時轉寫也會暫停,直到你切換回來為止。預設情況下,切換到一通被保留的電話會立即恢復它;如果你更希望每次都手動恢復,可以在**設定 → 一般**中關閉「切換到通話時自動恢復」。任何處於保留狀態的通話都會顯示醒目的橫幅提示,安靜的線路絕不會被誤認為已經掛斷。 + +![Ubuntu 上的 WaveKat Voice —— 一通進行中的通話,另有兩位來電者在切換列中保留等待。](/screenshots/in-call-waiting/zh-Hant.webp) + +## 轉接來電——直接轉,或先溝通再轉 + +**轉接**按鈕可以把正在通話的來電者轉給其他人——另一個號碼、另一個分機,或另一個 SIP 位址。轉接有兩種方式,WaveKat Voice 兩種都支援: + +| | 盲轉(直接轉接) | 詢問轉接(先溝通再轉) | +|---|---|---| +| **會發生什麼** | 來電者被立即轉到新號碼 | 你先撥給接收方,溝通後再把兩人接通 | +| **轉接前是否先和接收方通話?** | 否 | 是——來電者在保留中等待你確認 | +| **如果接收方沒有接聽** | 來電者仍在你這邊,什麼都不會遺失 | 掛斷諮詢通話,回到來電者即可 | +| **適用場景** | 你確定該由對方接手:「幫您轉到帳務部」 | 你想先介紹來電者,或不確定對方是否方便 | + +盲轉時,按下轉接、輸入目標號碼即可——新的接收方一接聽,你這邊的通話就結束了。詢問轉接時,選擇**先溝通**:來電者進入保留狀態,WaveKat Voice 以第二通電話撥給目標號碼,你可以先和對方私下交談(「有位客戶想詢問發票的事——你方便接嗎?」)。對方準備好後,按下**完成轉接**,兩人即被接通,你則退出通話。如果對方正忙、拒接,或者發現找錯了人,只需掛斷諮詢通話並恢復來電者——對方完全不會知道第一次嘗試沒有成功。 + +![Ubuntu 上的 WaveKat Voice —— 詢問轉接進行中:來電者處於保留狀態,按下完成轉接即可把兩人接通。](/screenshots/in-call-transfer/zh-Hant.webp) + +轉接也會如實記錄在你的通話記錄中。被轉接的通話以**已轉接**結束,通話詳情頁會準確顯示它去了哪裡——「已轉接至 …」——而不是假裝是你掛斷了電話。 + +## 常見問題 + +### 如何在 WaveKat Voice 中轉接電話? + +在通話畫面按下轉接,輸入號碼、分機或 SIP 位址。直接送出就是盲轉;選擇**先溝通**會把來電者保留並撥給目標號碼,讓你先介紹來電者,再按**完成轉接**把兩人接通。 + +### 盲轉和詢問轉接有什麼區別? + +盲轉會立即把來電者轉到新的目標號碼,轉接前不與接收方通話。詢問轉接則先保留來電者,由你親自撥給接收方,確認後才把兩人接通——如果對方正忙或拒接,你隨時可以退回。WaveKat Voice 兩種方式都支援。 + +### 我把電話轉給的人需要安裝 WaveKat Voice 嗎? + +不需要。WaveKat Voice 使用標準的 SIP 轉接機制(RFC 3515 的 REFER),接收方收到的只是一通普通來電——任何電話、任何軟體電話、任何你的電信業者能接通的分機都可以。 + +### 保留和轉接可以搭配任何 SIP 供應商使用嗎? + +可以。保留使用標準的 SIP re-INVITE(RFC 3264),轉接使用 SIP REFER(RFC 3515),所以兩者都能搭配任何符合 SIP 標準的供應商或 PBX 使用,用你現有的帳號即可——無需任何供應商專屬的設定。 + +### 可以把兩通電話合併成電話會議嗎? + +暫時不行。WaveKat Voice 可以同時保留兩通或更多電話並在它們之間切換,但任何時刻只有一通是即時的。三方通話是另一項我們尚未打造的功能。 + +### 來電者在保留期間會聽到什麼? + +在 WaveKat Voice 中被保留的來電者,聽到的是他們自己的電話系統為保留狀態播放的內容——通常是等待音樂,而不是一片靜寂或 WaveKat Voice 播放的提示音。WaveKat Voice 以標準 SIP 方式(RFC 3264 的 re-INVITE)告知保留,把保留時的體驗交給來電者自己的系統處理,所以他們聽到的正是預期中的內容。 + +### 通話保留期間會錄音嗎? + +不會。錄音和即時轉寫在保留期間雙向暫停,通話恢復時才繼續。儲存下來的錄音時間軸依然準確——保留的時段呈現為靜音,而不是被剪掉。 + +### 哪些平台支援保留、話中插接和轉接? + +WaveKat Voice 目前支援 Mac 和 Linux,Windows 版將視需求推出。保留、話中插接和兩種轉接方式在兩個受支援的平台上都可用,使用你現有的 SIP 帳號即可——無需額外付費,也無需任何設定。 + +## 試試看 + +[下載 WaveKat Voice](/zh-hant/voice/download/)——或更新到 [0.0.42](/zh-hant/voice/changelog/#0.0.42)——每個通話畫面上就都有這些控制項了:保留就在靜音旁邊,轉接緊挨著它,第二通電話響起時話中插接會自動生效。無需設定,也無需額外付費。 + +把來電者保留,接起第二條線,再像有總機一樣把人轉接過去——因為現在,你真的有了。 diff --git a/src/content/blog/zh/hold-switch-and-transfer-calls.md b/src/content/blog/zh/hold-switch-and-transfer-calls.md new file mode 100644 index 0000000..a3ff286 --- /dev/null +++ b/src/content/blog/zh/hold-switch-and-transfer-calls.md @@ -0,0 +1,85 @@ +--- +title: "像前台一样保持、切换和转接来电" +description: "WaveKat Voice 现在可以将通话置于保持状态、在通话中接听第二通来电,并以盲转或询问转接的方式转接来电——Mac 和 Linux 均可用。录音在保持期间会自动暂停。" +date: 2026-07-05 +author: Eason Guo +tags: [语音AI, 通话] +lang: "zh-Hans" +--- + +WaveKat Voice——一款可在 Mac 和 Linux 上运行、会记录并转写每一通通话的 SIP 软电话——现在可以做前台每天都在做的三件事:把来电者置于保持状态、在第一通电话等待时接听第二通来电,以及把来电者转接给其他人——可以直接转过去,也可以先和对方沟通确认。该功能随 WaveKat Voice [0.0.42](/zh/voice/changelog/#0.0.42) 推出。 + +这是我们朝着[让每一家小企业都拥有大企业的声音](/zh/blog/hello-world/)迈出的最直观的一步。当你致电一家大公司时,会有人说「请稍等,我帮您转过去」——之所以能做到,是因为有一位前台和一台话务台。现在,[WaveKat Voice](/zh/voice/)——这款已经记录并转写每一通通话的应用——让一个人的小店也拥有同样的能力。保持、呼叫等待和转接是接线员每天都离不开的操作,也是任何一款像样的[软电话](/zh/voice/alternatives/)都应具备的功能——WaveKat Voice 现在不仅有了它们,还多了一层自己的坚持:保持期间发生的一切,不会进入录音。 + +## 将来电者置于保持状态 + +在 WaveKat Voice 中将来电者置于保持状态,会在通话被挂起期间暂停录音和实时转写——保持期间你桌边说的任何话都不会进入录音或转写。通话界面上有一个**保持**按钮,位于静音和拨号键盘之间;按下它,通话会在两个方向上同时暂停:你听不到对方,对方也听不到你。 + +WaveKat Voice 会以标准 SIP 方式告知对方的电话系统这通电话正被保持,所以大多数系统会向来电者播放自己的等待音乐——对方听到的是「您正在等待」,而不是一片死寂。这不只是把两端在本地静音:对方系统知道这通电话正被挂起,而不只是安静下来。按下**恢复**,对话、录音和转写就会继续。 + +![Ubuntu 上的 WaveKat Voice —— 一通处于保持状态的通话:显示保持横幅和恢复按钮,转写已暂停。](/screenshots/in-call-hold/zh-Hans.webp) + +## 呼叫等待:通话中接听第二通来电 + +当你正在通话时又有第二通电话打进来,你不再需要二选一。接听它,第一通电话会自动进入保持状态——就像手机上的呼叫等待一样。通话界面上的切换栏会列出每一通正在进行的通话,点击即可在它们之间切换。 + +任何时刻只有一通电话是实时的。你正在看的那通电话就是你正在讲的那通;其他每一通电话都处于保持状态,它们的录音和实时转写会一直暂停,直到你切换回去。默认情况下,切换到一通被保持的电话会立即恢复它;如果你更希望每次都手动恢复,可以在**设置 → 通用**中关闭「切换到通话时自动恢复」。任何处于保持状态的通话都会显示醒目的横幅提示,安静的线路绝不会被误认为已经挂断。 + +![Ubuntu 上的 WaveKat Voice —— 一通正在进行的通话,另有两位来电者在切换栏中保持等待。](/screenshots/in-call-waiting/zh-Hans.webp) + +## 转接来电——直接转,或先沟通再转 + +**转接**按钮可以把正在通话的来电者转给其他人——另一个号码、另一个分机,或另一个 SIP 地址。转接有两种方式,WaveKat Voice 两种都支持: + +| | 盲转(直接转接) | 询问转接(先沟通再转) | +|---|---|---| +| **会发生什么** | 来电者被立即转到新号码 | 你先拨给接收方,沟通后再把两人接通 | +| **转接前是否先和接收方通话?** | 否 | 是——来电者在保持中等待你确认 | +| **如果接收方没有接听** | 来电者仍在你这边,什么都不会丢失 | 挂断咨询通话,回到来电者即可 | +| **适用场景** | 你确定该由对方接手:「帮您转到账务部」 | 你想先介绍来电者,或不确定对方是否方便 | + +盲转时,按下转接、输入目标号码即可——新的接收方一接听,你这边的通话就结束了。询问转接时,选择**先沟通**:来电者进入保持状态,WaveKat Voice 以第二通电话拨给目标号码,你可以先和对方私下交谈(「有位客户想咨询发票的事——你方便接吗?」)。对方准备好后,按下**完成转接**,两人即被接通,你则退出通话。如果对方正忙、拒接,或者发现找错了人,只需挂断咨询通话并恢复来电者——对方完全不会知道第一次尝试没有成功。 + +![Ubuntu 上的 WaveKat Voice —— 询问转接进行中:来电者处于保持状态,按下完成转接即可把两人接通。](/screenshots/in-call-transfer/zh-Hans.webp) + +转接也会如实记录在你的通话历史中。被转接的通话以**已转接**结束,通话详情页会准确显示它去了哪里——「已转接至 …」——而不是假装是你挂断了电话。 + +## 常见问题 + +### 如何在 WaveKat Voice 中转接电话? + +在通话界面按下转接,输入号码、分机或 SIP 地址。直接发送就是盲转;选择**先沟通**会把来电者置于保持状态并拨给目标号码,让你先介绍来电者,再按**完成转接**把两人接通。 + +### 盲转和询问转接有什么区别? + +盲转会立即把来电者转到新的目标号码,转接前不与接收方通话。询问转接则先保持来电者,由你亲自拨给接收方,确认后才把两人接通——如果对方正忙或拒接,你随时可以退回。WaveKat Voice 两种方式都支持。 + +### 我把电话转给的人需要安装 WaveKat Voice 吗? + +不需要。WaveKat Voice 使用标准的 SIP 转接机制(RFC 3515 的 REFER),接收方收到的只是一通普通来电——任何电话、任何软电话、任何你的运营商能接通的分机都可以。 + +### 保持和转接适用于任何 SIP 运营商吗? + +适用。保持使用标准的 SIP re-INVITE(RFC 3264),转接使用 SIP REFER(RFC 3515),所以两者都能在任何符合 SIP 标准的运营商或 PBX 上工作,使用你现有的账号即可——无需针对特定运营商进行任何设置。 + +### 可以把两通电话合并成电话会议吗? + +暂时不行。WaveKat Voice 可以同时保持两通或更多电话并在它们之间切换,但任何时刻只有一通是实时的。三方通话是另一项我们尚未构建的功能。 + +### 来电者在保持期间会听到什么? + +在 WaveKat Voice 中被置于保持状态的来电者,听到的是他们自己的电话系统为保持状态播放的内容——通常是等待音乐,而不是 WaveKat Voice 发出的静音或提示音。WaveKat Voice 以标准 SIP 方式(RFC 3264 的 re-INVITE)告知保持,将保持体验交给来电者自己的系统,所以他们听到的正是意料之中的内容。 + +### 通话保持期间会录音吗? + +不会。录音和实时转写在保持期间双向暂停,通话恢复时才继续。保存下来的录音时间线依然准确——保持的时段呈现为静音,而不是被剪掉。 + +### 哪些平台支持保持、呼叫等待和转接? + +WaveKat Voice 目前支持 Mac 和 Linux,Windows 版将视需求推出。保持、呼叫等待和两种转接方式在两个受支持的平台上都可用,使用你现有的 SIP 账号即可——无需额外付费,也无需任何设置。 + +## 试试看 + +[下载 WaveKat Voice](/zh/voice/download/)——或更新到 [0.0.42](/zh/voice/changelog/#0.0.42)——每个通话界面上就都有这些控件了:保持就在静音旁边,转接紧挨着它,第二通电话响起时呼叫等待会自动生效。无需配置,也无需额外付费。 + +把来电者置于保持状态,接起第二条线,再像有前台一样把人转接过去——因为现在,你真的有了。 diff --git a/src/lib/blog.ts b/src/lib/blog.ts new file mode 100644 index 0000000..d839522 --- /dev/null +++ b/src/lib/blog.ts @@ -0,0 +1,18 @@ +import type { CollectionEntry } from 'astro:content'; + +// Draft posts are hidden from every blog route (listings, per-post pages, RSS) +// in normal builds. To preview them locally, set DRAFTS=1 — `make dev-draft` +// (dev server) or `make build-draft` (production build) do this for you. The +// env var is read at build/dev time in Node, so it never ships to the client +// and production builds (where it's unset) always exclude drafts. +export const showDrafts = process.env.DRAFTS === '1' || process.env.DRAFTS === 'true'; + +/** + * Predicate for getCollection('blog', …): keeps posts in `lang`, hiding drafts + * unless DRAFTS is set. Every blog route filters through this so drafts appear + * or vanish everywhere at once. + */ +export function blogFilter(lang: string) { + return ({ data }: CollectionEntry<'blog'>) => + (showDrafts || !data.draft) && data.lang === lang; +} diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts index b21ab91..22f07bd 100644 --- a/src/lib/i18n.ts +++ b/src/lib/i18n.ts @@ -78,6 +78,7 @@ const fullSite = [ '/blog/common-voice-explorer/', '/blog/place-calls-from-the-command-line/', '/blog/share-a-call-recording/', + '/blog/hold-switch-and-transfer-calls/', '/about/', ]; diff --git a/src/pages/blog/[slug].astro b/src/pages/blog/[slug].astro index b0fedb8..99855e3 100644 --- a/src/pages/blog/[slug].astro +++ b/src/pages/blog/[slug].astro @@ -1,10 +1,11 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../lib/blog'; import Post from '../../layouts/Post.astro'; import { extractFaqs } from '../../lib/seo'; export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'en'); + const posts = await getCollection('blog', blogFilter('en')); return posts.map((post) => ({ params: { slug: post.id }, props: { post }, diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index 90c4686..137f168 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -1,12 +1,13 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../lib/blog'; import Base from '../../layouts/Base.astro'; import Header from '../../components/Header.astro'; import Footer from '../../components/Footer.astro'; import PostCard from '../../components/PostCard.astro'; import { itemListSchema } from '../../lib/seo'; -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'en')) +const posts = (await getCollection('blog', blogFilter('en'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const listSchema = itemListSchema('WaveKat Blog', new URL(Astro.url.pathname, Astro.site!).href, posts.map((p) => ({ name: p.data.title, url: new URL(`/blog/${p.id}/`, Astro.site!).href }))); diff --git a/src/pages/de/blog/[slug].astro b/src/pages/de/blog/[slug].astro index 44b74f8..9aa9d7c 100644 --- a/src/pages/de/blog/[slug].astro +++ b/src/pages/de/blog/[slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Post from '../../../layouts/Post.astro'; import { extractFaqs } from '../../../lib/seo'; @@ -7,7 +8,7 @@ import { extractFaqs } from '../../../lib/seo'; // (id "de/"); the route param is the bare slug so URLs are /de/blog//. // The Post layout localises its chrome from the /de/ URL automatically. export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'de'); + const posts = await getCollection('blog', blogFilter('de')); return posts.map((post) => ({ params: { slug: post.id.replace(/^de\//, '') }, props: { post }, diff --git a/src/pages/de/blog/index.astro b/src/pages/de/blog/index.astro index fff681a..5808f7e 100644 --- a/src/pages/de/blog/index.astro +++ b/src/pages/de/blog/index.astro @@ -1,5 +1,6 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Base from '../../../layouts/Base.astro'; import Header from '../../../components/Header.astro'; import Footer from '../../../components/Footer.astro'; @@ -8,7 +9,7 @@ import { itemListSchema } from '../../../lib/seo'; // German posts live under src/content/blog/de/ (id "de/"). // Strip the locale prefix so the cards link to /de/blog//. -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'de')) +const posts = (await getCollection('blog', blogFilter('de'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const slugOf = (id: string) => id.replace(/^de\//, ''); diff --git a/src/pages/es/blog/[slug].astro b/src/pages/es/blog/[slug].astro index 92b1be1..d29d4c6 100644 --- a/src/pages/es/blog/[slug].astro +++ b/src/pages/es/blog/[slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Post from '../../../layouts/Post.astro'; import { extractFaqs } from '../../../lib/seo'; @@ -7,7 +8,7 @@ import { extractFaqs } from '../../../lib/seo'; // (id "es/"); the route param is the bare slug so URLs are /es/blog//. // The Post layout localises its chrome from the /es/ URL automatically. export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'es'); + const posts = await getCollection('blog', blogFilter('es')); return posts.map((post) => ({ params: { slug: post.id.replace(/^es\//, '') }, props: { post }, diff --git a/src/pages/es/blog/index.astro b/src/pages/es/blog/index.astro index edbb6be..29ec8a0 100644 --- a/src/pages/es/blog/index.astro +++ b/src/pages/es/blog/index.astro @@ -1,5 +1,6 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Base from '../../../layouts/Base.astro'; import Header from '../../../components/Header.astro'; import Footer from '../../../components/Footer.astro'; @@ -8,7 +9,7 @@ import { itemListSchema } from '../../../lib/seo'; // Spanish posts live under src/content/blog/es/ (id "es/"). // Strip the locale prefix so the cards link to /es/blog//. -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'es')) +const posts = (await getCollection('blog', blogFilter('es'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const slugOf = (id: string) => id.replace(/^es\//, ''); diff --git a/src/pages/fr/blog/[slug].astro b/src/pages/fr/blog/[slug].astro index 850b56f..8d0da05 100644 --- a/src/pages/fr/blog/[slug].astro +++ b/src/pages/fr/blog/[slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Post from '../../../layouts/Post.astro'; import { extractFaqs } from '../../../lib/seo'; @@ -7,7 +8,7 @@ import { extractFaqs } from '../../../lib/seo'; // (id "fr/"); the route param is the bare slug so URLs are /fr/blog//. // The Post layout localises its chrome from the /fr/ URL automatically. export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'fr'); + const posts = await getCollection('blog', blogFilter('fr')); return posts.map((post) => ({ params: { slug: post.id.replace(/^fr\//, '') }, props: { post }, diff --git a/src/pages/fr/blog/index.astro b/src/pages/fr/blog/index.astro index c6ff619..6cc90c5 100644 --- a/src/pages/fr/blog/index.astro +++ b/src/pages/fr/blog/index.astro @@ -1,5 +1,6 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Base from '../../../layouts/Base.astro'; import Header from '../../../components/Header.astro'; import Footer from '../../../components/Footer.astro'; @@ -8,7 +9,7 @@ import { itemListSchema } from '../../../lib/seo'; // French posts live under src/content/blog/fr/ (id "fr/"). // Strip the locale prefix so the cards link to /fr/blog//. -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'fr')) +const posts = (await getCollection('blog', blogFilter('fr'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const slugOf = (id: string) => id.replace(/^fr\//, ''); diff --git a/src/pages/it/blog/[slug].astro b/src/pages/it/blog/[slug].astro index 80193cb..b8dcbfe 100644 --- a/src/pages/it/blog/[slug].astro +++ b/src/pages/it/blog/[slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Post from '../../../layouts/Post.astro'; import { extractFaqs } from '../../../lib/seo'; @@ -7,7 +8,7 @@ import { extractFaqs } from '../../../lib/seo'; // (id "it/"); the route param is the bare slug so URLs are /it/blog//. // The Post layout localises its chrome from the /it/ URL automatically. export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'it'); + const posts = await getCollection('blog', blogFilter('it')); return posts.map((post) => ({ params: { slug: post.id.replace(/^it\//, '') }, props: { post }, diff --git a/src/pages/it/blog/index.astro b/src/pages/it/blog/index.astro index 83a29b9..1b31885 100644 --- a/src/pages/it/blog/index.astro +++ b/src/pages/it/blog/index.astro @@ -1,5 +1,6 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Base from '../../../layouts/Base.astro'; import Header from '../../../components/Header.astro'; import Footer from '../../../components/Footer.astro'; @@ -8,7 +9,7 @@ import { itemListSchema } from '../../../lib/seo'; // Italian posts live under src/content/blog/it/ (id "it/"). // Strip the locale prefix so the cards link to /it/blog//. -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'it')) +const posts = (await getCollection('blog', blogFilter('it'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const slugOf = (id: string) => id.replace(/^it\//, ''); diff --git a/src/pages/ja/blog/[slug].astro b/src/pages/ja/blog/[slug].astro index 975437d..dd218f8 100644 --- a/src/pages/ja/blog/[slug].astro +++ b/src/pages/ja/blog/[slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Post from '../../../layouts/Post.astro'; import { extractFaqs } from '../../../lib/seo'; @@ -7,7 +8,7 @@ import { extractFaqs } from '../../../lib/seo'; // (id "ja/"); the route param is the bare slug so URLs are /ja/blog//. // The Post layout localises its chrome from the /ja/ URL automatically. export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'ja'); + const posts = await getCollection('blog', blogFilter('ja')); return posts.map((post) => ({ params: { slug: post.id.replace(/^ja\//, '') }, props: { post }, diff --git a/src/pages/ja/blog/index.astro b/src/pages/ja/blog/index.astro index fbb188a..e1c0695 100644 --- a/src/pages/ja/blog/index.astro +++ b/src/pages/ja/blog/index.astro @@ -1,5 +1,6 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Base from '../../../layouts/Base.astro'; import Header from '../../../components/Header.astro'; import Footer from '../../../components/Footer.astro'; @@ -8,7 +9,7 @@ import { itemListSchema } from '../../../lib/seo'; // Japanese posts live under src/content/blog/ja/ (id "ja/"). // Strip the locale prefix so the cards link to /ja/blog//. -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'ja')) +const posts = (await getCollection('blog', blogFilter('ja'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const slugOf = (id: string) => id.replace(/^ja\//, ''); diff --git a/src/pages/ko/blog/[slug].astro b/src/pages/ko/blog/[slug].astro index 8c072c9..b78c726 100644 --- a/src/pages/ko/blog/[slug].astro +++ b/src/pages/ko/blog/[slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Post from '../../../layouts/Post.astro'; import { extractFaqs } from '../../../lib/seo'; @@ -7,7 +8,7 @@ import { extractFaqs } from '../../../lib/seo'; // (id "ko/"); the route param is the bare slug so URLs are /ko/blog//. // The Post layout localises its chrome from the /ko/ URL automatically. export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'ko'); + const posts = await getCollection('blog', blogFilter('ko')); return posts.map((post) => ({ params: { slug: post.id.replace(/^ko\//, '') }, props: { post }, diff --git a/src/pages/ko/blog/index.astro b/src/pages/ko/blog/index.astro index 9eabae5..2ebb508 100644 --- a/src/pages/ko/blog/index.astro +++ b/src/pages/ko/blog/index.astro @@ -1,5 +1,6 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Base from '../../../layouts/Base.astro'; import Header from '../../../components/Header.astro'; import Footer from '../../../components/Footer.astro'; @@ -8,7 +9,7 @@ import { itemListSchema } from '../../../lib/seo'; // Korean posts live under src/content/blog/ko/ (id "ko/"). // Strip the locale prefix so the cards link to /ko/blog//. -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'ko')) +const posts = (await getCollection('blog', blogFilter('ko'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const slugOf = (id: string) => id.replace(/^ko\//, ''); diff --git a/src/pages/rss.xml.ts b/src/pages/rss.xml.ts index d028c3f..0c82fc8 100644 --- a/src/pages/rss.xml.ts +++ b/src/pages/rss.xml.ts @@ -1,12 +1,13 @@ import rss from '@astrojs/rss'; import { getCollection } from 'astro:content'; +import { blogFilter } from '../lib/blog'; import type { APIContext } from 'astro'; export async function GET(context: APIContext) { // English only: translated posts have ids like "de/" whose URLs live // under /de/blog/, so including them here produced broken /blog/de/ // links and interleaved nine languages into one feed. - const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'en')) + const posts = (await getCollection('blog', blogFilter('en'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); return rss({ diff --git a/src/pages/zh-hant/blog/[slug].astro b/src/pages/zh-hant/blog/[slug].astro index 85a2303..6844048 100644 --- a/src/pages/zh-hant/blog/[slug].astro +++ b/src/pages/zh-hant/blog/[slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Post from '../../../layouts/Post.astro'; import { extractFaqs } from '../../../lib/seo'; @@ -7,7 +8,7 @@ import { extractFaqs } from '../../../lib/seo'; // (id "zh-hant/"); the route param is the bare slug so URLs are /zh-hant/blog//. // The Post layout localises its chrome from the /zh-hant/ URL automatically. export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'zh-Hant'); + const posts = await getCollection('blog', blogFilter('zh-Hant')); return posts.map((post) => ({ params: { slug: post.id.replace(/^zh-hant\//, '') }, props: { post }, diff --git a/src/pages/zh-hant/blog/index.astro b/src/pages/zh-hant/blog/index.astro index 6f20cdb..68bce66 100644 --- a/src/pages/zh-hant/blog/index.astro +++ b/src/pages/zh-hant/blog/index.astro @@ -1,5 +1,6 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Base from '../../../layouts/Base.astro'; import Header from '../../../components/Header.astro'; import Footer from '../../../components/Footer.astro'; @@ -8,7 +9,7 @@ import { itemListSchema } from '../../../lib/seo'; // Traditional-Chinese posts live under src/content/blog/zh-hant/ (id "zh-hant/"). // Strip the locale prefix so the cards link to /zh-hant/blog//. -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'zh-Hant')) +const posts = (await getCollection('blog', blogFilter('zh-Hant'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const slugOf = (id: string) => id.replace(/^zh-hant\//, ''); diff --git a/src/pages/zh/blog/[slug].astro b/src/pages/zh/blog/[slug].astro index 39c4a2d..65abfbd 100644 --- a/src/pages/zh/blog/[slug].astro +++ b/src/pages/zh/blog/[slug].astro @@ -1,5 +1,6 @@ --- import { getCollection, render } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Post from '../../../layouts/Post.astro'; import { extractFaqs } from '../../../lib/seo'; @@ -7,7 +8,7 @@ import { extractFaqs } from '../../../lib/seo'; // (id "zh/"); the route param is the bare slug so URLs are /zh/blog//. // The Post layout localises its chrome from the /zh/ URL automatically. export async function getStaticPaths() { - const posts = await getCollection('blog', ({ data }) => !data.draft && data.lang === 'zh-Hans'); + const posts = await getCollection('blog', blogFilter('zh-Hans')); return posts.map((post) => ({ params: { slug: post.id.replace(/^zh\//, '') }, props: { post }, diff --git a/src/pages/zh/blog/index.astro b/src/pages/zh/blog/index.astro index 0b3498c..74946d0 100644 --- a/src/pages/zh/blog/index.astro +++ b/src/pages/zh/blog/index.astro @@ -1,5 +1,6 @@ --- import { getCollection } from 'astro:content'; +import { blogFilter } from '../../../lib/blog'; import Base from '../../../layouts/Base.astro'; import Header from '../../../components/Header.astro'; import Footer from '../../../components/Footer.astro'; @@ -8,7 +9,7 @@ import { itemListSchema } from '../../../lib/seo'; // Simplified-Chinese posts live under src/content/blog/zh/ (id "zh/"). // Strip the locale prefix so the cards link to /zh/blog//. -const posts = (await getCollection('blog', ({ data }) => !data.draft && data.lang === 'zh-Hans')) +const posts = (await getCollection('blog', blogFilter('zh-Hans'))) .sort((a, b) => b.data.date.getTime() - a.data.date.getTime()); const slugOf = (id: string) => id.replace(/^zh\//, '');