Shopify / js-buy-sdk

The JS Buy SDK is a lightweight library that allows you to build ecommerce into any website. It is based on Shopify's API and provides the ability to retrieve products and collections from your shop, add products to a cart, and checkout.
https://shopify.github.io/js-buy-sdk
MIT License
984 stars 259 forks source link

Is it possible to localize a checkout url? #927

Open blasco opened 1 year ago

blasco commented 1 year ago

Is there a way to localize the generated checkout webUrl to match a desired currency?

ansmlc commented 1 year ago

@blasco Any chance you figured this out?

owenhoskins commented 1 year ago

I have the same question but regarding the Checkout's translations.

I came across an approach like webUrl + '&locale=en' online but it doesn't seem to work out of the box. As soon as you hit the checkout the URL is instantly changed by Shopify.

This is the URL I get from the buy-sdk: https://christian-metzner.myshopify.com/58368163980/checkouts/f3885cfdb02b596f66adf5370440dbb4?key=d77d7a3562834230534a1885cbf3934c

And this is the final URL on the Shopify hosted checkout: https://christian-metzner.myshopify.com/checkouts/co/f3885cfdb02b596f66adf5370440dbb4/information

If I append the locale code on the hosted checkout URL, it works, but I don't get this actual URL from the buy-sdk. So if I take the final URL structure from Shopify's checkout and splice in the ID I get from the buy-sdk I have a working localized solution.

adamatronix commented 9 months ago

Having the same issue. I recall this working in the past couple of years, but I just noticed on one of my sites I am not able to pass params all of a sudden.

DerBasler commented 9 months ago

Same issue here! I think it is related to: https://shopify.dev/changelog/storefront-api-cart-checkouturl-now-contains-key-param

I use the https://sdks.shopifycdn.com/buy-button/latest/buy-button-storefront.min.js

I can think of two very hacky solutions which I have not tested and don't even want to implement. Anyway maybe it helps someone.

option1: While you configure your cart you can do something like: events: { "beforeInit": beforeChartInit }

function beforeChartInit(cart): void { cart.checkout.open = function (url) { // here you open the url with the they within a small window this is to let shopify do its thing // then you create form the url the checkout url the one shopify would redirect you and then you open this one but with the locale attached ......

option 2 which is probably more usable is to associate a special domain to every language like: en-mydomain.myshopify.com and de-mydomain.myshopify.com and then use this one this might work as well.

🙏 shopify goods please help us out

owenhoskins commented 9 months ago

Update ⚠️ After additional testing I found my above attempt to solve to be incomplete. This issue details https://github.com/Shopify/js-buy-sdk/issues/943#issuecomment-1568610467 the stable and production ready solution!

DerBasler commented 9 months ago

So this took me a while but @owenhoskins thanks for listing the other issue and thanks to @ansmlc for the original pseudocode.

In the og pseudocode it was mentioned that you could read out a custom attribute but I did not find where I could set that once the sdk creates the checkout but I think it does not matter.

Here is most of my code:

function getShopifyClient(force = false): any {
  if (globalShopifyClient && !force) {
    return globalShopifyClient;
  }

  const { shopifyDomain, shopifyStorefrontAccessToken } = ConfigurationService.get();
  const client = ShopifyBuy.buildClient({
    domain: shopifyDomain,
    storefrontAccessToken: shopifyStorefrontAccessToken,
    language: `${language}-CH`,
  });
  globalShopifyClient = client;
  return client;
}

function getCartConfigObj(t: TFunction): any {
  const cartTextObj = getTextObj(t);

  return {
    events: {
      beforeInit: beforeCartInit,
    },
  };
}

function beforeCartInit(cart): void {
  cart.checkout.open = function(url: string): void {
    const checkoutId = url.split('/').pop() || '';
    // alternative: get it from the local storage
    const shopifyCheckoutId = `gid://shopify/Checkout/${checkoutId}`;
    createNewCheckout(shopifyCheckoutId);
  }
}

/**
 * Creates a new shopify client with the current language
 * Creates a new checkout
 * Copies the line items from the previous checkout
 * Opens the checkout in a new tab
 */
async function createNewCheckout(oldCheckoutId: string): Promise<void> {
  const oldCheckout = await globalShopifyClient.checkout.fetch(oldCheckoutId);
  const currentItems = oldCheckout.lineItems.map((item) => {
    return {
      variantId: item.variant.id,
      quantity: item.quantity,
    };
  });
  const newClient = getShopifyClient(true);
  const newCheckout = await newClient.checkout.create();
  // add the line items from the previous checkout
  await newClient.checkout.addLineItems(newCheckout.id, currentItems);
  // open in a new tab
  window.open(newCheckout.webUrl, 'checkout');
}

Maybe it is also possible to use https://shopify.dev/docs/api/storefront/2023-10/mutations/cartAttributesUpdate but I was not able to quickly achieve this.