Framework integration guide

Documentation index for the SDK: docs/README.md.

This document explains how to use @unolio/sdk with React, Next.js, Vite, Vue, Preact, and Svelte. It also answers whether you need a separate SDK per framework.

Do you need one SDK per framework?

No. The same package ships a framework-agnostic core (createClient from @unolio/sdk) that works anywhere modern JavaScript runs (browser with fetch, Node 18+, etc.).

  • @unolio/sdk — always use this for the translation client (t, preload, setLanguage, etc.).
  • @unolio/sdk/react — optional helpers for React only: UnolioProvider, useUnolioClient, <Trans>, parseRichMessage. These are thin wrappers around React Context and hooks.

For Vue, Svelte, or plain usage, you do not need a second npm package unless you choose to publish your own @your-org/unolio-vue later. The pattern is always:

  1. Create one createClient(...) instance (module scope or dependency-injection container).
  2. Call setLanguage and preload when the active locale changes (often in a root layout / onMounted / route change).
  3. Expose t (and any other client methods you need) to the tree via your framework’s context / provide / stores.

Optional future packages (@unolio/sdk-vue, etc.) would only be convenience — the core API stays one.


Shared concepts (all stacks)

TopicPractice
API key & base URLNever commit real keys. Use env vars (VITE_*, NEXT_PUBLIC_*, import.meta.env, process.env in Node).
CORSThe browser calls your baseUrl; that API must allow your app origin.
Initial loadAfter setLanguage(lang), call await client.preload(lang) before showing translated UI (or show a loading state until preload finishes).
Rich / ICU messagesCore + React: parseRichMessage and <Trans> are React-only today. Other frameworks can use client.t(key) for plain strings, or parse templates with your own component layer.
SSRIf the client runs only in the browser, keep the provider in a client-only boundary (see Next.js). For SSR of copy, you’d load messages on the server separately (out of scope here; core is client-oriented for fetch).

React (CRA, Vite + React, etc.)

Install:

npm install @unolio/sdk react

Typical pattern: one module-level client, a small provider that preloads on lang, and a useTranslation hook.

/* eslint-disable react-refresh/only-export-components -- i18n entry: provider + hook */
import { createClient } from '@unolio/sdk';
import { UnolioProvider, useUnolioClient } from '@unolio/sdk/react';
import { useState, useEffect, type ReactNode } from 'react';

const i18n = createClient({
  apiKey: import.meta.env.VITE_UNOLIO_API_KEY as string,
  baseUrl: import.meta.env.VITE_UNOLIO_BASE_URL as string,
});

export function I18nProvider({
  children,
  lang = 'de',
}: {
  children: ReactNode;
  lang?: string;
}) {
  const [ready, setReady] = useState(false);

  useEffect(() => {
    i18n.setLanguage(lang);
    i18n.preload(lang).then(() => setReady(true));
  }, [lang]);

  if (!ready) return <div>Loading…</div>;

  return <UnolioProvider client={i18n}>{children}</UnolioProvider>;
}

export function useTranslation() {
  const client = useUnolioClient();
  return { t: client.t.bind(client) };
}

Usage: wrap your app root with I18nProvider. Use useTranslation() for t('key'). For rich messages, use <Trans i18nKey="…" /> from @unolio/sdk/react (it reads the same client from context — do not pass client into Trans).


Next.js

Next splits Server Components vs Client Components. Anything that calls fetch to your API, holds useState/useEffect, or React Context must run on the client.

  1. Put I18nProvider (and any component using useTranslation / Trans) in a file marked 'use client' at the top.
  2. Prefix public env vars with NEXT_PUBLIC_ so they are available in the browser bundle, e.g. NEXT_PUBLIC_UNOLIO_API_KEY, NEXT_PUBLIC_UNOLIO_BASE_URL.
  3. In createClient, read those vars inside the client module (not from server-only secrets unless you proxy).

Example env usage:

const i18n = createClient({
  apiKey: process.env.NEXT_PUBLIC_UNOLIO_API_KEY!,
  baseUrl: process.env.NEXT_PUBLIC_UNOLIO_BASE_URL!,
});

Wrap layout.tsx or app/providers.tsx so children sit under I18nProvider. App Router and Pages Router both follow the same rule: provider = client component subtree.

If you must avoid exposing the API key to the browser, you cannot use the browser client directly with that key; you’d need a server-side proxy route that attaches credentials — that is an application architecture choice, not a separate SDK.


Vite

Vite is a bundler, not a framework. You integrate based on the template you chose:

TemplateFollow
Vite + ReactSame as React. Use import.meta.env.VITE_* for keys (must prefix with VITE_).
Vite + VueSame as Vue. Use import.meta.env.VITE_*.
Vite + SvelteSame as Svelte and SvelteKit.

Example .env:

VITE_UNOLIO_API_KEY=lk_your_key_here
VITE_UNOLIO_BASE_URL=https://your-api-domain.com

Vue 3

Install core only:

npm install @unolio/sdk

Create the client once (e.g. src/i18n/client.ts). Provide it from main.ts or a plugin, and expose a useI18n composable via inject.

// src/i18n/client.ts
import { createClient } from '@unolio/sdk';

export const unolio = createClient({
  apiKey: import.meta.env.VITE_UNOLIO_API_KEY as string,
  baseUrl: import.meta.env.VITE_UNOLIO_BASE_URL as string,
});

export const injectionKey = Symbol('unolio');
// src/i18n/plugin.ts
import type { App } from 'vue';
import { unolio, injectionKey } from './client';

export async function installI18n(app: App, lang: string) {
  unolio.setLanguage(lang);
  await unolio.preload(lang);
  app.provide(injectionKey, unolio);
}
// src/i18n/useI18n.ts
import { inject } from 'vue';
import { injectionKey } from './client';

export function useI18n() {
  const client = inject(injectionKey);
  if (!client) throw new Error('Unolio i18n not installed');
  return { t: client.t.bind(client), client };
}

Call installI18n(app, 'de') before app.mount (or await in an async bootstrap). You do not need @unolio/sdk/vue unless you later extract this into a published package.


Preact

Option A — preact/compat: Alias react and react-dom to Preact’s compat builds in your bundler so @unolio/sdk/react believes it is talking to React. Then use the same React provider and hooks as documented in the React section.

Option B — Preact-native: Use createClient from @unolio/sdk only and wire Preact Context (createContext / useContext) yourself, mirroring what UnolioProvider does. The API surface you need from the client is t, preload, setLanguage.

You do not need a separate npm SDK; you may need build aliases or a tiny local wrapper.


Svelte and SvelteKit

Use createClient from @unolio/sdk. For SvelteKit, initialize in +layout.ts / +layout.svelte (or a dedicated store module) so setLanguage + preload run when the locale changes.

Example with a writable “ready” flag and a thin t helper:

// src/lib/i18n.ts
import { createClient } from '@unolio/sdk';
import { writable } from 'svelte/store';

const client = createClient({
  apiKey: import.meta.env.VITE_UNOLIO_API_KEY,
  baseUrl: import.meta.env.VITE_UNOLIO_BASE_URL,
});

export const i18nReady = writable(false);

export async function initI18n(lang: string) {
  i18nReady.set(false);
  client.setLanguage(lang);
  await client.preload(lang);
  i18nReady.set(true);
}

export function t(key: string, vars?: Record<string, string | number>) {
  return client.t(key, vars);
}

In root layout, await initI18n('de') (or react to $page.params.lang). In components, import t from src/lib/i18n or bind a store. No separate Svelte SDK is required.


Summary

FrameworkPackages to installPattern
React@unolio/sdk + reactUnolioProvider + useUnolioClient / your useTranslation
Next.jssame as React'use client' + NEXT_PUBLIC_* env
Vitesame as chosen UIimport.meta.env.VITE_*
Vue 3@unolio/sdkprovide / inject + createClient
Preact@unolio/sdk (+ optional compat for @unolio/sdk/react)Alias to React adapter or manual context
Svelte@unolio/sdkmodule + stores / layout init

You do not need a distinct SDK product per framework for Unolio’s HTTP API — only one core and, for React, the optional @unolio/sdk/react subpath.

For UMD/script-tag HTML (no bundler), see the main README “Script tag” section.