Przejdź do treści
Sonenta

SDK · Ocena przez użytkownika końcowego

Wersja zapowiadająca

@sonenta/feedback

Pozwól swoim użytkownikom końcowym oceniać (5★) i proponować tłumaczenia z wnętrza wdrożonej aplikacji. Jeden pakiet, pięć punktów wejścia — /react, /native, /vue, /svelte, /core — ta sama warstwa sieciowa, ta sama sesja generowana po stronie serwera, to samo zaplecze moderacji. React i React Native podpinają się do providera @sonenta/*-i18n, którego już używasz (bez drugiego kontekstu, bez ponownego renderowania hosta); Vue i Svelte to idiomatyczne, samodzielne adaptery. Dostępne jako płatny dodatek od Pro w górę.

Pakiet @sonenta/feedback jest dostarczany wraz z dodatkiem „Ocena tłumaczeń przez użytkownika końcowego” przy starcie V1 Sonenta. Nie ma go jeszcze na npm — kontrakt sieciowy jest zamrożony (v3); bindingi frameworków się stabilizują i mogą jeszcze ulec zmianie przed startem.

1. Instalacja (przy starcie)

Jeden pakiet. Zaimportuj punkt wejścia swojego frameworka: @sonenta/feedback/react, /native (RN/Expo), /vue, /svelte lub /core dla wszystkiego innego. vue / svelte to opcjonalne peer deps — potrzebuje ich tylko odpowiedni punkt wejścia. Publikowany wraz z dodatkiem przy starcie 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

Dodaj feedbackPlugin() do slotu plugins w istniejącym providerze @sonenta/react-i18next (>= 0.7.0) — bez nowego providera, bez drugiego kontekstu. Provider wywołuje setup() pluginu raz i wykorzystuje ponownie własne apiBase / projectId / defaultLocale. Panel montuje się jako izolowany liść siostrzany z prywatnym storem otwarcia/zamknięcia, więc jego otwarcie nigdy nie renderuje ponownie Twojego drzewa hosta. Wyzwalaj z własnego CTA za pomocą kontrolera dostarczanego przez controllerRef (lub callbacka 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>
Wszystkie opcje feedbackPlugin() / createFeedback()
Opcja Typ Domyślnie
controllerRefRef<Controller>
onReady(c) => void
keysstring[]auto-discovered
flushDebounceMsnumber1500
maxBatchnumber20
defaultButtonbooleanfalse

3. React Native / Expo

Identyczny wzorzec z punktu wejścia /native: dodaj feedbackPlugin() do slotu plugins tego samego providera @sonenta/react-i18next w swojej aplikacji Expo i wyzwalaj przez kontroler. Bez dodatkowych modułów natywnych; przechowywanie tokenu korzysta z secure store platformy.

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 to samodzielny adapter — jawna konfiguracja, brak providera i18n do dziedziczenia. createFeedback(config) zwraca { client, isOpen, controller, FeedbackPanel }. Zamontuj <FeedbackPanel /> raz blisko korzenia (Teleport do body) i wywołaj controller.open() z własnego CTA. Ten sam izolowany stan otwarcia — nigdy nie renderuje ponownie Twojej aplikacji.

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 jest headless i idiomatyczny: createFeedback(config) zwraca store'y Svelte — isOpen (Writable), strings (Writable) — plus open(), close(), loadStrings(), rate(), suggest(). Renderujesz własny panel ze store'ów; SDK obsługuje transport, zgodę i sesję serwerową.

+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. Wszystko inne — /core

@sonenta/feedback/core udostępnia zamrożony FeedbackClient, na którym zbudowane są wszystkie adaptery: acceptTos(), loadStrings(), rate(), suggest(), transport z debouncingiem i batchowaniem, rotujący JWT. Używaj go bezpośrednio dla dowolnego frameworka bez adaptera 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. Ograniczanie do wyświetlanych kluczy (automatyczne)

Panel automatycznie ogranicza się do kluczy faktycznie wyświetlanych w bieżącym widoku, dzięki globalnemu rejestrowi kluczy tworzonemu przez SDK @sonenta/*-i18n — bez konfiguracji. Jawną tablicę keys przekazuj tylko jako rozwiązanie awaryjne (np. teksty niepochodzące z @sonenta/*-i18n); nigdy nie przekazuj całego katalogu — ujawniłoby to każdy tekst w aplikacji, a nie te, na które patrzy użytkownik. Rejestr jest śledzony przy montowaniu i liczony przez referencje: trwałe teksty stale obecne na ekranie (nagłówek, eyebrow) pozostają zarejestrowane, dopóki ich komponent jest zamontowany — nie ma resetu na widok. (reset() istnieje wyłącznie jako furtka awaryjna dla brzegowych przypadków routingu spoza React; SDK nigdy nie wywołuje go automatycznie.)

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. Filtr namespace (opcjonalny)

Ekran renderujący wiele namespace'ów może ograniczyć panel tylko do tego, na którym zależy klientowi — przekaż opcjonalny namespace (string | string[]) na triggerze/konfiguracji (feedbackPlugin() dla React/Native, createFeedback() dla Vue/Svelte, resolveKeys() / filterByNamespace() dla /core). Składa się po ograniczeniu do wyświetlanych kluczy — pokazane = wyświetlone ∩ namespace. Brak wartości, "" lub [] oznacza brak filtra (identycznie jak wcześniej). Nigdy nie wraca do całego projektu.

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. Sesja generowana po stronie serwera (wszystkie frameworki)

Klucz sesji / grupowania jest generowany po stronie serwera w momencie wyrażenia zgody. Klient nigdy go nie wysyła ani nie generuje samodzielnie — nie ma konfiguracji groupingKey ani pola żądania. Przy acceptTos() backend go zwraca (powiązany z ograniczonym JWT); każdy adapter udostępnia go w trybie tylko do odczytu jako client.sessionId. Powracający endUserId zachowuje swoją stabilną wartość serwerową; nowy użytkownik otrzymuje świeży 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. Zgoda i bezpieczeństwo (automatyczne)

Przed pierwszym zapisem użytkownik końcowy akceptuje wersjonowane warunki korzystania dla użytkownika końcowego Sonenta. SDK pozyskuje następnie krótkotrwały JWT o zakresie wyłącznie feedback:write — kryptograficznie oddzielony od uwierzytelniania Twoich klientów — i rotuje go w sposób przezroczysty. Użytkownicy końcowi są anonimowi (nieprzejrzysty identyfikator, brak danych osobowych). Po stronie bezpieczeństwa nie musisz pisać nic.

Co dostajesz za darmo

Dalej