stripe / stripe-ios

Stripe iOS SDK
https://stripe.com
MIT License
2.12k stars 982 forks source link

[BUG] Localized error strings not being translated to Spanish #1964

Closed maganap closed 2 years ago

maganap commented 2 years ago

Summary

I'm using flutter_stripe package for an app developed in Flutter. After some initial setup, this package automatically sets the payment bottom sheet language to the language configured on the cell phone.

We're working in Spanish es-ES. The bottom sheet certainly shows in Spanish, but the localizad error messages are always shown in English. For example, when closing the sheet without paying, a StripeException is received with a LocalizedErrorMessage. The localizedMessage property is supposed to be translated, but it is not.

I asked a question to this flutter package support and I was told the localized messages come directly from the native Stripe SDK, they're a bridge to Flutter so I should open a case here. I'm sorry I can't really give you more details on the problem since I don't know the way this package works internally.

iOS version

iOS 15.4.1

Installation method

Through flutter_stripe package.

SDK version

Stripe 22.0.0 from Podfile.lock

Other information

This problem is actually happening in Android as well, but anyway I was told to report to the native SDK. If there's anything else you can explain me to verify so I can give you better information, please let me know. Thanks!

yuki-stripe commented 2 years ago

Hello @maganap, can you provide an example of an error string you're seeing in English?

maganap commented 2 years ago

@yuki-stripe Sure!

This is in iOS using es-ES language in the phone settings. The sheet is properly shown in Spanish:

but when cancelled the error string is shown in English:

The snackbar is showing: errorMessage = 'Stripe: ${e.error.localizedMessage}'; after the exception is thrown when the sheet is closed without paying.

Thanks for taking a look at it

yuki-stripe commented 2 years ago

Thanks for the example! I'm not familiar with the flutter SDK, does it provide anything besides an error? For example, our native SDKs return a status enum of success, cancel, or failure(error). This way you can not show anything to the user if they merely canceled.

remonh87 commented 2 years ago

@yuki-stripe I am one of the maintainers of the Flutter Stripe library. We are using the Stripe react native sdk and are indeed forwarding the errors one to one. For iOS the Stripe errors are situated: https://github.com/stripe/stripe-react-native/blob/master/ios/Errors.swift . I have the assumption that this is just a bridge and that the actual error is coming from the iOS sdk. I am fine to create an error on the react native repo.

Reproduction scenario:

  1. Open payment sheet on a phone with language spanish
  2. Cancel the payment. In our case the react native sdk provides us an english localized message which is curious.

@maganap for this particular case there is a workaround. We also provide a failure code in this case that you can use to provide your own translated message. See: https://github.com/flutter-stripe/flutter_stripe/blob/f6ee41e7c6c62cabc4a166557c0ed4c7045e15ed/packages/stripe_platform_interface/lib/src/models/errors.dart#L74

yuki-stripe commented 2 years ago

Hello @remonh87! Super helpful, thank you.

The React Native SDK has something similar, I think - ErrorType to let you know if this was merely a cancellation. The SDK converts the 'cancel' case here.

Usage in RN looks something like

const { error } = await presentPaymentSheet();

if (!error) {
      // success
    } else if (error.code === PaymentSheetError.Failed) {
      // failed
    } else if (error.code === PaymentSheetError.Canceled) {
      // canceled
    }
}
maganap commented 2 years ago

Hi!

Thank you both @yuki-stripe and @remonh87 for your replies.

The cancellation was just the simplest example (and the only one I could just avoid showing, as you suggest).

I believe I was expecting the localizedMessage to always contain the failure reason after the sheet was closed (like insufficient funds, not authorized, lost card, incorrect cvc or whatever other cases I'm not even aware of). But the properly localized error is actually showing on the sheet before being closed. We have no way to know the failure reason because, when the sheet is closed, the cancellation exception is thrown without any information on the actual failure reason.

Not that I need it but... I guess I got that wrongly interpreted idea from the documentation, since we do get something like:

StripeException(
  error: LocalizedErrorMessage(
    code: FailureCode.Canceled,
    localizedMessage: The payment has been canceled,
    message: The payment has been canceled,
    stripeErrorCode: null,
    declineCode: null,
    type: null,
  ),
)

Properties that I can't find useful if the only received exceptions are the generic canceled/failed cases, and the rest of the fields are always null.

In any case, localizedMessage is indeed not being translated, but I guess it's not that important as I expected since I can just avoid showing anything to the user on actual cancellation, and I can translate my own message on technical failure (which is the only other case being reported, for example when the Payment Intent fails to be created, but those are not "payment errors").

You may close this ticket if you think it's not worth the fix. I would xD

Thank you very much for your time!

yuki-stripe commented 2 years ago

@maganap Ah, yes this is confusing...thank you for the feedback! Adding an item for us to improve the documentation here.

AristideVB commented 4 months ago

So if I understand @yuki-stripe this correctly localizedMessage isn't actually... localized ? 😢

maganap commented 4 months ago

@AristideVB Yes, but no. 😅

Internal error texts are indeed translated.

The only exception actually thrown that you can catch is the cancelled exception (which you can just avoid showing at all). This is the case that I reported that was not translated.

The other payment failure error texts are directly shown on the bottom sheet (properly translated) without your intervention.

For example, "insufficient funds" will be shown to the user on the bottom sheet if they try to pay without funds (and you won't even know in your source code, it's handled internally). The user can either retry with a different card (so you receive a payment success) or close the bottom sheet (then you receive a thrown cancelled error).

AristideVB commented 4 months ago

Ok @maganap 🙂 but I'm not using the bottom sheet, I'm using the Credit Card field on it's own & I've seen a localizedMessage internal error "Card details not complete" untranslated is that normal, should I expect all errors thrown in the localizedMessage not to be translated ?

maganap commented 4 months ago

@AristideVB oh, I'm not even using stripe-ios package directly, but through flutter_stripe, where the typical use is with the bottom sheet. Sorry I can't help with that.

AristideVB commented 4 months ago

@maganap Using flutter_stripe too but with the Credit Card field