Qwik / Qwik City
ShipEasyI18n integration for Qwik and Qwik City — useStore integration, Qwik City routeLoader$, and resumable hydration with zero client-side fetch.
Package: @i18n/qwik
Install
npm install @i18n/qwik
Script tag
Add the loader to src/root.tsx:
// src/root.tsx
export default component$(() => {
return (
<QwikCityProvider>
<head>
<script
src="https://cdn.i18n.shipeasy.ai/v1/loader.js"
data-key="i18n_pk_your_key_here"
data-profile="en:prod"
/>
</head>
<body>
<RouterOutlet />
</body>
</QwikCityProvider>
);
});
useShipEasyI18nProvider and useStore integration
Initialise the ShipEasyI18n store at the root component level so all child components can access labels without re-fetching:
// src/root.tsx
import { component$, useStore } from '@builder.io/qwik';
import { useShipEasyI18nProvider } from '@i18n/qwik';
export default component$(() => {
const i18n = useShipEasyI18nProvider({ profile: 'en:prod' });
return (
<QwikCityProvider>
<RouterOutlet />
</QwikCityProvider>
);
});
useShipEasyI18n() in components
// src/components/NavBar.tsx
import { component$ } from '@builder.io/qwik';
import { useShipEasyI18n } from '@i18n/qwik';
export const NavBar = component$(() => {
const { t, ready } = useShipEasyI18n();
return (
<nav>
<a href="/" data-label="nav.home">{t('nav.home')}</a>
<a href="/account" data-label="nav.account">{t('nav.account')}</a>
</nav>
);
});
Qwik City routeLoader$
Use routeLoader$ to fetch labels on the server and serialize them into the resumable state — the client never makes a separate labels request:
// src/routes/layout.tsx
import { routeLoader$ } from '@builder.io/qwik-city';
import { fetchLabels } from '@i18n/qwik/server';
export const useShipEasyI18nData = routeLoader$(async ({ cookie }) => {
const profile = cookie.get('i18n_profile')?.value ?? 'en:prod';
return fetchLabels({
i18nKey: process.env.ShipEasyI18n_KEY!,
profile,
chunk: 'index',
});
});
Pass the loader result to ShipEasyI18nProvider:
// src/routes/layout.tsx
import { component$ } from '@builder.io/qwik';
import { ShipEasyI18nProvider } from '@i18n/qwik';
export default component$(() => {
const i18nData = useShipEasyI18nData();
return (
<ShipEasyI18nProvider initialData={i18nData.value}>
<Slot />
</ShipEasyI18nProvider>
);
});
Because Qwik serializes component state into the HTML, label data loaded in routeLoader$ is available instantly on resumption — no hydration fetch needed.
For the full implementation spec including package source code and edge cases, see plans/frameworks/qwik.md in the repository.
Nuxt 3
ShipEasyI18n integration for Nuxt 3 — useShipEasyI18n() composable, nuxt.config.ts module registration, and server-side $i18n.t() in API routes.
Ruby on Rails
ShipEasyI18n integration for Ruby on Rails — i18n_t() view helper, layout script tag, Hotwire/Turbo compatibility, and i18n.config.json for ERB scanning.