SDK · Bewertung durch Endnutzer
Vorschau@sonenta/feedback
Lassen Sie Ihre eigenen Endnutzer Übersetzungen direkt aus Ihrer ausgelieferten App heraus bewerten (5★) und vorschlagen. Ein Paket, fünf Einstiegspunkte — /react, /native, /vue, /svelte, /core — gleicher Wire, gleiche serverseitig erstellte Sitzung, gleiches Moderations-Backoffice. React und React Native klinken sich in den @sonenta/*-i18n-Provider ein, den Sie bereits verwenden (kein zweiter Kontext, kein Host-Re-Render); Vue und Svelte sind eigenständige, idiomatische Adapter. Verfügbar als kostenpflichtiges Add-on ab Pro.
Das Paket @sonenta/feedback wird mit dem Add-on „Bewertung von Übersetzungen durch Endnutzer“ beim V1-Launch von Sonenta ausgeliefert. Es ist noch nicht auf npm — der Wire-Vertrag ist eingefroren (v3); die Framework-Bindings stabilisieren sich und können sich vor dem Launch noch ändern.
1. Installieren (beim Launch)
Ein einziges Paket. Importieren Sie den Einstiegspunkt Ihres Frameworks: @sonenta/feedback/react, /native (RN/Expo), /vue, /svelte oder /core für alles andere. vue / svelte sind optionale Peer-Dependencies — nur der jeweilige Einstiegspunkt benötigt sie. Veröffentlicht mit dem Add-on beim V1-Launch.
terminal 1// ships with the End-user evaluation add-on at the V1 launch2npm i @sonenta/react-i18next @sonenta/feedback3// feedback peers with @sonenta/react-i18next 2.x4// optional peer deps only for the matching entry: vue · svelte 2. React (Web) — i18n-Plugin
Fügen Sie feedbackPlugin() dem plugins-Slot Ihres bestehenden @sonenta/react-i18next-Providers (>= 0.7.0) hinzu — kein neuer Provider, kein zweiter Kontext. Der Provider ruft das setup() des Plugins einmal auf und verwendet dessen eigene apiBase / projectId / defaultLocale wieder. Das Panel wird als isoliertes Geschwister-Blatt mit einem privaten Open/Close-Store gemountet: Das Öffnen re-rendert Ihren Host-Baum niemals. Lösen Sie es über Ihr eigenes CTA mithilfe des über controllerRef bereitgestellten Controllers aus (oder dem onReady-Callback).
main.tsx 1// src/main.tsx — plugin of the i18n provider you already run2import { SonentaProvider } from "@sonenta/react-i18next";3import { feedbackPlugin } from "@sonenta/feedback/react";4import { useRef } from "react"; 6const feedback = useRef(null); 8<SonentaProvider9 projectUuid="proj_xxx"10 token={import.meta.env.VITE_SONENTA_TOKEN}11 plugins={[ feedbackPlugin({ controllerRef: feedback }) ]}12>13 <App />14</SonentaProvider> 16// own CTA — does NOT re-render the host tree17<button onClick={() => feedback.current?.open()}>Rate translations</button> Alle Optionen von feedbackPlugin() / createFeedback()
| Option | Typ | Standard |
|---|---|---|
| controllerRef | Ref<Controller> | — |
| onReady | (c) => void | — |
| keys | string[] | auto-discovered |
| flushDebounceMs | number | 1500 |
| maxBatch | number | 20 |
| defaultButton | boolean | false |
3. React Native / Expo
Gleiches Schema vom Einstiegspunkt /native aus: Fügen Sie feedbackPlugin() dem plugins-Slot desselben @sonenta/react-i18next-Providers in Ihrer Expo-App hinzu und lösen Sie über den Controller aus. Keine zusätzlichen nativen Module; die Token-Speicherung verwendet den Secure Store der Plattform.
App.tsx 1// App.tsx (Expo / React Native) — same plugins slot2import { SonentaProvider } from "@sonenta/react-i18next";3import { feedbackPlugin } from "@sonenta/feedback/native"; 5<SonentaProvider6 projectUuid="proj_xxx"7 token={process.env.EXPO_PUBLIC_SONENTA_TOKEN}8 plugins={[ feedbackPlugin({ onReady: (c) => (ctrl = c) }) ]}9>{/* … */}</SonentaProvider> 11// wire ctrl.open() to your own button / FAB 4. Vue
@sonenta/feedback/vue ist ein eigenständiger Adapter — explizite Konfiguration, kein i18n-Provider, von dem geerbt wird. createFeedback(config) liefert { client, isOpen, controller, FeedbackPanel } zurück. Mounten Sie <FeedbackPanel /> einmal nahe der Wurzel (Teleport nach body) und rufen Sie controller.open() aus Ihrem CTA auf. Gleicher isolierter Open-State — er re-rendert Ihre App niemals.
App.vue 1// main.ts — standalone adapter, explicit config2import { createFeedback } from "@sonenta/feedback/vue"; 4export const { controller, FeedbackPanel } = createFeedback({5 apiBase: "https://api.sonenta.com",6 projectId: "proj_xxx", language: "fr",7}); 9// App.vue — mount once near root (Teleports to body)10<FeedbackPanel />11<button @click="controller.open()">Rate translations</button> 5. Svelte
@sonenta/feedback/svelte ist headless und idiomatisch: createFeedback(config) liefert Svelte-Stores zurück — isOpen (Writable), strings (Writable) — plus open(), close(), loadStrings(), rate(), suggest(). Sie rendern Ihr eigenes Panel aus den Stores; das SDK kümmert sich um Transport, Einwilligung und die Server-Sitzung.
+page.svelte 1// feedback.ts — headless idiomatic stores2import { createFeedback } from "@sonenta/feedback/svelte"; 4export const fb = createFeedback({5 apiBase: "https://api.sonenta.com",6 projectId: "proj_xxx", language: "fr",7}); 9// component — render your own panel from the stores10{#if $fb.isOpen}{#each $fb.strings as s}…{/each}{/if}11<button on:click={fb.open}>Rate translations</button> 6. Alles andere — /core
@sonenta/feedback/core stellt den eingefrorenen FeedbackClient bereit, auf dem alle Adapter aufbauen: acceptTos(), loadStrings(), rate(), suggest(), debounce-ter, gebündelter Transport, rotierendes JWT. Verwenden Sie ihn direkt für jedes Framework ohne First-Party-Adapter.
feedback.ts 1// any framework — the frozen client all adapters wrap2import { FeedbackClient } from "@sonenta/feedback/core"; 4const client = new FeedbackClient({5 apiBase: "https://api.sonenta.com",6 projectId: "proj_xxx", language: "fr",7});8await client.acceptTos(); // server mints the session9await client.loadStrings(); client.rate(/* … */); client.suggest(/* … */); 7. Eingrenzung auf angezeigte Schlüssel (automatisch)
Das Panel grenzt sich automatisch auf die Schlüssel ein, die tatsächlich in der aktuellen Ansicht angezeigt werden, über das globale Schlüsselregister, das das @sonenta/*-i18n-SDK erzeugt — keine Konfiguration. Übergeben Sie ein explizites keys-Array nur als Fallback (z. B. für Strings, die nicht aus @sonenta/*-i18n stammen); übergeben Sie niemals Ihren gesamten Katalog — das würde jeden String der App offenlegen, nicht die, die der Nutzer gerade betrachtet. Das Register wird beim Mounten verfolgt und per Referenz gezählt: dauerhaft sichtbare Strings (eine Kopfzeile, ein Eyebrow) bleiben registriert, solange ihre Komponente gemountet ist — es gibt kein Zurücksetzen pro Ansicht. (reset() existiert nur als Notausstieg für Sonderfälle bei Nicht-React-Routing; das SDK ruft es niemals automatisch auf.)
scoping.ts 1// the panel auto-scopes to keys RENDERED on the current2// view, via the global key registry the @sonenta/*-i18n3// SDK produces — no config needed:4feedbackPlugin({ controllerRef: feedback }); // auto-scoped 6// explicit keys = FALLBACK only (e.g. strings not from7// @sonenta/*-i18n). NEVER pass your whole catalogue.8feedbackPlugin({ keys: ["common:checkout.cta"] }); 8. Namespace-Filter (optional)
Ein Bildschirm, der mehrere Namespaces rendert, kann das Panel auf den eingrenzen, der den Kunden interessiert — übergeben Sie einen optionalen namespace (string | string[]) am Trigger/an der Konfiguration (feedbackPlugin() für React/Native, createFeedback() für Vue/Svelte, resolveKeys() / filterByNamespace() für /core). Er wird nach der Eingrenzung auf angezeigte Schlüssel zusammengesetzt — angezeigt = angezeigt ∩ namespace. Nicht gesetzt, "" oder [] = kein Filter (wie zuvor). Er fällt niemals auf das gesamte Projekt zurück.
namespace.ts 1// §0d — OPTIONAL namespace filter (customer feature).2// Composes AFTER rendered-scoping: shown = rendered ∩ namespace.3feedbackPlugin({ controllerRef: feedback, namespace: "quiz" }); 5// Vue / Svelte — same option on createFeedback:6createFeedback({ apiBase, projectId, language, namespace: ["quiz"] }); 8// /core — resolveKeys / filterByNamespace:9resolveKeys(explicit, "quiz"); // or filterByNamespace(keys, "quiz") 11// unset / "" / [] ⇒ no filter (identical to v5). 9. Serverseitig erstellte Sitzung (alle Frameworks)
Der Sitzungs-/Gruppierungsschlüssel wird serverseitig erstellt bei der Einwilligung. Der Client sendet oder generiert ihn niemals — es gibt keine groupingKey-Konfiguration und kein Request-Feld. Bei acceptTos() gibt das Backend ihn zurück (gebunden an das eingeschränkte JWT); jeder Adapter stellt ihn schreibgeschützt über client.sessionId bereit. Ein wiederkehrender endUserId behält seinen stabilen Server-Wert; ein neuer Endnutzer erhält ein frisches sess_….
consent.ts 1// session/grouping key is MINTED SERVER-SIDE at consent2await client.acceptTos(); // POST /v1/feedback/tos3client.sessionId; // read-only, e.g. "sess_018f…" 5// NO groupingKey config, NO request field —6// the client never sends or self-generates the session. 10. Einwilligung und Sicherheit (automatisch)
Vor dem ersten Schreibvorgang akzeptiert der Endnutzer die versionierten Sonenta-Endnutzer-AGB. Das SDK erwirbt anschließend ein kurzlebiges JWT, das ausschließlich auf den Scope feedback:write beschränkt ist — kryptografisch getrennt von Ihrer Kunden-Authentifizierung — und erneuert es transparent. Endnutzer sind anonym (opake ID, keine PII). Sie müssen sicherheitsseitig nichts implementieren.
Was Sie kostenlos erhalten
- Null Host-Re-Render. React/Native laufen als isoliertes Geschwister-Blatt des i18n-Providers; Vue/Svelte halten den Open-State in ihrem eigenen Store. Das Hinzufügen oder Öffnen von Feedback re-rendert Ihre App niemals.
- Einwilligung + Server-Sitzung übernommen. AGB-Akzeptanz, serverseitig erstellte Sitzung, JWT-Erwerb, rotierende Erneuerung und ein einmaliger transparenter Retry bei 401 — alles innerhalb des SDK. Es wirft niemals eine Exception in Ihren Render-Pfad.
- Debounce-ter, gebündelter Transport. Bewertungen und Vorschläge werden eingereiht und auf einem Debounce (standardmäßig 1,5 s), bei einer maximalen Batch-Größe oder beim Schließen gesendet. Best-Effort: ein fehlgeschlagener Batch wird einmal erneut eingereiht und dann verworfen.
- Moderation vor der Veröffentlichung. Nichts, was ein Endnutzer einreicht, geht automatisch live. Vorschläge landen als
pendingin der Moderationswarteschlange Ihres Dashboards — Sie genehmigen, lehnen ab oder wenden sie über den normalen auditierten Bearbeitungspfad an. Bewertungen werden in einem Echtzeit-Dashboard pro Schlüssel / pro Sprache aggregiert.