How to implement localization in Qwik framework with Qwik Speak?

I'm trying to implement localization in Qwik framework with Qwik Speak but i'm getting the following error when trying to resolve locale:

Internal server error: locale is not a function

I'm following the instructions in the Qwik Speak docs.

  1. Created the src/speak-config.ts file
  2. Added QwikSpeakProvider to the src/root.tsx
  3. Added the onRequest function to the src/routes/layout.tsx
  4. Created the json files: public/i18n/en-US/app.json and public/i18n/it-IT/app.json

But still getting the error on the locale(lang || config.defaultLocale.lang); call in the src/routes/layout.tsx.

My src/speak-config.ts:

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' }
  ],
  assets: [
    'app' // Translations shared by the pages
  ]
};

export const loadTranslation$: LoadTranslationFn = $(async (lang: string, asset: string, origin?: string) => {
  let url = '';
  // Absolute urls on server
  if (isServer && origin) {
    url = origin;
  }
  url += `/i18n/${lang}/${asset}.json`;
  const response = await fetch(url);

  if (response.ok) {
    return response.json();
  }
  else if (response.status === 404) {
    console.warn(`loadTranslation$: ${url} not found`);
  }
});

export const translationFn: TranslationFn = {
  loadTranslation$: loadTranslation$
};

My src/root.tsx:

export default component$(() => {
  useStyles$(globalStyles);

  return (
    <QwikSpeakProvider config={config} translationFn={translationFn}>
      <QwikCityProvider>
        <head>
          <meta charSet="utf-8" />
          <link rel="manifest" href="/manifest.json" />
          <QwikPartytown forward={["dataLayer.push"]} />
          <RouterHead />
        </head>
        <body lang="en">
          <RouterOutlet />
          <ServiceWorkerRegister />
        </body>
      </QwikCityProvider>
    </QwikSpeakProvider>
  );
});

My src/routes/layout.tsx:

export default component$(() => {
  return (
    <>
      <Header />
      <main>
        <section>
          <Slot />
        </section>
      </main>
      <Footer />
    </>
  );
});

export const onRequest: RequestHandler = ({ request, locale }) => {
  const cookie = request.headers?.get("cookie");
  const acceptLanguage = request.headers?.get("accept-language");

  let lang: string | null = null;
  // Try whether the language is stored in a cookie
  if (cookie) {
    const result = new RegExp(
      "(?:^|; )" + encodeURIComponent("locale") + "=([^;]*)"
    ).exec(cookie);
    if (result) {
      lang = JSON.parse(result[1])["lang"];
    }
  }
  // Try to use user language
  if (!lang) {
    if (acceptLanguage) {
      lang = acceptLanguage.split(";")[0]?.split(",")[0];
    }
  }

  // Set Qwik locale
  locale(lang || config.defaultLocale.lang);
};

Upvotes: 3

Views: 651

Answers (2)

Aur&#233;lien B.
Aur&#233;lien B.

Reputation: 517

From what I read it seems you are missing the step to create the function.

/**
 * Translation files are lazy-loaded via dynamic import and will be split into separate chunks during build.
 * 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$
};

You can follow the step by step guide here: https://github.com/robisim74/qwik-speak/blob/main/docs/tutorial-routing.md

Upvotes: 0

Osaid Alhomedy
Osaid Alhomedy

Reputation: 1

Move this piece of code to a new file src/routes/plugin.ts

export const onRequest: RequestHandler = ({ request, locale }) => {
  const cookie = request.headers?.get("cookie");
  const acceptLanguage = request.headers?.get("accept-language");

  let lang: string | null = null;
  // Try whether the language is stored in a cookie
  if (cookie) {
    const result = new RegExp(
      "(?:^|; )" + encodeURIComponent("locale") + "=([^;]*)"
    ).exec(cookie);
    if (result) {
      lang = JSON.parse(result[1])["lang"];
    }
  }
  // Try to use user language
  if (!lang) {
    if (acceptLanguage) {
      lang = acceptLanguage.split(";")[0]?.split(",")[0];
    }
  }

  // Set Qwik locale
  locale(lang || config.defaultLocale.lang);
};

Upvotes: 0

Related Questions