Giter Club home page Giter Club logo

qwik-speak's People

Contributors

ahnpnl avatar genox avatar mahmoudajawad avatar mhuretski avatar nelsonprsousa avatar robisim74 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

qwik-speak's Issues

usePlural extract issue

Hi everyone,

thank you so much for this awesome package.

if you have an optional value like this:

const number = useSignal<number>()
const p = usePlural()

return <div>{p(number.value ?? 0,'app.someKey')}</div>

It seems to me, you extract 0 as key here, which is wrong. This way extract is creating 0.json file for each language containing:

{
  "0": {
    "one": "",
    "other": ""
  }
}

I hope in the future I find some time to help you guys out, I really like the approach and except this small issue it works already quite fine.

New runtime assets are not loaded using Speak component when navigating between same route with diff params

Hi,
I have found something odd happening when going from /path/with/params/A to /path/with/params/B

Imagine a route with parameters.
This route uses Speak component in order to load runtimeAssets that depend on the route parameter.
SPA-navigating to the same route but with different params will not load the new assets.

I believe this useTask is not re-executed when the component does not change (not really understanding Qwik internals and what/when a component gets recreated)

Small example:

// /src/routes/path/with/params/[param]/index.tsx

export default component$(() => {
  const loc = useLocation();
  const asset = `build-runtime-asset-${loc.params.param}`; // <- if you console log this, you will see it changes on SPA navigation

  return (
    {/* The runtime assets are loaded only the first time */}
    <Speak runtimeAssets={[asset]}>
      <ComponentPage></ComponentPage>
    </Speak>
  )
});

Cannot build the project and Extraction of the json file are done with value from the other lang json file, not the default value.

To reproduce this error, I have created a simple qwik project at the following GitHub repository: https://github.com/DongwonTTuna/qwik-speak-ErrExample.git.

  1. Firstly, please check the json files for each language.
  2. Next, please run npm install && npm run dev to confirm that it works as expected.
  3. Then, please try running npm run build to confirm that an error occurs.
  4. Finally, please use npm run qwik-speak-extract to confirm that the contents of each json file are overwritten with values in a different language other than the default values. (this may need to run the command several times with original i18n files)

Thank you!

how can i update the runtime asset

all tranlate data are runtime asset
i want update the data for runtime json when the locale json has changed

I can now update the json when restarting the service, but I expect that no restart is required

Runtime assets seem not to work with DocumentHead

Hi Robi,

first I would like to thank you for this great contribution. I was thinking about building a translation library for Qwik myself, but then found yours.

Currently I face the issue that the title and the description of the DocumentHead seems not to be translated. I added the runtime.json to the runtimeAssets in the config, but it stills shows the placeholder.

Do I miss something here?

One side note I always hated about ngx-translate that it is not type-safe. I was thinking about what to add to qwik-speak to make that feasible. I have had an own solution for Angular that uses a distributed-translate-loader-approach. Maybe we could customize the useTranslate hook to give back a function t that expects a dot-seperated string which matches the keys from the json that is used in the current scope. Especially for large projects that might be a better solution. Drawback is that we could only use the default language, but we could implement an unittest that checks wether the structure of the jsons is equal over all languages.

What do you think?

Sebastian

Bug: Code(3): Only primitive and object literals can be serialized

Hello,

I currently have the error above when using the library.
"version": "0.14.0",
"qwik": "1.1.4",
"qwik-city": "1.1.4"

QWIK ERROR Error: Code(3): Only primitive and object literals can be serialized
at createError (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/core.mjs:108:17)
at logError (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/core.mjs:102:54)
at logErrorAndStop (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/core.mjs:112:17)
at qError (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/core.mjs:185:12)
at eval (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/core.mjs:2639:15)
at Array.map ()
at Module._pauseFromContexts (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/core.mjs:2603:32)
at beforeClose (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/server.mjs:451:52)
at eval (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/core.mjs:3626:28)
at eval (D:/Zankel-Engineering/webpage/zankel-engineering/node_modules/@builder.io/qwik/core.mjs:4111:25) [Function: translate]

Will try to update the lib, but I guess I have nearly the latest version. Do you have an idea what that is coming from?

I get this warning before:

Qwik Speak warn Locale not resolved. Fallback to default locale: de-DE

Sebastian

Translation not working when deployed to node express instance

Hello.

I'm using the latest version of qwik and qwik-speak.
Qwik-speak was configured using the quick start guide and works great locally, but when I build and deploy to a node express server, the translation breaks when navigating to another page via Link (SPA).

Could you help me?

Improve unit test DX with test utilities and documentation

Issue

Currently there is no documentation how to unit test a Qwik component using qwik-speak and no test utilities either.

Example unit tests

Reference https://dev.to/manuartero/testing-a-react-context-provider-5cfg

  • Given a component TestComponent.tsx like below
import { component$ } from '@builder.io/qwik';
import { $translate } from 'qwik-speak';

export const TestComponent = component$(() => {
    return <h1>{$translate('banana_key')}</h1>;
});
  • Given speak-config.ts like below
import { $ } from '@builder.io/qwik';
import { isServer } from '@builder.io/qwik/build';
import type { LoadTranslationFn, SpeakConfig, TranslationFn } from 'qwik-speak';

export const speakConfig: SpeakConfig = {
    defaultLocale: { lang: 'nl-NL', currency: 'EUR', timeZone: 'Europe/Amsterdam' },
    supportedLocales: [
        { lang: 'nl-NL', currency: 'EUR', timeZone: 'Europe/Amsterdam' },
        { lang: 'en-US', currency: 'EUR', timeZone: 'Europe/Amsterdam' },
    ],
    assets: ['common'],
};

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

        return data.json();
    }

    return Promise.resolve();
});

export const translationFn: TranslationFn = {
    loadTranslation$,
};
  • We have a unit test
it('should translate', async () => {
        const Wrapper = component$(() => {
            /**
             * There are 2 choices here:
             * - Either developers would provide a stub loadTranslationFn
             * - Or in `speak-config.ts`, developers need to add extra logic to ensure translations are loaded in test environment
             */
            const loadTranslationStub$ = $(() => {
                // We can make this to return a JSON file as well
                return Promise.resolve({
                    banana_key: 'banana',
                });
            });

            return (
                <QwikSpeak
                    config={speakConfig}
                    translationFn={{
                        loadTranslation$: loadTranslationStub$,
                    }}
                >
                    <TestComponent />
                </QwikSpeak>
            );
        });
        const { screen, render } = await createDOM();

        await render(<Wrapper />);

        expect(screen.querySelector('h1')?.textContent).toBe('banana');
    });

Explanation

  • We don't mock context provider but we simply provide a wrapper around the component which uses qwik-speak. The wrapper component would be like Wrapper in the example.
  • To ensure translations are loaded, developers need to provide proper implementation for loadTranslation$ property of translationFn, see the example above.

Suggestion

From the discussion at f7d5920#r98961952, I think there should be:

  • documentation added for unit test
  • test utilities

Maybe qwik-speak can expose a wrapper component for unit test which provides:

  • Possibility to have children component so that any components use qwik-speak can be the children of it which allows them to access SpeakContext
  • A recommended example to define loadTranslation$ in such a way that it would work for dev, prod as well as test

Internal server error: Code(20): Calling a 'use*()' method outside component$...

The whole message is:
Internal server error: Code(20): Calling a 'use*()' method outside 'component$(() => { HERE })' is not allowed. 'use*()' methods provide hooks to the 'component$' state and lifecycle, ie 'use' hooks can only be called synchronously within the 'component$' function or another 'use' method. For more information see: https://qwik.builder.io/docs/components/tasks/#use-method-rules

and stack trace points to "placeholder attribute prop"
I am using "qwik-speak": "^0.13.0" but it started in previous versions.

<Input
     // this does not work any more
     placeholder={t('app.enterYourEmail@@Enter your email')}
/>`
`

but this is ok

`const inputPlaceholderMsg = t('app.enterYourEmail@@Enter your email');

<Input
   placeholder={inputPlaceholderMsg}
/>`

how to inline translate in Zod schema?

I wonder how to useTranslate out of component$

/* eslint-disable @typescript-eslint/no-unused-vars */
import { $, component$ } from '@builder.io/qwik';
import { routeLoader$, z } from '@builder.io/qwik-city';
import type { InitialValues, SubmitHandler } from '@modular-forms/qwik';
import { formAction$, useForm, zodForm$ } from '@modular-forms/qwik';

const loginSchema = z.object({
  email: z
    .string()
    .min(1, 'Please enter your email.') // =====> how to get localized message  out of component ?
    .email('The email address is badly formatted.'),
  password: z
    .string()
    .min(1, 'Please enter your password.')
    .min(8, 'You password must have 8 characters or more.'),
});
type LoginForm = z.infer<typeof loginSchema>;

export const useFormLoader = routeLoader$<InitialValues<LoginForm>>(() => ({
  email: '',
  password: '',
}));

// loginSchema can not move into component$ because useFormLoader refers loginSchema and should exported see https://qwik.builder.io/docs/route-loader/

export default component$(() => {
  const [loginForm, { Form, Field }] = useForm<LoginForm>({
    validate: zodForm$(loginSchema),
  });
 return <Form></Form>;
});

inlineTranslate function needs to get locale context , also not work out of component

build error with @builder.io/[email protected] or 0.19.2

app build fails after upgrading @builder.io/qwik to 0.19.1 or 0.19.2

error
[vite] Internal server error: 'get' on proxy: property 'defaultLocale' is a read-only and non-configurable data property on the proxy target but the proxy did not return its actual value (expected '#<Object>' but got '#<Object>')

🩹 Problem with translations in arrays when rendering on client

Hi @robisim74,

First of all, thank you very much for all your effort and for offering us Qwik Speak.

When my component listings are rendered on the client while navigating through Qwik City's Link, do I need to include the runtimeAssets prop for it to work correctly?

The problem I encounter is that by adding runtimeAssets, the waiting time between page transitions increases significantly. In fact, I believe that currently it would take less time to query the page to the server than it takes for the resource to reach the browser and for Qwik Speak to perform the translations.

I'll leave a test repository here along with the corresponding deployments.

deploy without runtimeAssets -> https://speak-spa-runtime.vercel.app/
deploy with runtimeAssets -> https://speak-spa-runtime-git-withruntimeassets-joshxy.vercel.app/
Repo -> https://github.com/devagja/speak-spa-runtime

Thank you very much for everything!

Display [object Object] when I pass it an anchor as a parameter

Hello!

I am using this code in my app

{t('app.hello@@Hello, visit my website {{link}}', { link: <a href="https://google.com/">Google</a> })}

but that translate this:

'Hello, visit my website [object Object]'

What am I doing wrong? What is the correct way?

Thanks

Cannot read properties of undefined (reading 'value')

Hi! I'm using qwik-speak with the inline plugin, and I'm getting the following error when building for production:
It only fails with version 0.12.1, and works with previous version

computing gzip size (0)...[vite-plugin-qwik-speak-inline] Cannot read properties of undefined (reading 'value')
✓ built in 3.56s
error during build:
TypeError: Cannot read properties of undefined (reading 'value')
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1731)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1686)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1686)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1686)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1686)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1686)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1686)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1907)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1686)
    at $ (/home/juan/Projects/every/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/qwik-speak/inline/index.cjs:6:1686)
 ELIFECYCLE  Command failed with exit code 1.
 ELIFECYCLE  Command failed with exit code 1.

Translating in loops within template doesn't work

I'm attempting to dynamically load values and then translate them in a loop within template as to offer a select menu with dynamic options. Take following example:

// i18n/LANG/app.json
{
  "termA": "Value for term A",
  "termB": "Value for term B",
  "termC": "Value for term C",
// componens.tsx
const TERMS = ["A", "B", "C"];

return (
  <select>
    {TERMS.map((term) => <option>{translate(`term${term`)}</option>)}
  </select>
);

The end results show up the terms without being translated. I tested this scenario in qwik-speak 0.0.5-0.0.8 and it was consistent.

Workaround

As to workaround this problem, I found translating the values outside of template, in a loop, does work such as:

// const TERMS...
const VALUES = TERMS.map((term) => translate(`term${term}`));

// ...

  <select>
    {VALUES.map((value) => <option>{value}</option>)}
  </select>

$plural: support for param interpolation

Hi @robisim74

I just noticed that $plural API doesn't support param interpolation. Is it something missing or I misunderstand the API? I have the json

"devs": {
    "one": "{{ value }} software developer {{ name }}",
    "other": "{{ value }} software developers {{ name }}"
  }

and when I look at $plural API, there is no way to pass value for name.

Another small thing is, I think prefix param name in $plural should be renamed to key to be clearer.

Originally posted by @ahnpnl in #29 (reply in thread)

qwik-speak does not resolve locale

"@builder.io/qwik": "^0.20.1",
"@builder.io/qwik-city": "^0.5.2",
"qwik-speak": "^0.6.2",

I am setting locale onRequest and in renderToStream
q:locale is not set in html tag. Is this qwik-city bug?

Screenshot from 2023-03-01 21-30-11

translate a prop field

Howdy,

we have the following;

export const TextInput = component$(
    ({ value, label, error, ...props }: TextInputProps) => {
        const { name, required } = props;
        return (
            <div class={clsx("form-control w-full mt-4", props.class)}>
                <InputLabel name={name} label={label} required={required} />
                <input
                    {...props}
                    class={clsx("input input-bordered w-full",
                        error
                            ? "border-red-600/50 dark:border-red-400/50"
                            : ""
                    )}
                    id={name}
                    value={value || ""}
                    aria-invalid={!!error}
                    aria-errormessage={`${name}-error`}
                />
                <InputError name={name} error={error} />
            </div>
        );
    }
);

our template uses;

             <Field name="code">
                {(field, props) => (
                  <TextInput {...props} value={field.value} error={field.error} type="text" label="code" required />
                )}
              </Field>

if we do the following;

label={t('crm.countries.input.code@@code')}

we get the following error

[vite] Internal server error: Code(20): Calling a 'use*()' method outside 'component$(() => { HERE })' is not allowed. 'use*()' methods provide hooks to the 'component$' state and lifecycle, ie 'use' hooks can only be called synchronously within the 'component$' function or another 'use' method.
For more information see: https://qwik.builder.io/docs/components/lifecycle/#use-method-rules

any ideas...

Thanks upfront

Static Site Generation (SSG) does not generate "dist/index.html"

Hello, thank you for all your work. I am trying to generate a static website but on "npm run build", the dist directory is generated but without "index.html". I tried again outside of my project, by pulling the qwik-speak repository and using SSG, however, this is not working. The steps as follow:

Setup qwik-speak repository:

git clone https://github.com/robisim74/qwik-speak.git
cd qwik-speak
npm install

Set SSG adapter:

npm run qwik add

Update speak-functions.ts by adding:

/**
 * Dynamic SSG route
 */
export const onStaticGenerate: StaticGenerateHandler = () => {
  return {
    params: config.supportedLocales.map(locale => {
      return { lang: locale.lang !== config.defaultLocale.lang ? locale.lang : '' };
    })
  };
};

Build:

npm run build

Maybe I miss understood something on https://robisim74.gitbook.io/qwik-speak/library/adapters. Those files are generated in "dist": "favicon.svg _headers manifest.json q-manifest.json robots.txt service-worker.js". Also "dist/build" folder contains "en-US" and "it-IT" folders surrounded by a lot of js files.

How to properly use SSG using qwik-speak?

Production build is referencing non existent variable when using typescript optional

Hi!
I'm using a translation like this one:

      {t("test.translation@@Envío para {{recipient}}", {
        recipient: remoteData.value.embed?.foo,
      })}

When I use the optional operator ?, translation fails when ran on client side, as compiled code is referencing a non existing variable, for example:

      {t("test.translation@@Envío para {{recipient}}", {
        recipient: remoteData.value.embed?.foo,
      })}

Compiles to:

import { N as o } from "./q-767952c7.js";
import "./q-3c25f3f0.js";
import { useRemoteData as r } from "./q-c4196f84.js";
import "./q-4012d65d.js";
const p = () => {
  var t;
  const e = r();
  return o("div", null, null, `Envío para ${te.value.embed}`, 1, "sB_0");
};
export { p as s_BP0CpRo5x74 };

As you can see, te does not exists

On the other side:

      {t("test.translation@@Envío para {{recipient}}", {
        recipient: remoteData.value.embed.foo,
      })}

Compiles to:

import { N as e } from "./q-767952c7.js";
import "./q-3c25f3f0.js";
import { useRemoteData as o } from "./q-d79a8c36.js";
import "./q-c200c11c.js";
const m = () => {
  const t = o();
  return e("div", null, null, `Envío para ${t.value.embed.foo}`, 1, "sB_0");
};
export { m as s_BP0CpRo5x74 };

You can find code to reproduce the error here:
https://github.com/juanpmarin/qwik-speak-repro/blob/4298ba760b2b05bc4852a6cf21fa7e0b0e8b9646/src/routes/test/%5Bid%5D/index.tsx#L17-L21

Issue with Folder Nesting in vite-plugin-qwik-speak-inline Plugin

Dear qwik-speak developer,

Allow me to start by thanking you for the effort and dedication put into creating this exceptional plugin, whose contribution has been immense.

I am reaching out to you because I have experienced a problem when trying to execute the "build" or "preview" functions of QwikJS. The issue lies in an error that arises with vite-plugin-qwik-speak-inline. Specifically, the error message reflects: "ENOENT: no such file or directory, scandir '/src/translations/en'".

This error does not appear in the "dev" development mode of QwikJS, which has led me to carry out a more detailed diagnosis. I found that the root of the problem is that the qwik-speak's vite-plugin-qwik-speak-inline plugin does not recognize ".json" files located in subfolders. An example of this is "src/translates/en/contact/contact.json". Despite it working correctly in the "dev" mode of QwikJS.

In other words, the vite-plugin-qwik-speak-inline plugin does not support nesting of folders, which, from my perspective, would be a substantial improvement. This capability would allow for a more efficient organization of the folder and file structure. Without it, we are forced to host all JSON files within a single folder, which can become confusing, especially in medium to large sized applications.

I would greatly appreciate it if you could provide me with some guidance on how to tackle this issue. Attached below is a code snippet that reflects the current configuration of qwik-speak in my application.

Once again, thank you for your commitment to creating this useful plugin. I am looking forward to your response.

import { server$ } from '@builder.io/qwik-city';

import { configuration } from '~/configuration';

import type { SpeakConfig, Translation, TranslationFn } from 'qwik-speak';

const translationFiles = import.meta.glob<Translation>(
  '/src/translations/**/*.json'
);

function getAssets(): string[] {
  const assets: string[] = [];

  for (const path of Object.keys(translationFiles)) {
    let finalPath = path;

    for (const language of configuration.i18n.language.available) {
      finalPath = finalPath.replace(`/src/translations/${language}`, '');
    }

    if (!finalPath.startsWith('/')) {
      finalPath = `/${finalPath}`;
    }

    if (!assets.includes(finalPath) && !finalPath.endsWith('runtime.json')) {
      assets.push(finalPath);
    }
  }

  return assets;
}

export const speakConfig: SpeakConfig = {
  assets: getAssets(),
  defaultLocale: {
    lang: configuration.i18n.language.default,
  },
  runtimeAssets: ['/runtime/runtime.json'],
  supportedLocales: configuration.i18n.language.available.map((language) => ({
    lang: language,
  })),
};

export const translationFunction: TranslationFn = {
  loadTranslation$: server$(async (language: string, asset: string) => {
    return translationFiles[`/src/translations/${language}${asset}`]();
  }),
};

[Feature request] Allow updating speak config dynamically

Scenario

My application gets user config on load to get user's default locale and supported locales. I have a default speakConfig like below

{
     defaultLocale: { lang: 'en-US' },
    supportedLocales: [{ lang: 'en-US' }],
    assets: ['common'],
}

I tried 2 attempts:

  • Creating a wrapper component around QwikSpeakProvider and pass a reactive store data into my wrapper component. The reactive store data is set based on API response. However, this way doesn't work.
  • Manually set value via useSpeakContext. For example speakContext.config.supportedLocales = [{ lang: 'en-US' }, { lang: 'nl-NL' }]. This way doesn't work either

Request

A new feature to allow config to be dynamic configured or if new feature is not possible, maybe some documentation updates?

Type safe

Translations return to default lang on rerender on production express and fastify builds

When a qwik app made with an express or fastify adapter is build in production, the page loads translated until there is a rerender of the component. Only the component turns in to the default lang

This is reproducible as followed:
created qwik app with npm create qwik@latest
add express or fastify adapter like described here: https://qwik.builder.io/docs/deployments/node/
add qwik speak following the quick start: https://github.com/robisim74/qwik-speak/blob/main/docs/quick-start.md

example component with state and translations:

import { $, component$, useSignal } from '@builder.io/qwik';
import type { SpeakLocale } from 'qwik-speak';
import { useSpeakConfig, useSpeakLocale, useTranslate } from 'qwik-speak';

export const ChangeLocale = component$(() => {
  const t = useTranslate();
  const locale = useSpeakLocale();
  const config = useSpeakConfig();
  const isOpen = useSignal(false);

  const changeLocale$ = $((newLocale: SpeakLocale) => {
    // Store locale in a cookie
    document.cookie = `locale=${JSON.stringify(
      newLocale
    )};max-age=86400;path=/`;

    location.reload();
  });

  const getLocaleTranslation = (lang: SpeakLocale['lang']) => {
    switch (lang) {
      case 'en-US':
        return t('app.english');
      case 'nl-NL':
        return t('app.dutch');
      case 'pl-PL':
        return t('app.polish');
      default:
        return null;
    }
  };

  return (
    <>
      <div class="relative inline-block text-left gap-x-4 px-6 py-3 text-sm font-semibold leading-6 text-gray-900">
        <div>
          <button
            type="button"
            class="inline-flex w-full justify-center gap-x-1.5 rounded-md bg-white px-3 py-2 text-sm font-semibold text-gray-900 shadow-sm ring-1 ring-inset ring-gray-300 hover:bg-gray-50"
            id="menu-button"
            aria-expanded="true"
            aria-haspopup="true"
            onClick$={() => (isOpen.value = !isOpen.value)}
          >
            {getLocaleTranslation(locale.lang)}
            <svg
              class="-mr-1 h-5 w-5 text-gray-400"
              viewBox="0 0 20 20"
              fill="currentColor"
              aria-hidden="true"
            >
              <path
                fill-rule="evenodd"
                d="M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z"
                clip-rule="evenodd"
              />
            </svg>
          </button>
        </div>
        {isOpen.value && (
          <div
            class="absolute left-6 bottom-16 z-10 mt-2 w-56 origin-bottom-right divide-y divide-gray-100 rounded-md bg-white shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none"
            role="menu"
            aria-orientation="vertical"
            aria-labelledby="menu-button"
            tabIndex={-1}
          >
            <div class="py-1" role="none">
              {config.supportedLocales.map((value) => {
                return (
                  <>
                    <a
                      key={value.lang}
                      onClick$={async () => await changeLocale$(value)}
                      class="text-gray-700 group flex items-center px-4 py-2 text-sm hover:text-emerald-600 hover:bg-gray-50 cursor-pointer"
                      role="menuitem"
                      tabIndex={-1}
                      id="menu-item-0"
                    >
                      {getLocaleTranslation(value.lang)}
                    </a>
                  </>
                );
              })}
            </div>
          </div>
        )}
      </div>
    </>
  );
});

If you need more from me, please tell me

Back button doesn't set the locale of the url

I've made a playground with your package. I copied pretty much everything from your sample app, but I did some changes to always show the locale in the URL, instead of hiding it when it's the default.

https://github.com/frederikstonge/qwik-playground

When I change from English to French, and then I press back, it changes the URL back to English, but the site remains in French.

Either I'm doing something wrong, but onGet in layout.tsx isn't called at all, and I can't use the speak context.

[QWIK-0.0.39] changeLocale(locale, ctx) results in eslint warning "Identifier ("ctx") can not be captured inside the scope [...]"

Hello.

Using qwik-speak against newly created app that is using Qwik 0.0.39, and implement locale changing such as:

onClick$={async () => await changeLocale(locale, ctx)}>

results in the following eslint warning:

[eslint] Identifier ("ctx") can not be captured inside the scope (onClick$) because "ctx.translateFn.getTranslation$" is a function, which is not serializable. Check out https://qwik.builder.io/docs/advanced/optimizer for more details. [qwik/valid-lexical-scope]

though, it seems to be working alright.

Would changing to using something like ctx.setLocale(locale) suppress this warning? I was looking into the lib code and there doesn't seem to be any blocker to moving that functionality to the context itself rather than creating a utility function for it.

Netlify compatibility

Hi,
I'm having an issue with qwik speak whenever I try to deploy to Netlify

It's like the whole deploy is broken it doesn't even load images but whenever I remove qwik speak it works

Intercept the request in the lib to get the browser language

Hi Robi,

I saw that internally the useServerData hook is used. I checked the code of Qwik in the node_modules. It is kinda cryptic. But I don't have so much time today to try to clone the Qwik repo and understand what is going on under the hood. So I am not sure what they are doing and if that is a point.

But why we don't use the Accept-Language header to get a grasp of the browser language in a routeLoader? That should also work in development where I always get the lib falling back to the default.

Serverlanguage might not be the correct here.

Just an idea. Don't know if it is valid. I will go to the Gym now and spend a little bit time with my wife :-). Was sitting in front of the computer all day again. But I want to try to get everything out of the framework with the zankel-engineering website. As soon as I am 80% satisfied with it and it is deployable I will make it public so that people even less experienced that Iam can maybe get a couple of ideas from it.

Qwik feels to me a little bit unstructured for enterprise grade applications. Maybe that is also a point where some companies could have a need for consulting in the future. Error reporting is also really bad. But he, it is open source and I am happy and thankful that somebody puts in the time to make something like this available. I never had the feeling that doing much open source as a small freelancer would be worth it. Anyway. Hear you soon.

Sebastian

[Question] Is it possible to work with a Storybook?

There is an issue in the console when trying to use translation in a component that is described by a storybook:

Error: Code(20): Calling a 'use*()' method outside 'component$(() => { HERE })' is not allowed. 'use*()' methods provide hooks to the 'component$' state and lifecycle, ie 'use' hooks can only be called syncronously within the 'component$' function or another 'use' method.
For more information see: https://qwik.builder.io/docs/components/lifecycle/#use-method-rules
    at createError (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:70:17)
    at logError (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:64:54)
    at logErrorAndStop (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:74:17)
    at qError (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:137:12)
    at useInvokeContext (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:1345:15)
    at useSequentialScope (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:1488:18)
    at useContext (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2593:39)
    at useSpeakContext (http://localhost:6006/node_modules/qwik-speak/lib/index.qwik.mjs?v=e630c39b:65:29)
    at $translate (http://localhost:6006/node_modules/qwik-speak/lib/index.qwik.mjs?v=e630c39b:75:18)
    at ViewAdventureSection (http://localhost:6006/src/components/adventure-card/adventure-card.tsx?t=1679334703890:348:23)
    at invoke (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:1367:26)
    at processNode (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2925:21)
    at processData$1 (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2960:16)
    at http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2970:55
    at Array.flatMap (<anonymous>)
    at processData$1 (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2970:40)
    at processNode (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2933:21)
    at processData$1 (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2960:16)
    at processNode (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2926:16)
    at processData$1 (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2960:16)
    at http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2970:55
    at Array.flatMap (<anonymous>)
    at processData$1 (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2970:40)
    at processNode (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2933:21)
    at processData$1 (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2960:16)
    at http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:2884:34
    at async Promise.all (index 1)
    at async Promise.all (index 0)
    at async renderRoot$1 (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:7187:9)
    at async render (http://localhost:6006/node_modules/@builder.io/qwik/core.mjs?v=e630c39b:7178:23)

How can smoothly reload, avoid page flickering?

@robisim74 Hello again,

Your package is great in all use-case, even with MD/MDX files.
But web pages are reloaded every time changing locales, causes flickering effect, which is not smooth rendered.
location.href = url.toString();
How can we avoid this?
Please help & thanks much.

EMFILE: too many open files

Hello,

I have finished rewriting my website from Angular to Qwik and I have been using Qwik Speak without any problems until now.

When building the app for production, I get an error:

vite v4.3.3 building for production... ✓ 2672 modules transformed. computing gzip size (0)...[vite-plugin-qwik-speak-inline] EMFILE: too many open files, open '\dist\build\nl\q-678594ab.js' ✓ built in 10.03s error during build: Error: EMFILE: too many open files, open '\dist\build\nl\q-678594ab.js'

This issue appears if I have too many supported languages set in qwikSpeakInline(). It works well with 4 languages set, but it will fail with 5+. I have a total of 14 supported languages, so this is an issue that must be fixed before I can deploy my app to production.

QWIK ERROR Error: Code(20)

Hi, I just upgraded qwik to 1.1.4 and qwik-speak ^0.13.0 with inline translation:
For production build I'm getting the following error:

QWIK ERROR Error: Code(20)

translationData[langasset] is not a function

Howdy,

with any fresh qwik install and following your quick install guide i end up with the following error;

20:01:48 [vite] Internal server error: translationData[langasset] is not a function
  File: /IdeaProjects/dare-qwik-4/src/speak-functions.ts:13:5
  11 |   */
  12 |  const loadTranslation$: LoadTranslationFn = server$(async (lang: string, asset: string) =>
  13 |    await translationData[`/i18n/${lang}/${asset}.json`]()
     |       ^
  14 |  );

If i remove the asset: string and have it like

await translationData[/i18n/${lang}/welcome.json]()

I use welcome because of the component;

export default component$(() => {
  return (
    <Speak assets={['welcome']}>
      <Welcome />
    </Speak>
  );
});

it will work just fine

all the code is from the quick install, either i'm missing something or there is a bug...

Can somebody verify if there's a bug or i'm just overlooking something ^^

How to use value of another term as parameter value

If I have following as my localised terms dictionary:

{
  term: 'Term Value',
  termWithParam: 'Term with {{term}}',
}

How can I get Term with Term Value out of the two terms defined in terms dictionary? trying the following:

_('termWithParam', {term: _('term')})

would result in:

Term with [object Promise]

Issues with Qwik 0.12

Hello.

Looks like adding qwik-speak to Qwik app of version 0.12 causes two issues:

  • Qwik Optimizer reports errors in speak-config where variables endpoint, newSegment should not be re-defined. I overcame this issue by changing the lines to following:
// ...
export const loadTranslation$: LoadTranslationFn = $(
  async (lang: string, asset: string, url?: URL) => {
    if (import.meta.env.DEV || asset === "runtime") {
      // Absolute urls on server
      if (isServer && url) {
        const endpoint = `${url.origin}/i18n/${lang}/${asset}.json`;
        const data = await fetch(endpoint);
        return data.json();
      } else {
        const endpoint = `/i18n/${lang}/${asset}.json`;
        const data = await fetch(endpoint);
        return data.json();
      }
    }
  }
);
// ...
export const storeLocale$: StoreLocaleFn = $((locale: SpeakLocale) => {
  // Store locale in cookie
  document.cookie = `locale=${JSON.stringify(locale)};path=/`;

  // Localize the route
  const url = new URL(document.location.href);
  if (url) {
    const pathLang = config.supportedLocales.find((x) =>
      url.pathname.startsWith(`/${x.lang}`)
    )?.lang;

    const regex = new RegExp(`(/${pathLang}/)|(/${pathLang}$)`);
    const segment = url.pathname.match(regex)?.[0];

    if (pathLang && segment) {
      if (locale.lang !== config.defaultLocale.lang) {
        const newSegment = segment.replace(pathLang, locale.lang);
        url.pathname = url.pathname.replace(segment, newSegment);
      } else {
        const newSegment = "/";
        url.pathname = url.pathname.replace(segment, newSegment);
      }
    } else if (locale.lang !== config.defaultLocale.lang) {
      url.pathname = `/${locale.lang}${url.pathname}`;
    }

    window.history.pushState({}, "", url);
  }
});
  • After previous changes, Qwik build works, but starting compiled site (express) results in all terms being printed as-is without being localised.

[Feature request]: execute `loadTranslation$` when use `changeLocale` on a non declared locale

Problem

  • Given speak config below
export const speakConfig: SpeakConfig = {
    defaultLocale: { lang: 'en-US' },
    supportedLocales: [{ lang: 'en-US' }],
    assets: ['common'],
};
  • Given loadTranslation$ like below
export const loadTranslation$: LoadTranslationFn = $(async (lang: string, asset: string, origin?: string) => {
    let url = '';
    // Absolute urls on server
    if (isServer && origin) {
        url = origin;
    }
    url += `/assets/i18n/${lang}/${asset}.json`;
    let data: object | null = null;

    try {
        const response = await fetch(url);
        data = await response.json();
    } catch (error) {
        // Implement error handling here
        console.log('loadTranslation$ error: ', error);
    }

    return data;
});
  • Given the codes which use changeLocale like below
export const Header = component$(() => {
    const ctx = useSpeakContext();

    return (
        <header>
            <div className={'header-banner'}></div>
            <button onClick$={() => changeLocale({ lang: 'nl-NL' }, ctx)}>Change locale</button>
        </header>
    );
});

What I noticed was, when I clicked the button to execute changeLocale, the loadTranslation$ didn't execute which took me a while to notice that my speak config didn't include locale nl-NL.

Suggestion

Can we make loadTranslation$ execute in this case so that the catch can log something?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.