SDK · エンドユーザーによる評価
プレビュー@sonenta/feedback
エンドユーザー自身が、出荷済みのアプリの中から翻訳を評価(5★)し、提案できます。React と React Native は、すでに稼働している @sonenta/*-i18n プロバイダーに接続します(第二のコンテキストなし、ホストの再レンダリングなし)。それ以外はすべて、各バインディングがラップする凍結済みクライアント /core を経由します。同じ通信、同じサーバー生成セッション、同じモデレーション用バックオフィス。Pro 以上の有料アドオンとして提供。
@sonenta/feedback パッケージは、Sonenta V1 ローンチ時にエンドユーザー翻訳評価アドオンとともに提供されます。ワイヤコントラクトは凍結済み(v3)です。フレームワークのバインディングは現在も安定化中で、ローンチ前に変更される可能性があります。
1. インストール(ローンチ時)
パッケージは 1 つです。ご利用のフレームワーク向けのエントリーをインポートしてください:@sonenta/feedback/react、/native(RN/Expo)、/vue、/svelte、またはその他向けの /core です。vue / svelte はオプションの peer 依存であり、該当するエントリーのみが必要とします。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), i18n プラグイン
既存の @sonenta/react-i18next(>= 0.7.0)プロバイダーの plugins スロットに feedbackPlugin() を追加してください。新しいプロバイダーも第 2 のコンテキストも不要です。プロバイダーはプラグインの setup() を一度呼び出し、自身の apiBase / projectId / defaultLocale を再利用します。パネルは独立した兄弟リーフとしてマウントされ、開閉状態を保持する専用のストアを持つため、パネルを開いてもホストツリーが再レンダリングされることは決してありません。controllerRef 経由で提供されるコントローラー(または onReady コールバック)を使い、ご自身の CTA からトリガーしてください。
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> feedbackPlugin() / createFeedback() のすべてのオプション
| オプション | 型 | デフォルト |
|---|---|---|
| controllerRef | Ref<Controller> | , |
| onReady | (c) => void | , |
| keys | string[] | auto-discovered |
| flushDebounceMs | number | 1500 |
| maxBatch | number | 20 |
| defaultButton | boolean | false |
3. React Native / Expo
/native エントリーから同じパターンを使います。Expo アプリ内の同じ @sonenta/react-i18next プロバイダーの plugins スロットに feedbackPlugin() を追加し、コントローラー経由でトリガーします。追加のネイティブモジュールは不要で、トークンの保存にはプラットフォームのセキュアストアを使用します。
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. その他, /core
@sonenta/feedback/core は、すべてのアダプターの基盤となる確定済みの FeedbackClient を公開します:acceptTos()、loadStrings()、rate()、suggest()、デバウンス&バッチ化されたトランスポート、ローテーションする JWT です。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.dev",6 projectId: "proj_xxx", language: "fr",7 // REQUIRED. Without it, the first authenticated call8 // accepts the end-user ToS on your user's behalf.9 autoAcceptTos: false,10}); 12// show YOUR ToS step, and only once the user agrees:13await client.acceptTos(); // server mints the session14await client.loadStrings(); client.rate(/* … */); client.suggest(/* … */); 16// with autoAcceptTos:false, an unconsented authed call throws17// FeedbackError("not consented") instead of fabricating a record. 5. 表示中のキーへのスコープ設定(自動)
パネルは、@sonenta/*-i18n SDK が生成するグローバルなキーレジストリを通じて、現在のビューに実際に表示されているキーへ自動的にスコープを設定します。設定は不要です。明示的な keys 配列はフォールバックとしてのみ渡してください(例:@sonenta/*-i18n 由来でない文字列)。カタログ全体を渡してはいけません。それでは、ユーザーが見ている文字列だけでなく、アプリ内のすべての文字列が露出してしまいます。レジストリはマウント単位で追跡され、参照カウントされます。常に画面に表示される永続的な文字列(ヘッダーや eyebrow)は、そのコンポーネントがマウントされている間は登録されたままです。ビューごとのリセットはありません。(reset() は、React 以外のルーティングのエッジケース向けのエスケープハッチとしてのみ存在します。SDK が自動的に呼び出すことはありません。)
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"] }); 6. namespace フィルター(オプション)
複数の namespace をレンダリングする画面では、顧客が関心を持つものだけにパネルのスコープを絞れます。トリガー/設定にオプションの namespace(string | string[])を渡してください(React/Native では feedbackPlugin()、Vue/Svelte では createFeedback()、/core では resolveKeys() / filterByNamespace())。これは表示中のキーへのスコープ設定の後に合成されます。表示 = 表示中 ∩ namespace です。未設定、""、または [] はフィルターなしを意味します(従来と同じです)。プロジェクト全体にフォールバックすることは決してありません。
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). 7. サーバー側で発行されるセッション(全フレームワーク)
セッション/グルーピングキーは、同意時にサーバー側で発行されます。クライアントがこれを送信したり自ら生成したりすることは決してありません。groupingKey の設定もリクエストフィールドもありません。acceptTos() 時にバックエンドがこれを返し(スコープ付き JWT に紐づけられます)、各アダプターはこれを client.sessionId として読み取り専用で公開します。再訪する endUserId は安定したサーバー値を保持し、新しいエンドユーザーには新規の 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. 8. 同意とセキュリティ
バージョン管理された Sonenta エンドユーザー利用規約が、最初の書き込みの前段に置かれます。React および React Native のパネルでは、認証付きの呼び出しより前に規約ステップが表示され、acceptTos() を呼ぶのはエンドユーザー自身のタップです。文字列の取得は構造上、同意に紐づいています。/core を使う場合は、クライアントを autoAcceptTos: false で生成し、ユーザーが同意した後にのみ acceptTos() を呼んでください。そうしないと、最初の認証付き呼び出しがユーザーに代わって同意してしまいます。クライアントはその後、feedback:write のみにスコープされた短命の JWT を保持します。これはお客様の顧客認証とは暗号的に分離されており、透過的にローテーションされます。エンドユーザーは匿名です(不透明な id、PII なし)。 @sonenta/feedback 1.2.x 以前では、これが既定の動作です。autoAcceptTos: false を渡さないかぎり、クライアントは最初の認証付き呼び出しで同意してしまいます。バージョン 1.3.0 ではこの既定値が反転し、ユーザーに代わって同意する代わりに FeedbackError("not consented") を送出して安全に失敗します。
無料で得られるもの
- ホストの再レンダリングはゼロ。 React/Native は i18n プロバイダーから独立した兄弟リーフとして動作し、Vue/Svelte は開閉状態を独自のストアで保持します。フィードバックの追加や表示でアプリが再レンダリングされることは決してありません。
- 同意とサーバーセッションを処理済み。 利用規約への同意、サーバー側で発行されるセッション、JWT の取得、ローテーションする更新、401 時の透過的な 1 回のリトライ、これらすべてが SDK 内で行われます。レンダリングパスに例外を投げることは決してありません。
- デバウンス&バッチ化されたトランスポート。 評価と提案はキューに入れられ、デバウンス(デフォルト 1.5 秒)、最大バッチ到達時、またはクローズ時にフラッシュされます。ベストエフォートで、失敗したバッチは一度再キューされ、その後は黙って破棄されます。
- 公開前のモデレーション。 エンドユーザーが送信したものが自動的に公開されることはありません。提案はダッシュボードのモデレーションキューに
pendingとして届きます。通常の監査済み編集パスを通じて、承認、却下、または適用できます。評価はキーごと/言語ごとのリアルタイムダッシュボードに集計されます。