stripe-node icon indicating copy to clipboard operation
stripe-node copied to clipboard

Provide a better way of handling `Stripe.Checkout.SessionCreateParams.Locale`

Open TastyPi opened this issue 3 months ago • 3 comments

Is your feature request related to a problem? Please describe.

Stripe.Checkout.SessionCreateParams.Locale is an enum of the specific supported locales. That's fine, but it makes it a pain to use if you don't enforce a subset of that list throughout your codebase.

We want a way to convert an arbitrary locale into the best locale for Stripe, what's the best way to do that?

Describe the solution you'd like

The Stripe API is updated so the locale parameter can be any BCP 47 string and Stripe will choose the most appropriate locale for that string.

Next best solution is a list of the supported locales is provided in the SDK so we can use that list to write a function once and not have to periodically check whether a new locale has been added and update the list.

Describe alternatives you've considered

We can create a conversion function with the current documented list, but this does not handle new locales being added.

import languageTags from "language-tags";

function toStripeLocale(
  locale: string,
): Stripe.Checkout.SessionCreateParams.Locale {
  const tag = languageTags(locale).preferred();
  const language = tag.language()?.format();
  switch (language) {
    case "bg":
    case "cs":
    case "da":
    case "de":
    case "el":
    case "et":
    case "fi":
    case "fil":
    case "hr":
    case "hu":
    case "id":
    case "it":
    case "ja":
    case "ko":
    case "lt":
    case "lv":
    case "ms":
    case "mt":
    case "nb":
    case "nl":
    case "pl":
    case "ro":
    case "ru":
    case "sk":
    case "sl":
    case "sv":
    case "th":
    case "tr":
    case "vi":
      return language;
    case "en":
      switch (tag.region()?.format()) {
        case "GB":
          return "en-GB";
      }
      return "en";
    case "es":
      switch (tag.region()?.format()) {
        case "419":
          return "es-419";
      }
      return "es";
    case "fr":
      switch (tag.region()?.format()) {
        case "CA":
          return "fr-CA";
      }
      return "fr";
    case "pt":
      switch (tag.region()?.format()) {
        case "BR":
          return "pt-BR";
      }
      return "pt";
    case "zh":
      switch (tag.region()?.format()) {
        case "HK":
          return "zh-HK";
        case "TW":
          return "zh-TW";
      }
      return "zh";
  }
  return "auto";
}

Additional context

No response

TastyPi avatar Nov 04 '25 17:11 TastyPi

Thanks for creating this issue! I can definitely see that it is difficult to return a strongly typed Locale from an arbitrary string. To be honest, your workaround is probably the best you can do at the moment. Fortunately, locale strings do not change frequently, so this should hold up for a while.

We don't have any immediate work planned to address this issue, so I'm going to make it as Future. We will see if others are running into this same issue and what their use cases are before we pick it up.

mbroshi-stripe avatar Nov 10 '25 21:11 mbroshi-stripe

@mbroshi-stripe I've found a nicer implementation using locale-matcher, tbh all Stripe needs to do is provide a runtime array of the supported languages and it becomes trivial for us:

import { matchLocale } from "locale-matcher";

function toStripeLocale(locale: string) {
  return matchLocale(locale, stripeLocales) ?? "auto";
}

TastyPi avatar Nov 11 '25 09:11 TastyPi

@TastyPi Thanks again for the suggestion, and for providing the code snippets! Given that example, I can see that providing you a runtime array appears to be all you would need. While we don't have plans to implement it right now, we'll track it for future consideration. I've added the future label so we can revisit this during our planning.

mbroshi-stripe avatar Nov 11 '25 15:11 mbroshi-stripe