mapbox / mapbox-navigation-ios

Turn-by-turn navigation logic and UI in Swift on iOS
https://docs.mapbox.com/ios/navigation/
Other
860 stars 310 forks source link

[Bug]: Resume button keeps showing in Turkish (Physical), Chinese (Simulator) #4038

Closed bartlomiejlechowski closed 1 year ago

bartlomiejlechowski commented 2 years ago

Mapbox Navigation SDK version

2.6.0

Steps to reproduce

"Resume / Re-center" button on Physical Device is in Turkish "RESUME" = "Devam et"`, (Chinese on Simulator)

Everything is set to English (development language, system language, and app language). Same effect on client's phone (USA)

RN sdk - https://github.com/homeeondemand/react-native-mapbox-navigation/releases/tag/2.0.0

image

Expected behavior

Showing in proper language, possibility to hide Resume Button label

Actual behavior

Showing in wrong language

Is this a one-time issue or a repeatable issue?

repeatable

MaximAlien commented 2 years ago

@bartlomiejlechowski, I do not experience this issue if iPhone Language is set to English and Region is set to United States. Can you please re-check any of our examples in https://github.com/mapbox/mapbox-navigation-ios-examples to verify this? If localization works as expected there I think there might be a problem with https://github.com/homeeondemand/react-native-mapbox-navigation/releases/tag/2.0.0.

1ec5 commented 2 years ago

More reports of this issue in #2608 homeeondemand/react-native-mapbox-navigation#57.

1ec5 commented 2 years ago

The Resume button’s contents come from an NSLocalizedString(_:tableName:bundle:value:comment:) call. We pass in Bundle.mapboxNavigation to get the resource bundle associated with MapboxNavigation.framework (or the MapboxNavigation module in SPM), as opposed to the application’s bundle:

https://github.com/mapbox/mapbox-navigation-ios/blob/b3689c16f3ad4168cb666a52d60a4d08b7dd6278/Sources/MapboxNavigation/ResumeButton.swift#L68

The other UI elements mentioned in homeeondemand/react-native-mapbox-navigation#57 use a similar mechanism:

https://github.com/mapbox/mapbox-navigation-ios/blob/63e556b47a19c900945747ca1841663d5aab2934/Sources/MapboxNavigation/EndOfRouteViewController.swift#L156

On iOS, most React Native applications are built using CocoaPods. For CocoaPods, Bundle.mapboxNavigation works by looking for the bundle that contains NavigationViewController. I assume this is working correctly, or else the UI elements wouldn’t be showing any text at all. That said, https://github.com/homeeondemand/react-native-mapbox-navigation/issues/57#issuecomment-1048176008 indicates that this issue doesn’t affect a React Native application built using SPM, so maybe there’s something to it:

https://github.com/mapbox/mapbox-navigation-ios/blob/63e556b47a19c900945747ca1841663d5aab2934/Sources/MapboxNavigation/Bundle.swift#L10-L18

Beyond that, it’s the job of Foundation to choose the correct language based on the locales available in the bundle, the application bundle’s available languages, and the system language preferences. It would be very surprising if this would fail somehow, and I don’t think we have any control over this process (unlike, say, the decision of which language to use for spoken instructions).

Incidentally, the English translations of these strings are only defined in en.lproj, not Base.lproj. But NSLocalizedString(_:tableName:bundle:value:comment:) should work regardless of whether base localization is enabled for a given table:

https://github.com/mapbox/mapbox-navigation-ios/blob/16511a54610c3fbd5e5a86b33ca8a4cbb2438588/Sources/MapboxNavigation/Resources/en.lproj/Localizable.strings#L199-L200

@bartlomiejlechowski, can you provide the value of Bundle.main.localizations, Bundle.main.developmentLocalization, Bundle.main.developmentLocalization, Locale.preferredLanguages, Locale.autoupdatingCurrent, and Locale.current? Thanks!

AlexanderCollins commented 2 years ago

I'm currently working through this same issue, in answer to your question @1ec5 here are those values for my case maybe it could help you provide some further insight:

Bundle.main.localizations: ["de", "he", "ar", "el", "zh-Hans", "ja", "fa", "en", "uk", "yo", "es", "sl", "da", "it", "bg", "es-ES", "sv", "ko", "Base", "zh-Hant", "hu", "tr", "pt-BR", "vi", "lt", "ru", "fr", "nl", "pt-PT", "ca"] Bundle.main.developmentLocalization: Optional("en") Locale.preferredLanguages: ["en"] Locale.autoupdatingCurrent:: en_US (autoupdatingCurrent) Locale.current: en_US (current)

AlexanderCollins commented 2 years ago

So I've spent the day digging into this and I'm at a loss 😄 .

I took a close look at that same "Resume" button (which also appears in a different language for me): https://github.com/mapbox/mapbox-navigation-ios/blob/b3689c16f3ad4168cb666a52d60a4d08b7dd6278/Sources/MapboxNavigation/ResumeButton.swift#L68

I put a breakpoint on .mapboxNavigation and followed it down to (as 1ec5 mentioned) MapboxNavigation's bundle implementation: https://github.com/mapbox/mapbox-navigation-ios/blob/63e556b47a19c900945747ca1841663d5aab2934/Sources/MapboxNavigation/Bundle.swift#L10-L18

in this context from line 15, the bundle's .developmentLocalization resolves to Optional("en").

I agree with @1ec5, I highly doubt this is an issue with foundation and rather perhaps something to do with project structure/configuration. I'm wondering if it could be possible that even though the language is 'en' that NSLocalizedString might fail to find the localization files due to a malformed project structure and fall back to some undefined (or random) language and that perhaps this issue is avoided with swift package manager (as suggested in https://github.com/homeeondemand/react-native-mapbox-navigation/issues/57#issuecomment-1048176008) .

If anyone has any thoughts around how to best debug NSLocalizedString or knows more about localization and ios project structures I'd be happy to test and follow things through so we can find the root cause of this issue.

Cheers!

hamza1216 commented 1 year ago

@AlexanderCollins I am still facing this issue. Did you manage to get it resolved? I tested mapbox-navigation-ios-examples whcih is Swift project(https://github.com/mapbox/mapbox-navigation-ios-examples), but it's working properly. But not working in the react-native project(https://github.com/homeeondemand/react-native-mapbox-navigation). The difference I found is that the Swift project uses use_framework. @1ec5 Any thoughts?

engelzero commented 1 year ago

@1ec5 - I've worked with the react native package before, this was not an issue in versions pre-2.0 - Only seems to be an issue from v2.0 onwards -- any way the translations can be based on the projects language or devices language set? What is causing the discrepancy?

1ec5 commented 1 year ago

We didn’t change much in v2.0 with respect to resources like strings files. However, we did add a special case to find the correct framework bundle location when building static frameworks in SPM:

https://github.com/mapbox/mapbox-navigation-ios/blob/4573a2cfe158abdfa86833fe22d703e634d5635e/Sources/MapboxNavigation/Bundle.swift#L7-L9 https://github.com/mapbox/mapbox-navigation-ios/blob/0287f55474101080939a6424bb64d8a150a3052b/Sources/MapboxNavigation/Bundle.swift#L10-L18

We did make a significant change to resource locations in v1.0, to move the entire SDK codebase into the Sources/ folder, but MapboxNavigation.podspec reflects that change:

https://github.com/mapbox/mapbox-navigation-ios/blob/0287f55474101080939a6424bb64d8a150a3052b/MapboxNavigation.podspec#L39

Incidentally, MapboxCoreNavigation.podspec doesn’t specify resources at all. That’s a bug, but the impact is minuscule, only affecting a console log message:

https://github.com/mapbox/mapbox-navigation-ios/blob/0287f55474101080939a6424bb64d8a150a3052b/Sources/MapboxCoreNavigation/Resources/en.lproj/Localizable.strings#L1-L2

1ec5 commented 1 year ago

The difference I found is that the Swift project uses use_framework.

Is everyone here using static frameworks with CocoaPods? That could well be the issue. Our map and navigation SDKs have required use_frameworks! for several years. There was a special static framework version of the map SDK for a while, but the navigation SDK never officially supported static frameworks using CocoaPods, only SPM where that’s the default.

/cc @jill-cardamon @azarovalex

engelzero commented 1 year ago

Fixed! - use_frameworks! is what was required. Thanks @1ec5

For anyone experiencing this issue with React Native Projects

use the following pre installer: (you will get build errors if you don't define static frameworks for most react native packages)

  use_frameworks!

  pre_install do |installer|
    installer.pod_targets.each do |pod|
      if pod.name.start_with?('react-native-') || pod.name.start_with?('ReactNative') || pod.name.start_with?('RN') || pod.name.eql?('RNPermissions') || pod.name.start_with?('Permission-')
        def pod.build_type;
          Pod::BuildType.static_library
        end
      end
    end
  end

MapboxNav v2.9 - simulator now shows English lang instead of Chinese.

Simulator Screen Shot - iPhone 8 - 2022-11-22 at 10 35 54

cc @AlexanderCollins @hamza1216 @bartlomiejlechowski

this issue can be closed now

jill-cardamon commented 1 year ago

Hi @bartlomiejlechowski! Feel free to close this issue if this fixes things.

shreypdev commented 1 year ago

Still have this issue even after using use_frameworks! in Podfile. Where you able to solve this @bartlomiejlechowski

engelzero commented 1 year ago

Still have this issue even after using use_frameworks! in Podfile. Where you able to solve this @bartlomiejlechowski

Can you share your pod file and did you

shreypdev commented 1 year ago

@engelzero Thanks for getting back.

Just for context, I am developing app in RN and I am using @homee/react-native-mapbox-navigation lib to get the Mapbox Navigation.

I did delete the Pods from my iOS dir and reinstalled it also I cleared my ~/Library/Developer/Xcode/DerivedData/ dir to get the clean build.

Here is my Podfile:

install! 'cocoapods', :disable_input_output_paths => true
require_relative '../node_modules/react-native/scripts/react_native_pods'
require_relative '../node_modules/@react-native-community/cli-platform-ios/native_modules'

platform :ios, '13.0'
use_frameworks! :linkage => :static #TODO: Put it in target app

target 'Sample' do
  rn_maps_path = '../node_modules/react-native-maps'

  config = use_native_modules!

  use_react_native!(:path => config["reactNativePath"])

  use_flipper!()

  $static_framework =  [
    'react-native-maps',
    'react-native-google-maps',
    'Google-Maps-iOS-Utils',
    'GoogleMaps',
    'RNPermissions',
    'Permission-LocationWhenInUse',
    'FlipperKit',
    'Flipper',
    'Flipper-Folly',
    'CocoaAsyncSocket',
    'ComponentKit',
    'Flipper-Fmt',
    'Flipper-DoubleConversion',
    'Flipper-Glog',
    'Flipper-PeerTalk',
    'Flipper-RSocket',
    'Yoga',
    'YogaKit',
    'CocoaLibEvent',
    'OpenSSL-Universal',
    'Flipper-Boost-iOSX',
    'DoubleConversion',
    'glog',
  ]

  permissions_path = '../node_modules/react-native-permissions/ios'
  pod 'Permission-LocationWhenInUse', :path => "#{permissions_path}/LocationWhenInUse"

  pod 'RNVectorIcons', :path => '../node_modules/react-native-vector-icons'

  pod 'react-native-geolocation', :path => '../node_modules/@react-native-community/geolocation'

  pod 'RNReactNativeHapticFeedback', :path => '../node_modules/react-native-haptic-feedback'

  pod 'React-Core', :path => '../node_modules/react-native/', :modular_headers => true

  pod 'RNGestureHandler', :path => '../node_modules/react-native-gesture-handler'

  pod 'react-native-google-maps', :path => rn_maps_path
  pod 'GoogleMaps'
  pod 'Google-Maps-iOS-Utils'
end

target 'SampleTests' do
  inherit! :complete
  # Pods for testing
end

pre_install do |installer|
  $RNMBNAV.pre_install(installer)
  Pod::Installer::Xcode::TargetValidator.send(:define_method, :verify_no_static_framework_transitive_dependencies) {}
    installer.pod_targets.each do |pod|
      if $static_framework.include?(pod.name)
        def pod.build_type;
        Pod::BuildType.static_library # >= 1.9
      end
    end
  end
end

post_install do |installer|
  flipper_post_install(installer)
  react_native_post_install(installer)
  installer.pods_project.targets.each do |target|
    if target.respond_to?(:product_type) and target.product_type == "com.apple.product-type.bundle"
      target.build_configurations.each do |config|
          config.build_settings['CODE_SIGNING_ALLOWED'] = 'NO'
      end
    end
    # TODO: Figure out a way to only change this for Mapbox related pods
    # target.build_configurations.each do |config|
    #   if config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'].to_f < 13.0
    #     config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
    #   end
    # end
  end
  __apply_Xcode_12_5_M1_post_install_workaround(installer)
  $RNMBNAV.post_install(installer)
end

Please let me know if you have better option to integrate Mapbox navigation in RN app as the lib that I mentioned above might be using the old version of Mapbox SDK.

Again thanks for the help.

AlexanderCollins commented 1 year ago

@shreypdev I'm also using my own fork of @homee/react-native-mapbox-navigation... Did you find a solution? use_frameworks! didn't work for me.

[Edit] Thanks @engelzero this resolved my issues.

pre_install do |installer|
    installer.pod_targets.each do |pod|
      if pod.name.start_with?('react-native-') || pod.name.start_with?('ReactNative') || pod.name.start_with?('RN') || pod.name.eql?('RNPermissions') || pod.name.start_with?('Permission-')
        def pod.build_type;
          Pod::BuildType.static_library
        end
      end
    end
  end

I also had to remove use_frameworks! :linkage => podfile_properties['ios.useFrameworks'].to_sym if podfile_properties['ios.useFrameworks'] from my podfile... and replace it with use_frameworks!

I've put this into a very primitive expo plugin for my specific use case if it helps anyone in the future specifically using rnmapbox/maps and or homeeondemand/react-native-mapbox-navigation with expo: https://github.com/drive-app/expo-plugin-pod-react-static-frameworks