Ir para o conteúdo
Sonenta

SDK · Avaliação pelo utilizador final

Pré-visualização

@sonenta/feedback

Deixe os seus próprios utilizadores finais classificarem (5★) e sugerirem traduções a partir da app em produção. Um pacote, cinco pontos de entrada — /react, /native, /vue, /svelte, /core — mesma rede, mesma sessão gerada no servidor, mesmo back office de moderação. React e React Native ligam-se ao provider @sonenta/*-i18n que já utiliza (sem segundo contexto, sem re-render do host); Vue e Svelte são adaptadores autónomos idiomáticos. Disponível como add-on pago a partir do Pro.

O pacote @sonenta/feedback é disponibilizado com o add-on «Avaliação de traduções pelo utilizador final» no lançamento V1 da Sonenta. Ainda não está no npm — o contrato de rede está congelado (v3); os bindings de frameworks estão a estabilizar e podem ainda evoluir antes do lançamento.

1. Instalar (no lançamento)

Um único pacote. Importe o ponto de entrada do seu framework: @sonenta/feedback/react, /native (RN/Expo), /vue, /svelte, ou /core para o resto. vue / svelte são peer deps opcionais — apenas o ponto de entrada correspondente precisa delas. Publicado com o add-on no lançamento 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

Adicione feedbackPlugin() ao slot plugins do seu provider @sonenta/react-i18next (>= 0.7.0) existente — sem novo provider, sem segundo contexto. O provider chama o setup() do plugin uma vez e reutiliza os seus próprios apiBase / projectId / defaultLocale. O painel é montado como uma folha irmã isolada com um store privado de abrir/fechar, pelo que abri-lo nunca faz re-render da sua árvore host. Despolete a partir do seu próprio CTA através do controlador fornecido por controllerRef (ou pelo 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>
Todas as opções de feedbackPlugin() / createFeedback()
Opção Tipo Por omissão
controllerRefRef<Controller>
onReady(c) => void
keysstring[]auto-discovered
flushDebounceMsnumber1500
maxBatchnumber20
defaultButtonbooleanfalse

3. React Native / Expo

Mesmo padrão a partir do ponto de entrada /native: adicione feedbackPlugin() ao slot plugins do mesmo provider @sonenta/react-i18next na sua app Expo e despolete através do controlador. Sem módulos nativos adicionais; o armazenamento do token usa o secure store da plataforma.

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 é um adaptador autónomo — config explícita, sem provider i18n do qual herdar. createFeedback(config) devolve { client, isOpen, controller, FeedbackPanel }. Monte <FeedbackPanel /> uma vez perto da raiz (faz Teleport para body) e chame controller.open() a partir do seu próprio CTA. O mesmo estado de abertura isolado — nunca faz re-render da sua 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 idiomático: createFeedback(config) devolve stores Svelte — isOpen (Writable), strings (Writable) — mais open(), close(), loadStrings(), rate(), suggest(). O painel é renderizado por si a partir dos stores; o SDK trata do transporte, do consentimento e da sessão de servidor.

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

@sonenta/feedback/core expõe o FeedbackClient congelado sobre o qual todos os adaptadores são construídos: acceptTos(), loadStrings(), rate(), suggest(), transporte com debounce e em lote, JWT rotativo. Use-o diretamente para qualquer framework sem adaptador 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. Delimitação às chaves apresentadas (automática)

O painel delimita-se automaticamente às chaves efetivamente apresentadas na vista atual, através do registo global de chaves produzido pelo SDK @sonenta/*-i18n — sem configuração. Passe um array keys explícito apenas como recurso de reserva (p. ex. strings que não provêm de @sonenta/*-i18n); nunca passe todo o seu catálogo — isso exporia todas as strings da app, e não as que o utilizador está a ver. O registo é rastreado no montar e contado por referência: strings persistentes sempre no ecrã (um cabeçalho, um eyebrow) permanecem registadas enquanto o seu componente estiver montado — não há reset por vista. (reset() existe apenas como válvula de escape para casos limite de routing não-React; o SDK nunca o chama 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 de namespace (opcional)

Um ecrã que apresenta vários namespaces pode delimitar o painel apenas àquele que interessa ao cliente — passe um namespace opcional (string | string[]) no trigger/config (feedbackPlugin() para React/Native, createFeedback() para Vue/Svelte, resolveKeys() / filterByNamespace() para /core). Compõe-se depois da delimitação às chaves apresentadas — apresentado = apresentado ∩ namespace. Por definir, "" ou [] = sem filtro (como antes). Nunca recorre a todo o projeto.

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. Sessão gerada no servidor (todos os frameworks)

A chave de sessão / agrupamento é gerada no servidor no momento do consentimento. O cliente nunca a envia nem a gera — não há config groupingKey nem campo de pedido. No acceptTos() o backend devolve-a (ligada ao JWT restrito); cada adaptador expõe-na em apenas leitura através de client.sessionId. Um endUserId recorrente mantém o seu valor estável de servidor; um novo utilizador final obtém um sess_… novo.

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. Consentimento e segurança (automático)

Antes da primeira escrita, o utilizador final aceita os Termos de Utilização para utilizador final da Sonenta, versionados. O SDK obtém então um JWT de curta duração limitado ao scope feedback:write — criptograficamente separado da autenticação do seu cliente — e renova-o de forma transparente. Os utilizadores finais são anónimos (id opaco, sem PII). Não tem nada a programar do lado da segurança.

O que obtém gratuitamente

A seguir