Setup an app with Qwik Speak
npm install qwik-speak --save-dev
Add Qwik Speak Inline Vite plugin in vite.config.ts
:
import { qwikSpeakInline } from 'qwik-speak/inline';
export default defineConfig(() => {
return {
plugins: [
qwikCity(),
qwikVite(),
qwikSpeakInline({
supportedLangs: ['en-US', 'it-IT'],
defaultLang: 'en-US',
assetsPath: 'i18n'
}),
tsconfigPaths(),
],
};
});
Let's create speak-config.ts
and speak-functions.ts
files in src
folder:
src/speak-config.ts
import type { SpeakConfig } from 'qwik-speak';
export const config: SpeakConfig = {
defaultLocale: { lang: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' },
supportedLocales: [
{ lang: 'it-IT', currency: 'EUR', timeZone: 'Europe/Rome' },
{ lang: 'en-US', currency: 'USD', timeZone: 'America/Los_Angeles' }
],
// Translations available in the whole app
assets: [
'app'
],
// Translations with dynamic keys available in the whole app
runtimeAssets: [
'runtime'
]
};
src/speak-functions.ts
import { server$ } from '@builder.io/qwik-city';
import type { LoadTranslationFn, Translation, TranslationFn } from 'qwik-speak';
/**
* Translation files are lazy-loaded via dynamic import and will be split into separate chunks during build.
* Assets names and keys must be valid variable names
*/
const translationData = import.meta.glob<Translation>('/i18n/**/*.json');
/**
* Using server$, translation data is always accessed on the server
*/
const loadTranslation$: LoadTranslationFn = server$(async (lang: string, asset: string) =>
await translationData[`/i18n/${lang}/${asset}.json`]?.()
);
export const translationFn: TranslationFn = {
loadTranslation$: loadTranslation$
};
loadTranslation$
is a customizable QRL function: you can load the translation files in the way you prefer
For more details, see Translation functions
Add useQwikSpeak
provider in root.tsx
and pass it the configuration and the translation functions:
src/root.tsx
import { useQwikSpeak } from 'qwik-speak';
import { config } from "./speak-config";
import { translationFn } from "./speak-functions";
export default component$(() => {
/**
* Init Qwik Speak
*/
useQwikSpeak({ config, translationFn });
return (
<QwikCityProvider>
{/* ... */}
</QwikCityProvider>
);
});
Create plugin.ts
in the root of the src/routes
directory:
src/routes/plugin.ts
import type { RequestHandler } from '@builder.io/qwik-city';
import { config } from '../speak-config';
/**
* This middleware function must only contain the logic to set the locale,
* because it is invoked on every request to the server.
* Avoid redirecting or throwing errors here, and prefer layouts or pages
*/
export const onRequest: RequestHandler = ({ request, locale }) => {
const acceptLanguage = request.headers?.get('accept-language');
let lang: string | null = null;
// Try to use user language
if (acceptLanguage) {
lang = acceptLanguage.split(';')[0]?.split(',')[0];
}
// Check supported locales
lang = config.supportedLocales.find(value => value.lang === lang)?.lang || config.defaultLocale.lang;
// Set Qwik locale
locale(lang);
};
We're on the server here, and you can get the language from
acceptLanguage
, a cookie, or a URL parameter, as you like. But is mandatory to set the Qwik locale
Set the base URL for loading the chunks in the browser in entry.ssr.tsx
file:
import { isDev } from '@builder.io/qwik/build';
import type { RenderOptions } from "@builder.io/qwik/server";
import { config } from './speak-config';
/**
* Determine the base URL to use for loading the chunks in the browser.
* The value set through Qwik 'locale()' in 'plugin.ts' is saved by Qwik in 'serverData.locale' directly.
* Make sure the locale is among the 'supportedLocales'
*/
export function extractBase({ serverData }: RenderOptions): string {
if (!isDev && serverData?.locale) {
return '/build/' + serverData.locale;
} else {
return '/build';
}
}
export default function (opts: RenderToStreamOptions) {
return renderToStream(<Root />, {
manifest,
...opts,
// Determine the base URL for the client code
base: extractBase,
// Use container attributes to set attributes on the html tag
containerAttributes: {
lang: opts.serverData?.locale || config.defaultLocale.lang,
...opts.containerAttributes,
},
});
}