Open redaready opened 1 year ago
I will investigate in it
thanks gioboa, i have tried add "locale" to the option of requester, it works, but i don't think it's the best way to do the job because we are obliged to add locale option to many api calls...
diff --git a/src/providers/collections/collections.ts b/src/providers/collections/collections.ts
index 3034f63..2802a6d 100644
--- a/src/providers/collections/collections.ts
+++ b/src/providers/collections/collections.ts
@@ -1,9 +1,9 @@
import gql from 'graphql-tag';
-import { sdk } from '~/graphql-wrapper';
import { Collection } from '~/generated/graphql';
+import { sdk } from '~/graphql-wrapper';
-export const getCollections = async () => {
- return await sdk.collections().then((res) => res.collections.items as Collection[]);
+export const getCollections = async (locale: string) => {
+ return await sdk.collections(undefined, { locale: locale }).then((res) => res.collections.items as Collection[]);
};
export const getCollectionBySlug = async (slug: string) => {
diff --git a/src/routes/layout.tsx b/src/routes/layout.tsx
index 9d8e4c2..eb14bfc 100644
--- a/src/routes/layout.tsx
+++ b/src/routes/layout.tsx
@@ -19,8 +19,9 @@ import { extractLang } from '~/utils/i18n';
import Footer from '../components/footer/footer';
import Header from '../components/header/header';
-export const useCollectionsLoader = routeLoader$(async () => {
- return await getCollections();
+export const useCollectionsLoader = routeLoader$(async (requestEvent) => {
+ const locale = extractLang(requestEvent.headers.get('accept-language'), requestEvent.url.toString())
+ return await getCollections(locale);
});
export const useAvailableCountriesLoader = routeLoader$(async () => {
diff --git a/src/utils/api.ts b/src/utils/api.ts
index f03dc54..ee28204 100644
--- a/src/utils/api.ts
+++ b/src/utils/api.ts
@@ -1,7 +1,7 @@
import { server$ } from '@builder.io/qwik-city';
import { isBrowser } from '@builder.io/qwik/build';
import { DocumentNode, print } from 'graphql/index';
-import { AUTH_TOKEN, HEADER_AUTH_TOKEN_KEY } from '~/constants';
+import { AUTH_TOKEN, DEFAULT_LOCALE, HEADER_AUTH_TOKEN_KEY } from '~/constants';
import { ENV_VARIABLES } from '~/env';
import { getCookie, setCookie } from '.';
@@ -12,22 +12,25 @@ type Options = { method: string; headers: Record<string, string>; body: string }
export const requester = async <R, V>(
doc: DocumentNode,
vars?: V,
- options: { token?: string } = { token: '' }
+ options: { token?: string, locale?: string } = { token: '' }
): Promise<R> => {
- return execute<R, V>({ query: print(doc), variables: vars }, options.token);
+ return execute<R, V>({ query: print(doc), variables: vars }, options.token, options.locale || DEFAULT_LOCALE);
};
const execute = async <R, V = Record<string, any>>(
body: ExecuteProps<V>,
- authToken: string = ''
+ authToken: string = '',
+ locale: string
): Promise<R> => {
- const options = { method: 'POST', headers: createHeaders(), body: JSON.stringify(body) };
+ const options = {
+ method: 'POST', headers: createHeaders(), body: JSON.stringify(body)
+ };
if (authToken !== '') {
options.headers = { 'Content-Type': 'application/json', Authorization: `Bearer ${authToken}` };
}
const response: ResponseProps<R> = isBrowser
- ? await executeOnTheServer(options)
- : await executeRequest(options);
+ ? await executeOnTheServer(options, locale)
+ : await executeRequest(options, locale);
if (isBrowser && response.token) {
setCookie(AUTH_TOKEN, response.token, 365);
@@ -45,10 +48,10 @@ const createHeaders = () => {
return headers;
};
-const executeOnTheServer = server$(async (options: Options) => executeRequest(options));
+const executeOnTheServer = server$(async (options: Options, locale: string) => executeRequest(options, locale));
-const executeRequest = async (options: Options) => {
- const httpResponse = await fetch(ENV_VARIABLES.VITE_VENDURE_PUBLIC_URL, options);
+const executeRequest = async (options: Options, locale?: string) => {
+ const httpResponse = await fetch(`${ENV_VARIABLES.VITE_VENDURE_PUBLIC_URL}/?languageCode=${locale}`, options);
return await extractTokenAndData(httpResponse);
};
@redaready, have you tried setting the locale in a Cookie just like it's done with the Vendure token?
You might be facing "Internal server error: Reading locale outside of context."
due to the locale is set here. So probably the getLocale()
function is called before the locale is set.
with some help of sourcegraph cody:
That error means you are calling getLocale() outside of a Qwik component or route. getLocale() relies on Qwik's locale context, so it can only be called within a Qwik component/route.
Some options to fix this:
Pass the locale as an argument to the function instead of calling getLocale():
function doSomething(locale: string) {
// Use locale here instead of calling getLocale()
}
Wrap the call in a Qwik component:
component$(() => {
const locale = getLocale();
// Use locale here
});
Use a Qwik route and access the locale from the request event:
export const onRequest: RequestHandler = ({ locale }) => {
// Use locale here
};
Store the locale in a variable outside of the Qwik context and pass that in:
let locale;
component$(() => {
locale = getLocale();
});
function doSomething() {
// Use locale here instead of calling getLocale()
}
Hope this helps resolve your error! Let me know if you have any other questions.
@giovramirez i think locale is a little bit diffrent with token, token is generated by vendure and then stored in cookie, locale on other hand, we must pass it to sdk calls at first invocations (ex: useCollectionsLoader and useAvailableCountriesLoader etc)... so i think we have no other choice than pass locale parameter to many sdk calls :-(
You're right @redaready. Besides, we can't use a Cookie since most of the calls are executed on the server, so it's not an option to get the locale from Cookie.
We have this interceptor where we can get the locale, store it outside of the Qwik context and use it globally within the app. However, I think for better readability of the codebase your approach of passing the locale parameter to every sdk looks better.
@gioboa any thoughts on this matter?
I need to investigate into the problem, I will look at it in few days. You are more then welcome to suggest a solution with a PR
my approach was a global config variable for currencyCode and use it here
const executeRequest = async (options: Options) => {
const httpResponse = await fetch(
`${ENV_VARIABLES.VITE_VENDURE_PUBLIC_URL}?currencyCode=${getCurrencyCode()}`,
options
);
return await extractTokenAndData(httpResponse);
};
This sounds reasonable to me 👍 Thanks for sharing
can we change locale per request in this way? sometimes storefront has a Language Selector component, we need to get locale value from request context(cookie, path, or header) to call api. i think the locale value proprity chain could be
Yep, if we change the path with a variable we can do whatever we want
@redaready we did as you mentioned storing the user selection in a cookie and updating the client-side global config on changes. vendure backend already supports it and there was an issue here that came up with this approach which has been fixed
is there a way to pass the locale value of "extractLang(request.headers.get('accept-language'), request.url)" to shop-api call?
i have tried something like this, but a error raised: "Internal server error: Reading
locale
outside of context."