Vai al contenuto
Sonenta

SDK · Valutazione da parte dell'utente finale

Anteprima

@sonenta/feedback

Lasciate che i vostri utenti finali valutino (5★) e propongano traduzioni dall'interno della vostra app in produzione. Un pacchetto, cinque punti d'ingresso — /react, /native, /vue, /svelte, /core — stessa rete, stessa sessione generata lato server, stesso back office di moderazione. React e React Native si agganciano al provider @sonenta/*-i18n che già usate (nessun secondo contesto, nessun re-render dell'host); Vue e Svelte sono adattatori autonomi idiomatici. Disponibile come add-on a pagamento da Pro in su.

Il pacchetto @sonenta/feedback viene fornito con l'add-on «Valutazione delle traduzioni da parte dell'utente finale» al lancio V1 di Sonenta. Non è ancora su npm — il contratto di rete è congelato (v3); i binding dei framework si stanno stabilizzando e potrebbero ancora cambiare prima del lancio.

1. Installare (al lancio)

Un solo pacchetto. Importate il punto d'ingresso del vostro framework: @sonenta/feedback/react, /native (RN/Expo), /vue, /svelte o /core per il resto. vue / svelte sono peer dependency opzionali — solo il punto d'ingresso corrispondente ne ha bisogno. Pubblicato con l'add-on al lancio V1.

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) — plugin i18n

Aggiungete feedbackPlugin() allo slot plugins del vostro provider @sonenta/react-i18next (>= 0.7.0) esistente — nessun nuovo provider, nessun secondo contesto. Il provider chiama il setup() del plugin una sola volta e riutilizza i propri apiBase / projectId / defaultLocale. Il pannello viene montato come foglia sorella isolata con uno store privato di apertura/chiusura: aprirlo non causa mai un re-render del vostro albero host. Attivatelo dal vostro CTA tramite il controller fornito da controllerRef (oppure il callback onReady).

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>
Tutte le opzioni di feedbackPlugin() / createFeedback()
Opzione Tipo Predefinito
controllerRefRef<Controller>
onReady(c) => void
keysstring[]auto-discovered
flushDebounceMsnumber1500
maxBatchnumber20
defaultButtonbooleanfalse

3. React Native / Expo

Stesso schema dal punto d'ingresso /native: aggiungete feedbackPlugin() allo slot plugins dello stesso provider @sonenta/react-i18next nella vostra app Expo e attivatelo tramite il controller. Nessun modulo nativo aggiuntivo; la memorizzazione del token usa il secure store della piattaforma.

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 è un adattatore autonomo — config esplicita, nessun provider i18n da cui ereditare. createFeedback(config) restituisce { client, isOpen, controller, FeedbackPanel }. Montate <FeedbackPanel /> una volta vicino alla radice (Teleport su body) e chiamate controller.open() dal vostro CTA. Stesso stato di apertura isolato — non causa mai un re-render della vostra app.

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 è headless e idiomatico: createFeedback(config) restituisce store Svelte — isOpen (Writable), strings (Writable) — più open(), close(), loadStrings(), rate(), suggest(). Renderizzate il vostro pannello a partire dagli store; l'SDK gestisce trasporto, consenso e sessione server.

+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. Il resto — /core

@sonenta/feedback/core espone il FeedbackClient congelato su cui sono costruiti tutti gli adattatori: acceptTos(), loadStrings(), rate(), suggest(), trasporto con debounce e batching, JWT a rotazione. Usatelo direttamente per qualsiasi framework privo di adattatore first-party.

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. Restrizione alle chiavi mostrate (automatica)

Il pannello si restringe automaticamente alle chiavi effettivamente mostrate nella vista corrente, tramite il registro globale delle chiavi prodotto dall'SDK @sonenta/*-i18n — nessuna configurazione. Passate un array keys esplicito solo come ripiego (es. stringhe non provenienti da @sonenta/*-i18n); non passate mai l'intero catalogo — esporrebbe tutte le stringhe dell'app, non quelle che l'utente sta guardando. Il registro è tracciato al montaggio e conteggiato per riferimento: le stringhe persistenti sempre a schermo (un'intestazione, un eyebrow) restano registrate finché il loro componente è montato — nessun reset per vista. (reset() esiste solo come via di fuga per casi limite di routing non-React; l'SDK non lo chiama mai automaticamente.)

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. Filtro di namespace (opzionale)

Una schermata che renderizza più namespace può restringere il pannello a quello che interessa al cliente — passate un namespace opzionale (string | string[]) sul trigger/config (feedbackPlugin() per React/Native, createFeedback() per Vue/Svelte, resolveKeys() / filterByNamespace() per /core). Si compone dopo la restrizione alle chiavi mostrate — mostrato = mostrato ∩ namespace. Non impostato, "" o [] = nessun filtro (come prima). Non ripiega mai sull'intero progetto.

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. Sessione generata lato server (tutti i framework)

La chiave di sessione / raggruppamento è generata lato server al momento del consenso. Il client non la invia né la genera mai — nessuna config groupingKey, nessun campo di richiesta. Su acceptTos() il backend la restituisce (legata al JWT con scope ristretto); ogni adattatore la espone in sola lettura tramite client.sessionId. Un endUserId di ritorno conserva il suo valore server stabile; un nuovo utente ottiene un sess_… nuovo.

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. Consenso e sicurezza (automatici)

Prima della prima scrittura, l'utente finale accetta i Termini di servizio Sonenta per utente finale, versionati. L'SDK ottiene quindi un JWT a breve durata limitato allo scope feedback:write — crittograficamente separato dalla vostra auth cliente — e lo rinnova in modo trasparente. Gli utenti finali sono anonimi (id opaco, nessun dato personale). Non dovete scrivere nulla lato sicurezza.

Cosa ottenete gratuitamente

Avanti