From b85ebddbfb41681901133f8d3510d41ffcfd8a6b Mon Sep 17 00:00:00 2001 From: Gerson Noboa Date: Thu, 2 Nov 2023 13:06:03 +0200 Subject: [PATCH] Add manual locale override capability The configuration accepts a manual locale override, which is `nil` by default. If the Core SDK returns an incorrect manual locale override, then the Widgets SDK also returns an error on configuration to let know the integrator about it. If the integrator provides a wrong site API key, this commit also makes sure to inform the integrator instead of hanging. Also, the settings screen now includes the possibility to add a manual locale override visually. If it's empty, then it sends nil. MOB-2798 --- GliaWidgets/Localization.swift | 304 +++++++++--------- .../Configuration/Configuration+Mock.swift | 6 +- .../Public/Configuration/Configuration.swift | 10 +- GliaWidgets/Public/Glia/Glia.swift | 18 +- GliaWidgets/Public/GliaError.swift | 2 + .../Coordinators/Chat/ChatCoordinator.swift | 1 - .../CoreSDKClient.Interface.swift | 1 + .../CoreSDKConfigurator.Interface.swift | 3 +- .../Extensions/Configuration.Extensions.swift | 22 +- .../Settings/SettingsViewController.swift | 17 +- .../ViewController/ViewController.swift | 38 ++- swiftgen-strings.stencil | 4 +- 12 files changed, 243 insertions(+), 183 deletions(-) diff --git a/GliaWidgets/Localization.swift b/GliaWidgets/Localization.swift index c8f4390c9..c28314b6a 100644 --- a/GliaWidgets/Localization.swift +++ b/GliaWidgets/Localization.swift @@ -13,32 +13,32 @@ internal enum Localization { internal enum Alert { internal enum Action { /// Settings - internal static let settings = Localization.tr("Localizable", "alert.action.settings", fallback: "Settings") + internal static var settings: String { Localization.tr("Localizable", "alert.action.settings", fallback: "Settings") } } internal enum CameraAccess { /// Unable to access camera - internal static let error = Localization.tr("Localizable", "alert.camera_access.error", fallback: "Unable to access camera") + internal static var error: String { Localization.tr("Localizable", "alert.camera_access.error", fallback: "Unable to access camera") } } internal enum MediaSourceAccess { /// Unable to access media source - internal static let error = Localization.tr("Localizable", "alert.media_source_access.error", fallback: "Unable to access media source") + internal static var error: String { Localization.tr("Localizable", "alert.media_source_access.error", fallback: "Unable to access media source") } } internal enum MicrophoneAccess { /// Unable to access microphone - internal static let error = Localization.tr("Localizable", "alert.microphone_access.error", fallback: "Unable to access microphone") + internal static var error: String { Localization.tr("Localizable", "alert.microphone_access.error", fallback: "Unable to access microphone") } } internal enum ScreenSharing { internal enum Start { /// Start Screen Sharing - internal static let header = Localization.tr("Localizable", "alert.screen_sharing.start.header", fallback: "Start Screen Sharing") + internal static var header: String { Localization.tr("Localizable", "alert.screen_sharing.start.header", fallback: "Start Screen Sharing") } /// {operatorName} has asked you to share your screen. - internal static let message = Localization.tr("Localizable", "alert.screen_sharing.start.message", fallback: "{operatorName} has asked you to share your screen.") + internal static var message: String { Localization.tr("Localizable", "alert.screen_sharing.start.message", fallback: "{operatorName} has asked you to share your screen.") } } internal enum Stop { /// Stop Screen Sharing? - internal static let header = Localization.tr("Localizable", "alert.screen_sharing.stop.header", fallback: "Stop Screen Sharing?") + internal static var header: String { Localization.tr("Localizable", "alert.screen_sharing.stop.header", fallback: "Stop Screen Sharing?") } /// Are you sure you want to stop sharing your screen? - internal static let message = Localization.tr("Localizable", "alert.screen_sharing.stop.message", fallback: "Are you sure you want to stop sharing your screen?") + internal static var message: String { Localization.tr("Localizable", "alert.screen_sharing.stop.message", fallback: "Are you sure you want to stop sharing your screen?") } } } } @@ -46,9 +46,9 @@ internal enum Localization { internal enum Bubble { internal enum Accessibility { /// Expands call view. - internal static let hint = Localization.tr("Localizable", "call.bubble.accessibility.hint", fallback: "Expands call view.") + internal static var hint: String { Localization.tr("Localizable", "call.bubble.accessibility.hint", fallback: "Expands call view.") } /// Go back to the engagement. - internal static let label = Localization.tr("Localizable", "call.bubble.accessibility.label", fallback: "Go back to the engagement.") + internal static var label: String { Localization.tr("Localizable", "call.bubble.accessibility.label", fallback: "Go back to the engagement.") } } } internal enum Buttons { @@ -57,13 +57,13 @@ internal enum Localization { internal enum MultipleItems { internal enum Accessibility { /// {badgeValue} unread messages - internal static let label = Localization.tr("Localizable", "call.buttons.chat.badge_value.multiple_items.accessibility.label", fallback: "{badgeValue} unread messages") + internal static var label: String { Localization.tr("Localizable", "call.buttons.chat.badge_value.multiple_items.accessibility.label", fallback: "{badgeValue} unread messages") } } } internal enum SingleItem { internal enum Accessibility { /// {badgeValue} unread message - internal static let label = Localization.tr("Localizable", "call.buttons.chat.badge_value.single_item.accessibility.label", fallback: "{badgeValue} unread message") + internal static var label: String { Localization.tr("Localizable", "call.buttons.chat.badge_value.single_item.accessibility.label", fallback: "{badgeValue} unread message") } } } } @@ -73,20 +73,20 @@ internal enum Localization { internal enum FirstText { internal enum Accessibility { /// Displays operator name. - internal static let hint = Localization.tr("Localizable", "call.connect.first_text.accessibility.hint", fallback: "Displays operator name.") + internal static var hint: String { Localization.tr("Localizable", "call.connect.first_text.accessibility.hint", fallback: "Displays operator name.") } } } internal enum SecondText { internal enum Accessibility { /// Displays call duration. - internal static let hint = Localization.tr("Localizable", "call.connect.second_text.accessibility.hint", fallback: "Displays call duration.") + internal static var hint: String { Localization.tr("Localizable", "call.connect.second_text.accessibility.hint", fallback: "Displays call duration.") } } } } internal enum Duration { internal enum Accessibility { /// Call duration. - internal static let label = Localization.tr("Localizable", "call.duration.accessibility.label", fallback: "Call duration.") + internal static var label: String { Localization.tr("Localizable", "call.duration.accessibility.label", fallback: "Call duration.") } } } internal enum Header { @@ -94,470 +94,470 @@ internal enum Localization { internal enum Button { internal enum Accessibility { /// Minimizes call view. - internal static let hint = Localization.tr("Localizable", "call.header.back.button.accessibility.hint", fallback: "Minimizes call view.") + internal static var hint: String { Localization.tr("Localizable", "call.header.back.button.accessibility.hint", fallback: "Minimizes call view.") } } } } } internal enum Mute { /// Mute - internal static let button = Localization.tr("Localizable", "call.mute.button", fallback: "Mute") + internal static var button: String { Localization.tr("Localizable", "call.mute.button", fallback: "Mute") } } internal enum OnHold { /// You can continue browsing while you are on hold - internal static let bottomText = Localization.tr("Localizable", "call.on_hold.bottom_text", fallback: "You can continue browsing while you are on hold") + internal static var bottomText: String { Localization.tr("Localizable", "call.on_hold.bottom_text", fallback: "You can continue browsing while you are on hold") } /// On Hold - internal static let icon = Localization.tr("Localizable", "call.on_hold.icon", fallback: "On Hold") + internal static var icon: String { Localization.tr("Localizable", "call.on_hold.icon", fallback: "On Hold") } } internal enum OperatorAvatar { internal enum Accessibility { /// Shows operator picture. - internal static let hint = Localization.tr("Localizable", "call.operator_avatar.accessibility.hint", fallback: "Shows operator picture.") + internal static var hint: String { Localization.tr("Localizable", "call.operator_avatar.accessibility.hint", fallback: "Shows operator picture.") } /// Operator Picture - internal static let label = Localization.tr("Localizable", "call.operator_avatar.accessibility.label", fallback: "Operator Picture") + internal static var label: String { Localization.tr("Localizable", "call.operator_avatar.accessibility.label", fallback: "Operator Picture") } } } internal enum OperatorName { internal enum Accessibility { /// Shows operator name. - internal static let hint = Localization.tr("Localizable", "call.operator_name.accessibility.hint", fallback: "Shows operator name.") + internal static var hint: String { Localization.tr("Localizable", "call.operator_name.accessibility.hint", fallback: "Shows operator name.") } } } internal enum OperatorVideo { internal enum Accessibility { /// Operator's Video - internal static let label = Localization.tr("Localizable", "call.operator_video.accessibility.label", fallback: "Operator's Video") + internal static var label: String { Localization.tr("Localizable", "call.operator_video.accessibility.label", fallback: "Operator's Video") } } } internal enum Speaker { /// Speaker - internal static let button = Localization.tr("Localizable", "call.speaker.button", fallback: "Speaker") + internal static var button: String { Localization.tr("Localizable", "call.speaker.button", fallback: "Speaker") } } internal enum Unmute { /// Unmute - internal static let button = Localization.tr("Localizable", "call.unmute.button", fallback: "Unmute") + internal static var button: String { Localization.tr("Localizable", "call.unmute.button", fallback: "Unmute") } } internal enum VisitorVideo { internal enum Accessibility { /// Your Video - internal static let label = Localization.tr("Localizable", "call.visitor_video.accessibility.label", fallback: "Your Video") + internal static var label: String { Localization.tr("Localizable", "call.visitor_video.accessibility.label", fallback: "Your Video") } } } } internal enum CallVisualizer { internal enum ScreenSharing { /// Your Screen is Being Shared - internal static let message = Localization.tr("Localizable", "call_visualizer.screen_sharing.message", fallback: "Your Screen is Being Shared") + internal static var message: String { Localization.tr("Localizable", "call_visualizer.screen_sharing.message", fallback: "Your Screen is Being Shared") } internal enum Header { /// Screen Sharing - internal static let title = Localization.tr("Localizable", "call_visualizer.screen_sharing.header.title", fallback: "Screen Sharing") + internal static var title: String { Localization.tr("Localizable", "call_visualizer.screen_sharing.header.title", fallback: "Screen Sharing") } } } internal enum VisitorCode { /// Your Visitor Code - internal static let title = Localization.tr("Localizable", "call_visualizer.visitor_code.title", fallback: "Your Visitor Code") + internal static var title: String { Localization.tr("Localizable", "call_visualizer.visitor_code.title", fallback: "Your Visitor Code") } internal enum Close { internal enum Accessibility { /// Closes the visitor code - internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.close.accessibility.hint", fallback: "Closes the visitor code") + internal static var hint: String { Localization.tr("Localizable", "call_visualizer.visitor_code.close.accessibility.hint", fallback: "Closes the visitor code") } } } internal enum Refresh { internal enum Accessibility { /// Generates a new visitor code - internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.refresh.accessibility.hint", fallback: "Generates a new visitor code") + internal static var hint: String { Localization.tr("Localizable", "call_visualizer.visitor_code.refresh.accessibility.hint", fallback: "Generates a new visitor code") } /// Refresh Button - internal static let label = Localization.tr("Localizable", "call_visualizer.visitor_code.refresh.accessibility.label", fallback: "Refresh Button") + internal static var label: String { Localization.tr("Localizable", "call_visualizer.visitor_code.refresh.accessibility.label", fallback: "Refresh Button") } } } internal enum Title { internal enum Accessibility { /// Shows the five-digit visitor code. - internal static let hint = Localization.tr("Localizable", "call_visualizer.visitor_code.title.accessibility.hint", fallback: "Shows the five-digit visitor code.") + internal static var hint: String { Localization.tr("Localizable", "call_visualizer.visitor_code.title.accessibility.hint", fallback: "Shows the five-digit visitor code.") } } } } } internal enum Chat { /// Pick attachment - internal static let attachFiles = Localization.tr("Localizable", "chat.attach_files", fallback: "Pick attachment") + internal static var attachFiles: String { Localization.tr("Localizable", "chat.attach_files", fallback: "Pick attachment") } /// New Messages - internal static let unreadMessageDivider = Localization.tr("Localizable", "chat.unread_message_divider", fallback: "New Messages") + internal static var unreadMessageDivider: String { Localization.tr("Localizable", "chat.unread_message_divider", fallback: "New Messages") } internal enum Attachment { /// Photo Library - internal static let photoLibrary = Localization.tr("Localizable", "chat.attachment.photo_library", fallback: "Photo Library") + internal static var photoLibrary: String { Localization.tr("Localizable", "chat.attachment.photo_library", fallback: "Photo Library") } /// Take Photo or Video - internal static let takePhoto = Localization.tr("Localizable", "chat.attachment.take_photo", fallback: "Take Photo or Video") + internal static var takePhoto: String { Localization.tr("Localizable", "chat.attachment.take_photo", fallback: "Take Photo or Video") } /// This file type is not supported. - internal static let unsupportedFile = Localization.tr("Localizable", "chat.attachment.unsupported_file", fallback: "This file type is not supported.") + internal static var unsupportedFile: String { Localization.tr("Localizable", "chat.attachment.unsupported_file", fallback: "This file type is not supported.") } internal enum Message { internal enum Accessibility { /// Attachment from {fileSender} - internal static let label = Localization.tr("Localizable", "chat.attachment.message.accessibility.label", fallback: "Attachment from {fileSender}") + internal static var label: String { Localization.tr("Localizable", "chat.attachment.message.accessibility.label", fallback: "Attachment from {fileSender}") } } } } internal enum ChoiceCard { /// Tap on the answer above - internal static let placeholderMessage = Localization.tr("Localizable", "chat.choice_card.placeholder_message", fallback: "Tap on the answer above") + internal static var placeholderMessage: String { Localization.tr("Localizable", "chat.choice_card.placeholder_message", fallback: "Tap on the answer above") } internal enum Button { internal enum Disabled { internal enum Accessibility { /// Disabled - internal static let label = Localization.tr("Localizable", "chat.choice_card.button.disabled.accessibility.label", fallback: "Disabled") + internal static var label: String { Localization.tr("Localizable", "chat.choice_card.button.disabled.accessibility.label", fallback: "Disabled") } } } } internal enum Image { internal enum Accessibility { /// Choice card - internal static let label = Localization.tr("Localizable", "chat.choice_card.image.accessibility.label", fallback: "Choice card") + internal static var label: String { Localization.tr("Localizable", "chat.choice_card.image.accessibility.label", fallback: "Choice card") } } } } internal enum Download { /// Downloading file… - internal static let downloading = Localization.tr("Localizable", "chat.download.downloading", fallback: "Downloading file…") + internal static var downloading: String { Localization.tr("Localizable", "chat.download.downloading", fallback: "Downloading file…") } /// Could not download the file. - internal static let failed = Localization.tr("Localizable", "chat.download.failed", fallback: "Could not download the file.") + internal static var failed: String { Localization.tr("Localizable", "chat.download.failed", fallback: "Could not download the file.") } } internal enum File { internal enum InfectedFile { /// The safety of the file could not be confirmed. - internal static let error = Localization.tr("Localizable", "chat.file.infected_file.error", fallback: "The safety of the file could not be confirmed.") + internal static var error: String { Localization.tr("Localizable", "chat.file.infected_file.error", fallback: "The safety of the file could not be confirmed.") } } internal enum RemoveUpload { internal enum Accessibility { /// Remove upload - internal static let label = Localization.tr("Localizable", "chat.file.remove_upload.accessibility.label", fallback: "Remove upload") + internal static var label: String { Localization.tr("Localizable", "chat.file.remove_upload.accessibility.label", fallback: "Remove upload") } } } internal enum SizeLimit { /// File size must be less than 25 MB. - internal static let error = Localization.tr("Localizable", "chat.file.size_limit.error", fallback: "File size must be less than 25 MB.") + internal static var error: String { Localization.tr("Localizable", "chat.file.size_limit.error", fallback: "File size must be less than 25 MB.") } } internal enum Upload { /// Could not upload the file. - internal static let failed = Localization.tr("Localizable", "chat.file.upload.failed", fallback: "Could not upload the file.") + internal static var failed: String { Localization.tr("Localizable", "chat.file.upload.failed", fallback: "Could not upload the file.") } /// Could not upload the file. - internal static let genericError = Localization.tr("Localizable", "chat.file.upload.generic_error", fallback: "Could not upload the file.") + internal static var genericError: String { Localization.tr("Localizable", "chat.file.upload.generic_error", fallback: "Could not upload the file.") } /// Uploading file… - internal static let inProgress = Localization.tr("Localizable", "chat.file.upload.in_progress", fallback: "Uploading file…") + internal static var inProgress: String { Localization.tr("Localizable", "chat.file.upload.in_progress", fallback: "Uploading file…") } /// Could not upload the file due to a network issue. - internal static let networkError = Localization.tr("Localizable", "chat.file.upload.network_error", fallback: "Could not upload the file due to a network issue.") + internal static var networkError: String { Localization.tr("Localizable", "chat.file.upload.network_error", fallback: "Could not upload the file due to a network issue.") } /// Checking file security… - internal static let scanning = Localization.tr("Localizable", "chat.file.upload.scanning", fallback: "Checking file security…") + internal static var scanning: String { Localization.tr("Localizable", "chat.file.upload.scanning", fallback: "Checking file security…") } /// Ready to send - internal static let success = Localization.tr("Localizable", "chat.file.upload.success", fallback: "Ready to send") + internal static var success: String { Localization.tr("Localizable", "chat.file.upload.success", fallback: "Ready to send") } } } internal enum Input { /// Enter Message - internal static let placeholder = Localization.tr("Localizable", "chat.input.placeholder", fallback: "Enter Message") + internal static var placeholder: String { Localization.tr("Localizable", "chat.input.placeholder", fallback: "Enter Message") } } internal enum MediaUpgrade { internal enum Audio { /// Upgraded to Audio - internal static let systemMessage = Localization.tr("Localizable", "chat.media_upgrade.audio.system_message", fallback: "Upgraded to Audio") + internal static var systemMessage: String { Localization.tr("Localizable", "chat.media_upgrade.audio.system_message", fallback: "Upgraded to Audio") } } internal enum Video { /// Upgraded to Video - internal static let systemMessage = Localization.tr("Localizable", "chat.media_upgrade.video.system_message", fallback: "Upgraded to Video") + internal static var systemMessage: String { Localization.tr("Localizable", "chat.media_upgrade.video.system_message", fallback: "Upgraded to Video") } } } internal enum Message { /// Delivered - internal static let delivered = Localization.tr("Localizable", "chat.message.delivered", fallback: "Delivered") + internal static var delivered: String { Localization.tr("Localizable", "chat.message.delivered", fallback: "Delivered") } /// Send a message to start chatting - internal static let startEngagementPlaceholder = Localization.tr("Localizable", "chat.message.start_engagement_placeholder", fallback: "Send a message to start chatting") + internal static var startEngagementPlaceholder: String { Localization.tr("Localizable", "chat.message.start_engagement_placeholder", fallback: "Send a message to start chatting") } internal enum Unread { internal enum Accessibility { /// Unread messages - internal static let label = Localization.tr("Localizable", "chat.message.unread.accessibility.label", fallback: "Unread messages") + internal static var label: String { Localization.tr("Localizable", "chat.message.unread.accessibility.label", fallback: "Unread messages") } } } } internal enum OperatorAvatar { internal enum Accessibility { /// Operator Picture - internal static let label = Localization.tr("Localizable", "chat.operator_avatar.accessibility.label", fallback: "Operator Picture") + internal static var label: String { Localization.tr("Localizable", "chat.operator_avatar.accessibility.label", fallback: "Operator Picture") } } } internal enum OperatorJoined { /// {operatorName} has joined the conversation. - internal static let systemMessage = Localization.tr("Localizable", "chat.operator_joined.system_message", fallback: "{operatorName} has joined the conversation.") + internal static var systemMessage: String { Localization.tr("Localizable", "chat.operator_joined.system_message", fallback: "{operatorName} has joined the conversation.") } } internal enum OperatorName { internal enum Accessibility { /// Operator Name - internal static let label = Localization.tr("Localizable", "chat.operator_name.accessibility.label", fallback: "Operator Name") + internal static var label: String { Localization.tr("Localizable", "chat.operator_name.accessibility.label", fallback: "Operator Name") } } } internal enum Status { /// Operator is typing - internal static let typing = Localization.tr("Localizable", "chat.status.typing", fallback: "Operator is typing") + internal static var typing: String { Localization.tr("Localizable", "chat.status.typing", fallback: "Operator is typing") } internal enum Typing { internal enum Accessibility { /// {operatorName} is typing - internal static let label = Localization.tr("Localizable", "chat.status.typing.accessibility.label", fallback: "{operatorName} is typing") + internal static var label: String { Localization.tr("Localizable", "chat.status.typing.accessibility.label", fallback: "{operatorName} is typing") } } } } } internal enum Engagement { /// Operator - internal static let defaultOperator = Localization.tr("Localizable", "engagement.default_operator", fallback: "Operator") + internal static var defaultOperator: String { Localization.tr("Localizable", "engagement.default_operator", fallback: "Operator") } internal enum Audio { /// Audio - internal static let title = Localization.tr("Localizable", "engagement.audio.title", fallback: "Audio") + internal static var title: String { Localization.tr("Localizable", "engagement.audio.title", fallback: "Audio") } } internal enum Chat { /// Chat - internal static let title = Localization.tr("Localizable", "engagement.chat.title", fallback: "Chat") + internal static var title: String { Localization.tr("Localizable", "engagement.chat.title", fallback: "Chat") } } internal enum ConnectionScreen { /// Connecting with {operatorName} - internal static let connectWith = Localization.tr("Localizable", "engagement.connection_screen.connect_with", fallback: "Connecting with {operatorName}") + internal static var connectWith: String { Localization.tr("Localizable", "engagement.connection_screen.connect_with", fallback: "Connecting with {operatorName}") } /// We are here to help! - internal static let message = Localization.tr("Localizable", "engagement.connection_screen.message", fallback: "We are here to help!") + internal static var message: String { Localization.tr("Localizable", "engagement.connection_screen.message", fallback: "We are here to help!") } } internal enum End { /// Are you sure you want to end this engagement? - internal static let message = Localization.tr("Localizable", "engagement.end.message", fallback: "Are you sure you want to end this engagement?") + internal static var message: String { Localization.tr("Localizable", "engagement.end.message", fallback: "Are you sure you want to end this engagement?") } internal enum Confirmation { /// End Engagement? - internal static let header = Localization.tr("Localizable", "engagement.end.confirmation.header", fallback: "End Engagement?") + internal static var header: String { Localization.tr("Localizable", "engagement.end.confirmation.header", fallback: "End Engagement?") } } } internal enum Ended { /// Engagement Ended - internal static let header = Localization.tr("Localizable", "engagement.ended.header", fallback: "Engagement Ended") + internal static var header: String { Localization.tr("Localizable", "engagement.ended.header", fallback: "Engagement Ended") } /// This engagement has ended. /// Thank you! - internal static let message = Localization.tr("Localizable", "engagement.ended.message", fallback: "This engagement has ended.\nThank you!") + internal static var message: String { Localization.tr("Localizable", "engagement.ended.message", fallback: "This engagement has ended.\nThank you!") } } internal enum MediaUpgrade { /// {operatorName} has offered you to upgrade. - internal static let offer = Localization.tr("Localizable", "engagement.media_upgrade.offer", fallback: "{operatorName} has offered you to upgrade.") + internal static var offer: String { Localization.tr("Localizable", "engagement.media_upgrade.offer", fallback: "{operatorName} has offered you to upgrade.") } internal enum Audio { /// Speak through your device - internal static let info = Localization.tr("Localizable", "engagement.media_upgrade.audio.info", fallback: "Speak through your device") + internal static var info: String { Localization.tr("Localizable", "engagement.media_upgrade.audio.info", fallback: "Speak through your device") } } internal enum Phone { /// Enter your number and will call you back. - internal static let info = Localization.tr("Localizable", "engagement.media_upgrade.phone.info", fallback: "Enter your number and will call you back.") + internal static var info: String { Localization.tr("Localizable", "engagement.media_upgrade.phone.info", fallback: "Enter your number and will call you back.") } } } internal enum MinimizeVideo { /// Minimize - internal static let button = Localization.tr("Localizable", "engagement.minimize_video.button", fallback: "Minimize") + internal static var button: String { Localization.tr("Localizable", "engagement.minimize_video.button", fallback: "Minimize") } } internal enum Phone { /// Phone - internal static let title = Localization.tr("Localizable", "engagement.phone.title", fallback: "Phone") + internal static var title: String { Localization.tr("Localizable", "engagement.phone.title", fallback: "Phone") } } internal enum Queue { /// Transferring - internal static let transferring = Localization.tr("Localizable", "engagement.queue.transferring", fallback: "Transferring") + internal static var transferring: String { Localization.tr("Localizable", "engagement.queue.transferring", fallback: "Transferring") } internal enum Closed { /// We are sorry! The queue is closed. - internal static let header = Localization.tr("Localizable", "engagement.queue.closed.header", fallback: "We are sorry! The queue is closed.") + internal static var header: String { Localization.tr("Localizable", "engagement.queue.closed.header", fallback: "We are sorry! The queue is closed.") } /// Operators are no longer available. /// Please try again later. - internal static let message = Localization.tr("Localizable", "engagement.queue.closed.message", fallback: "Operators are no longer available. \nPlease try again later.") + internal static var message: String { Localization.tr("Localizable", "engagement.queue.closed.message", fallback: "Operators are no longer available. \nPlease try again later.") } } internal enum Leave { /// Are you sure you want to leave? - internal static let header = Localization.tr("Localizable", "engagement.queue.leave.header", fallback: "Are you sure you want to leave?") + internal static var header: String { Localization.tr("Localizable", "engagement.queue.leave.header", fallback: "Are you sure you want to leave?") } /// You will lose your place in the queue. - internal static let message = Localization.tr("Localizable", "engagement.queue.leave.message", fallback: "You will lose your place in the queue.") + internal static var message: String { Localization.tr("Localizable", "engagement.queue.leave.message", fallback: "You will lose your place in the queue.") } } internal enum Reconnection { /// Please try again later. - internal static let failed = Localization.tr("Localizable", "engagement.queue.reconnection.failed", fallback: "Please try again later.") + internal static var failed: String { Localization.tr("Localizable", "engagement.queue.reconnection.failed", fallback: "Please try again later.") } } } internal enum QueueWait { /// You can continue browsing and we will connect you automatically. - internal static let message = Localization.tr("Localizable", "engagement.queue_wait.message", fallback: "You can continue browsing and we will connect you automatically.") + internal static var message: String { Localization.tr("Localizable", "engagement.queue_wait.message", fallback: "You can continue browsing and we will connect you automatically.") } } internal enum SecureMessaging { /// Messaging - internal static let title = Localization.tr("Localizable", "engagement.secure_messaging.title", fallback: "Messaging") + internal static var title: String { Localization.tr("Localizable", "engagement.secure_messaging.title", fallback: "Messaging") } } internal enum Video { /// Video - internal static let title = Localization.tr("Localizable", "engagement.video.title", fallback: "Video") + internal static var title: String { Localization.tr("Localizable", "engagement.video.title", fallback: "Video") } } } internal enum Error { /// Something went wrong. - internal static let general = Localization.tr("Localizable", "error.general", fallback: "Something went wrong.") + internal static var general: String { Localization.tr("Localizable", "error.general", fallback: "Something went wrong.") } /// Something went wrong. - internal static let `internal` = Localization.tr("Localizable", "error.internal", fallback: "Something went wrong.") + internal static var `internal`: String { Localization.tr("Localizable", "error.internal", fallback: "Something went wrong.") } /// Something went wrong. - internal static let unexpected = Localization.tr("Localizable", "error.unexpected", fallback: "Something went wrong.") + internal static var unexpected: String { Localization.tr("Localizable", "error.unexpected", fallback: "Something went wrong.") } } internal enum General { /// Accept - internal static let accept = Localization.tr("Localizable", "general.accept", fallback: "Accept") + internal static var accept: String { Localization.tr("Localizable", "general.accept", fallback: "Accept") } /// Back - internal static let back = Localization.tr("Localizable", "general.back", fallback: "Back") + internal static var back: String { Localization.tr("Localizable", "general.back", fallback: "Back") } /// Browse - internal static let browse = Localization.tr("Localizable", "general.browse", fallback: "Browse") + internal static var browse: String { Localization.tr("Localizable", "general.browse", fallback: "Browse") } /// Cancel - internal static let cancel = Localization.tr("Localizable", "general.cancel", fallback: "Cancel") + internal static var cancel: String { Localization.tr("Localizable", "general.cancel", fallback: "Cancel") } /// Close - internal static let close = Localization.tr("Localizable", "general.close", fallback: "Close") + internal static var close: String { Localization.tr("Localizable", "general.close", fallback: "Close") } /// Comment - internal static let comment = Localization.tr("Localizable", "general.comment", fallback: "Comment") + internal static var comment: String { Localization.tr("Localizable", "general.comment", fallback: "Comment") } /// Company Name - internal static let companyName = Localization.tr("Localizable", "general.company_name", fallback: "Company Name") + internal static var companyName: String { Localization.tr("Localizable", "general.company_name", fallback: "Company Name") } /// Company Name without asking string provider - internal static let companyNameLocalFallbackOnly = Localization.tr("Localizable", "general.company_name", fallback: "Company Name", stringProviding: nil) + internal static var companyNameLocalFallbackOnly: String { Localization.tr("Localizable", "general.company_name", fallback: "Company Name", stringProviding: nil) } /// Decline - internal static let decline = Localization.tr("Localizable", "general.decline", fallback: "Decline") + internal static var decline: String { Localization.tr("Localizable", "general.decline", fallback: "Decline") } /// Download - internal static let download = Localization.tr("Localizable", "general.download", fallback: "Download") + internal static var download: String { Localization.tr("Localizable", "general.download", fallback: "Download") } /// End - internal static let end = Localization.tr("Localizable", "general.end", fallback: "End") + internal static var end: String { Localization.tr("Localizable", "general.end", fallback: "End") } /// Message - internal static let message = Localization.tr("Localizable", "general.message", fallback: "Message") + internal static var message: String { Localization.tr("Localizable", "general.message", fallback: "Message") } /// No - internal static let no = Localization.tr("Localizable", "general.no", fallback: "No") + internal static var no: String { Localization.tr("Localizable", "general.no", fallback: "No") } /// Ok - internal static let ok = Localization.tr("Localizable", "general.ok", fallback: "Ok") + internal static var ok: String { Localization.tr("Localizable", "general.ok", fallback: "Ok") } /// Open - internal static let `open` = Localization.tr("Localizable", "general.open", fallback: "Open") + internal static var `open`: String { Localization.tr("Localizable", "general.open", fallback: "Open") } /// Powered by - internal static let powered = Localization.tr("Localizable", "general.powered", fallback: "Powered by") + internal static var powered: String { Localization.tr("Localizable", "general.powered", fallback: "Powered by") } /// Refresh - internal static let refresh = Localization.tr("Localizable", "general.refresh", fallback: "Refresh") + internal static var refresh: String { Localization.tr("Localizable", "general.refresh", fallback: "Refresh") } /// Retry - internal static let retry = Localization.tr("Localizable", "general.retry", fallback: "Retry") + internal static var retry: String { Localization.tr("Localizable", "general.retry", fallback: "Retry") } /// Selected - internal static let selected = Localization.tr("Localizable", "general.selected", fallback: "Selected") + internal static var selected: String { Localization.tr("Localizable", "general.selected", fallback: "Selected") } /// Send - internal static let send = Localization.tr("Localizable", "general.send", fallback: "Send") + internal static var send: String { Localization.tr("Localizable", "general.send", fallback: "Send") } /// Sending… - internal static let sending = Localization.tr("Localizable", "general.sending", fallback: "Sending…") + internal static var sending: String { Localization.tr("Localizable", "general.sending", fallback: "Sending…") } /// Submit - internal static let submit = Localization.tr("Localizable", "general.submit", fallback: "Submit") + internal static var submit: String { Localization.tr("Localizable", "general.submit", fallback: "Submit") } /// Thank you! - internal static let thankYou = Localization.tr("Localizable", "general.thank_you", fallback: "Thank you!") + internal static var thankYou: String { Localization.tr("Localizable", "general.thank_you", fallback: "Thank you!") } /// Yes - internal static let yes = Localization.tr("Localizable", "general.yes", fallback: "Yes") + internal static var yes: String { Localization.tr("Localizable", "general.yes", fallback: "Yes") } /// You - internal static let you = Localization.tr("Localizable", "general.you", fallback: "You") + internal static var you: String { Localization.tr("Localizable", "general.you", fallback: "You") } internal enum Close { /// Close Button - internal static let accessibility = Localization.tr("Localizable", "general.close.accessibility", fallback: "Close Button") + internal static var accessibility: String { Localization.tr("Localizable", "general.close.accessibility", fallback: "Close Button") } } } internal enum Gva { internal enum UnsupportedAction { /// This action is not currently supported on mobile. - internal static let error = Localization.tr("Localizable", "gva.unsupported_action.error", fallback: "This action is not currently supported on mobile.") + internal static var error: String { Localization.tr("Localizable", "gva.unsupported_action.error", fallback: "This action is not currently supported on mobile.") } } } internal enum Ios { internal enum Alert { internal enum CameraAccess { /// Allow access to your camera in 'Settings' - 'Privacy & Security' - 'Camera' - internal static let message = Localization.tr("Localizable", "ios.alert.camera_access.message", fallback: "Allow access to your camera in 'Settings' - 'Privacy & Security' - 'Camera'") + internal static var message: String { Localization.tr("Localizable", "ios.alert.camera_access.message", fallback: "Allow access to your camera in 'Settings' - 'Privacy & Security' - 'Camera'") } } internal enum MediaSource { /// This media source is not available on your device - internal static let message = Localization.tr("Localizable", "ios.alert.media_source.message", fallback: "This media source is not available on your device") + internal static var message: String { Localization.tr("Localizable", "ios.alert.media_source.message", fallback: "This media source is not available on your device") } } internal enum MicrophoneAccess { /// Allow access to your microphone in 'Settings' - 'Privacy & Security' - 'Microphone' - internal static let message = Localization.tr("Localizable", "ios.alert.microphone_access.message", fallback: "Allow access to your microphone in 'Settings' - 'Privacy & Security' - 'Microphone'") + internal static var message: String { Localization.tr("Localizable", "ios.alert.microphone_access.message", fallback: "Allow access to your microphone in 'Settings' - 'Privacy & Security' - 'Microphone'") } } } internal enum Engagement { internal enum ConnectionScreen { /// (By default, your video will be turned off) - internal static let videoNotice = Localization.tr("Localizable", "ios.engagement.connection_screen.video_notice", fallback: "(By default, your video will be turned off)") + internal static var videoNotice: String { Localization.tr("Localizable", "ios.engagement.connection_screen.video_notice", fallback: "(By default, your video will be turned off)") } } } } internal enum MediaUpgrade { internal enum Audio { /// {operatorName} has offered you to upgrade to audio - internal static let title = Localization.tr("Localizable", "media_upgrade.audio.title", fallback: "{operatorName} has offered you to upgrade to audio") + internal static var title: String { Localization.tr("Localizable", "media_upgrade.audio.title", fallback: "{operatorName} has offered you to upgrade to audio") } } internal enum Video { internal enum OneWay { /// {operatorName} has offered you to see their video - internal static let title = Localization.tr("Localizable", "media_upgrade.video.one_way.title", fallback: "{operatorName} has offered you to see their video") + internal static var title: String { Localization.tr("Localizable", "media_upgrade.video.one_way.title", fallback: "{operatorName} has offered you to see their video") } } internal enum TwoWay { /// {operatorName} has offered you to upgrade to video - internal static let title = Localization.tr("Localizable", "media_upgrade.video.two_way.title", fallback: "{operatorName} has offered you to upgrade to video") + internal static var title: String { Localization.tr("Localizable", "media_upgrade.video.two_way.title", fallback: "{operatorName} has offered you to upgrade to video") } } } } internal enum MessageCenter { /// Messaging - internal static let header = Localization.tr("Localizable", "message_center.header", fallback: "Messaging") + internal static var header: String { Localization.tr("Localizable", "message_center.header", fallback: "Messaging") } internal enum Confirmation { /// Your message has been sent. We will get back to you within 48 hours. - internal static let subtitle = Localization.tr("Localizable", "message_center.confirmation.subtitle", fallback: "Your message has been sent. We will get back to you within 48 hours.") + internal static var subtitle: String { Localization.tr("Localizable", "message_center.confirmation.subtitle", fallback: "Your message has been sent. We will get back to you within 48 hours.") } internal enum CheckMessages { internal enum Accessibility { /// Navigates you to the chat transcript. - internal static let hint = Localization.tr("Localizable", "message_center.confirmation.check_messages.accessibility.hint", fallback: "Navigates you to the chat transcript.") + internal static var hint: String { Localization.tr("Localizable", "message_center.confirmation.check_messages.accessibility.hint", fallback: "Navigates you to the chat transcript.") } /// Check messages - internal static let label = Localization.tr("Localizable", "message_center.confirmation.check_messages.accessibility.label", fallback: "Check messages") + internal static var label: String { Localization.tr("Localizable", "message_center.confirmation.check_messages.accessibility.label", fallback: "Check messages") } } } } internal enum NotAuthenticated { /// We could not verify your authentication status. - internal static let message = Localization.tr("Localizable", "message_center.not_authenticated.message", fallback: "We could not verify your authentication status.") + internal static var message: String { Localization.tr("Localizable", "message_center.not_authenticated.message", fallback: "We could not verify your authentication status.") } } internal enum Unavailable { /// The Message Center is currently unavailable. Please try again later. - internal static let message = Localization.tr("Localizable", "message_center.unavailable.message", fallback: "The Message Center is currently unavailable. Please try again later.") + internal static var message: String { Localization.tr("Localizable", "message_center.unavailable.message", fallback: "The Message Center is currently unavailable. Please try again later.") } /// Message Center Unavailable - internal static let title = Localization.tr("Localizable", "message_center.unavailable.title", fallback: "Message Center Unavailable") + internal static var title: String { Localization.tr("Localizable", "message_center.unavailable.title", fallback: "Message Center Unavailable") } } internal enum Welcome { /// Check messages - internal static let checkMessages = Localization.tr("Localizable", "message_center.welcome.check_messages", fallback: "Check messages") + internal static var checkMessages: String { Localization.tr("Localizable", "message_center.welcome.check_messages", fallback: "Check messages") } /// Your message - internal static let messageTitle = Localization.tr("Localizable", "message_center.welcome.message_title", fallback: "Your message") + internal static var messageTitle: String { Localization.tr("Localizable", "message_center.welcome.message_title", fallback: "Your message") } /// Send a message and we will get back to you within 48 hours. - internal static let subtitle = Localization.tr("Localizable", "message_center.welcome.subtitle", fallback: "Send a message and we will get back to you within 48 hours.") + internal static var subtitle: String { Localization.tr("Localizable", "message_center.welcome.subtitle", fallback: "Send a message and we will get back to you within 48 hours.") } /// Welcome to Message Center - internal static let title = Localization.tr("Localizable", "message_center.welcome.title", fallback: "Welcome to Message Center") + internal static var title: String { Localization.tr("Localizable", "message_center.welcome.title", fallback: "Welcome to Message Center") } internal enum CheckMessages { internal enum Accessibility { /// Navigates you to the chat transcript. - internal static let hint = Localization.tr("Localizable", "message_center.welcome.check_messages.accessibility.hint", fallback: "Navigates you to the chat transcript.") + internal static var hint: String { Localization.tr("Localizable", "message_center.welcome.check_messages.accessibility.hint", fallback: "Navigates you to the chat transcript.") } } } internal enum FilePicker { internal enum Accessibility { /// Opens the file picker to attach media. - internal static let hint = Localization.tr("Localizable", "message_center.welcome.file_picker.accessibility.hint", fallback: "Opens the file picker to attach media.") + internal static var hint: String { Localization.tr("Localizable", "message_center.welcome.file_picker.accessibility.hint", fallback: "Opens the file picker to attach media.") } /// File picker - internal static let label = Localization.tr("Localizable", "message_center.welcome.file_picker.accessibility.label", fallback: "File picker") + internal static var label: String { Localization.tr("Localizable", "message_center.welcome.file_picker.accessibility.label", fallback: "File picker") } } } internal enum MessageInput { /// Enter your message - internal static let placeholder = Localization.tr("Localizable", "message_center.welcome.message_input.placeholder", fallback: "Enter your message") + internal static var placeholder: String { Localization.tr("Localizable", "message_center.welcome.message_input.placeholder", fallback: "Enter your message") } } internal enum MessageLength { /// The message cannot exceed 10,000 characters. - internal static let error = Localization.tr("Localizable", "message_center.welcome.message_length.error", fallback: "The message cannot exceed 10,000 characters.") + internal static var error: String { Localization.tr("Localizable", "message_center.welcome.message_length.error", fallback: "The message cannot exceed 10,000 characters.") } } internal enum Send { internal enum Accessibility { /// Sends a secure message. - internal static let hint = Localization.tr("Localizable", "message_center.welcome.send.accessibility.hint", fallback: "Sends a secure message.") + internal static var hint: String { Localization.tr("Localizable", "message_center.welcome.send.accessibility.hint", fallback: "Sends a secure message.") } } } } @@ -566,16 +566,16 @@ internal enum Localization { internal enum VisitorScreen { internal enum Disclaimer { /// Depending on your selection, your entire screen might be shared with the operator, not just the application window. - internal static let info = Localization.tr("Localizable", "screen_sharing.visitor_screen.disclaimer.info", fallback: "Depending on your selection, your entire screen might be shared with the operator, not just the application window.") + internal static var info: String { Localization.tr("Localizable", "screen_sharing.visitor_screen.disclaimer.info", fallback: "Depending on your selection, your entire screen might be shared with the operator, not just the application window.") } /// You are about to share your screen - internal static let title = Localization.tr("Localizable", "screen_sharing.visitor_screen.disclaimer.title", fallback: "You are about to share your screen") + internal static var title: String { Localization.tr("Localizable", "screen_sharing.visitor_screen.disclaimer.title", fallback: "You are about to share your screen") } } internal enum End { /// End Screen Sharing - internal static let title = Localization.tr("Localizable", "screen_sharing.visitor_screen.end.title", fallback: "End Screen Sharing") + internal static var title: String { Localization.tr("Localizable", "screen_sharing.visitor_screen.end.title", fallback: "End Screen Sharing") } internal enum Accessibility { /// Ends screen sharing - internal static let hint = Localization.tr("Localizable", "screen_sharing.visitor_screen.end.accessibility.hint", fallback: "Ends screen sharing") + internal static var hint: String { Localization.tr("Localizable", "screen_sharing.visitor_screen.end.accessibility.hint", fallback: "Ends screen sharing") } } } } @@ -583,33 +583,33 @@ internal enum Localization { internal enum Survey { internal enum Action { /// Please provide an answer. - internal static let validationError = Localization.tr("Localizable", "survey.action.validation_error", fallback: "Please provide an answer.") + internal static var validationError: String { Localization.tr("Localizable", "survey.action.validation_error", fallback: "Please provide an answer.") } } internal enum Question { internal enum Input { internal enum Accessibility { /// Enter the answer - internal static let hint = Localization.tr("Localizable", "survey.question.input.accessibility.hint", fallback: "Enter the answer") + internal static var hint: String { Localization.tr("Localizable", "survey.question.input.accessibility.hint", fallback: "Enter the answer") } } } internal enum OptionButton { internal enum Selected { internal enum Accessibility { /// Selected: {buttonTitle} - internal static let label = Localization.tr("Localizable", "survey.question.option_button.selected.accessibility.label", fallback: "Selected: {buttonTitle}") + internal static var label: String { Localization.tr("Localizable", "survey.question.option_button.selected.accessibility.label", fallback: "Selected: {buttonTitle}") } } } internal enum Unselected { internal enum Accessibility { /// Unselected: {buttonTitle} - internal static let label = Localization.tr("Localizable", "survey.question.option_button.unselected.accessibility.label", fallback: "Unselected: {buttonTitle}") + internal static var label: String { Localization.tr("Localizable", "survey.question.option_button.unselected.accessibility.label", fallback: "Unselected: {buttonTitle}") } } } } internal enum Required { internal enum Accessibility { /// This is a required question. - internal static let label = Localization.tr("Localizable", "survey.question.required.accessibility.label", fallback: "This is a required question.") + internal static var label: String { Localization.tr("Localizable", "survey.question.required.accessibility.label", fallback: "This is a required question.") } } } } @@ -617,14 +617,14 @@ internal enum Localization { internal enum Title { internal enum Accessibility { /// Please provide an answer for the question above. - internal static let label = Localization.tr("Localizable", "survey.validation.title.accessibility.label", fallback: "Please provide an answer for the question above.") + internal static var label: String { Localization.tr("Localizable", "survey.validation.title.accessibility.label", fallback: "Please provide an answer for the question above.") } } } } } internal enum VisitorCode { /// Could not load the visitor code. Please try refreshing. - internal static let failed = Localization.tr("Localizable", "visitor_code.failed", fallback: "Could not load the visitor code. Please try refreshing.") + internal static var failed: String { Localization.tr("Localizable", "visitor_code.failed", fallback: "Could not load the visitor code. Please try refreshing.") } } } // swiftlint:enable explicit_type_interface function_parameter_count identifier_name line_length diff --git a/GliaWidgets/Public/Configuration/Configuration+Mock.swift b/GliaWidgets/Public/Configuration/Configuration+Mock.swift index 409453c4a..c1956ed95 100644 --- a/GliaWidgets/Public/Configuration/Configuration+Mock.swift +++ b/GliaWidgets/Public/Configuration/Configuration+Mock.swift @@ -8,13 +8,15 @@ extension Configuration { authMethod: AuthorizationMethod = .siteApiKey(id: "site-api-key-id", secret: "site-api-key-secret"), environment: Environment = .beta, site: String = "site-id", - companyName: String = "" + companyName: String = "", + manualLocaleOverride: String? = nil ) -> Self { Configuration( authorizationMethod: authMethod, environment: environment, site: site, - companyName: companyName + companyName: companyName, + manualLocaleOverride: manualLocaleOverride ) } } diff --git a/GliaWidgets/Public/Configuration/Configuration.swift b/GliaWidgets/Public/Configuration/Configuration.swift index 84f688404..15f110eec 100644 --- a/GliaWidgets/Public/Configuration/Configuration.swift +++ b/GliaWidgets/Public/Configuration/Configuration.swift @@ -17,6 +17,9 @@ public struct Configuration { public let isWhiteLabelApp: Bool /// Company name. Appears during connection with operator. public let companyName: String + /// The name of the manual locale override. If not set, or if set as `nil`, + /// then the default locale from site settings will be used. + public var manualLocaleOverride: String? /// Initializes the configuration. /// /// - Parameters: @@ -24,7 +27,8 @@ public struct Configuration { /// - environment: The environment to use. /// - site: The site to use. /// - visitorContext: Additional context about the visitor that operator may need. - /// + /// - manualLocaleOverride: The name of the manual locale override. + /// If not set, or if set as `nil`, then the default locale from site settings will be used. public init( authorizationMethod: AuthorizationMethod, environment: Environment, @@ -32,7 +36,8 @@ public struct Configuration { visitorContext: VisitorContext? = nil, pushNotifications: PushNotifications = .disabled, isWhiteLabelApp: Bool = false, - companyName: String = "" + companyName: String = "", + manualLocaleOverride: String? = nil ) { self.authorizationMethod = authorizationMethod self.environment = environment @@ -41,6 +46,7 @@ public struct Configuration { self.pushNotifications = pushNotifications self.isWhiteLabelApp = isWhiteLabelApp self.companyName = companyName + self.manualLocaleOverride = manualLocaleOverride } } diff --git a/GliaWidgets/Public/Glia/Glia.swift b/GliaWidgets/Public/Glia/Glia.swift index f0ec3cbe8..a34c951b8 100644 --- a/GliaWidgets/Public/Glia/Glia.swift +++ b/GliaWidgets/Public/Glia/Glia.swift @@ -149,9 +149,23 @@ public class Glia { } completion(.success(())) - case let .failure(error): + case .failure(let error): + typealias ProcessError = CoreSdkClient.ConfigurationProcessError + var errorForCompletion: GliaError = .internalError + + // To avoid the integrator having to figure out if an error is a `GliaError` + // or a `ConfigurationProcessError`, the `ConfigurationProcessError` is translated + // into a `GliaError`. + if let processError = error as? ProcessError { + if processError == .invalidSiteApiKeyCredentials { + errorForCompletion = GliaError.invalidSiteApiKeyCredentials + } else if processError == .localeRetrieval { + errorForCompletion = GliaError.invalidLocale + } + } + debugPrint("💥 Core SDK configuration is not valid. Unexpected error='\(error)'.") - completion(.failure(error)) + completion(.failure(errorForCompletion)) } } } diff --git a/GliaWidgets/Public/GliaError.swift b/GliaWidgets/Public/GliaError.swift index ee9349849..e651b77ab 100644 --- a/GliaWidgets/Public/GliaError.swift +++ b/GliaWidgets/Public/GliaError.swift @@ -7,5 +7,7 @@ public enum GliaError: Error { case configuringDuringEngagementIsNotAllowed case clearingVisitorSessionDuringEngagementIsNotAllowed case startingEngagementWithNoQueueIdsIsNotAllowed + case invalidSiteApiKeyCredentials + case invalidLocale case internalError } diff --git a/GliaWidgets/Sources/Coordinators/Chat/ChatCoordinator.swift b/GliaWidgets/Sources/Coordinators/Chat/ChatCoordinator.swift index 1dc4d1170..e92c5b29d 100644 --- a/GliaWidgets/Sources/Coordinators/Chat/ChatCoordinator.swift +++ b/GliaWidgets/Sources/Coordinators/Chat/ChatCoordinator.swift @@ -78,7 +78,6 @@ class ChatCoordinator: SubFlowCoordinator, FlowCoordinator { ) self.controller = chatController return chatController - } private func presentMediaPickerController( diff --git a/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Interface.swift b/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Interface.swift index d734c0285..19c5a279b 100644 --- a/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Interface.swift +++ b/GliaWidgets/Sources/CoreSDKClient/CoreSDKClient.Interface.swift @@ -198,6 +198,7 @@ extension CoreSdkClient { typealias FileError = GliaCoreSDK.FileError typealias GeneralError = GliaCoreSDK.GeneralError typealias GliaCoreError = GliaCoreSDK.GliaCoreError + typealias ConfigurationProcessError = GliaCoreSDK.GliaCore.ConfigurationProcessError typealias Interactable = GliaCoreSDK.Interactable typealias MediaDirection = GliaCoreSDK.MediaDirection typealias MediaError = GliaCoreSDK.MediaError diff --git a/GliaWidgets/Sources/CoreSDKConfigurator/CoreSDKConfigurator.Interface.swift b/GliaWidgets/Sources/CoreSDKConfigurator/CoreSDKConfigurator.Interface.swift index 3fa83ef96..6613b4eb2 100644 --- a/GliaWidgets/Sources/CoreSDKConfigurator/CoreSDKConfigurator.Interface.swift +++ b/GliaWidgets/Sources/CoreSDKConfigurator/CoreSDKConfigurator.Interface.swift @@ -14,7 +14,8 @@ extension CoreSDKConfigurator { siteId: configuration.site, region: configuration.environment.region, authorizingMethod: configuration.authorizationMethod.coreAuthorizationMethod, - pushNotifications: configuration.pushNotifications.coreSdk + pushNotifications: configuration.pushNotifications.coreSdk, + manualLocaleOverride: configuration.manualLocaleOverride ) coreSdk.configureWithConfiguration(sdkConfiguration, completion) } diff --git a/TestingApp/Extensions/Configuration.Extensions.swift b/TestingApp/Extensions/Configuration.Extensions.swift index eb5c29634..25d79e252 100644 --- a/TestingApp/Extensions/Configuration.Extensions.swift +++ b/TestingApp/Extensions/Configuration.Extensions.swift @@ -8,7 +8,8 @@ extension Configuration { .init( authorizationMethod: .siteApiKey(id: "", secret: ""), environment: env, - site: "" + site: "", + manualLocaleOverride: nil ) } } @@ -25,15 +26,17 @@ extension Configuration { return nil } - let visitorAssetId = queryItems.first(where: { $0.name == "visitor_context_asset_id" })?.value ?? "" + let visitorAssetId = queryItems.first { $0.name == "visitor_context_asset_id" }?.value ?? "" let visitorContext = UUID(uuidString: visitorAssetId) .map(Configuration.VisitorContext.init(assetId:)) + let manualLocaleOverride = queryItems.first { $0.name == "manual_locale_override" }?.value ?? nil self = .init( authorizationMethod: .siteApiKey(id: siteApiKeyId, secret: siteApiKeySecret), environment: environment, site: siteId, - visitorContext: visitorContext + visitorContext: visitorContext, + manualLocaleOverride: manualLocaleOverride ) } } @@ -56,7 +59,12 @@ private extension Environment { extension Configuration: Codable { enum CodingKeys: String, CodingKey { - case authorizationMethod, environment, site, visitorContext, pushNotifications + case authorizationMethod, + environment, + site, + visitorContext, + pushNotifications, + manualLocaleOverride } public init(from decoder: Decoder) throws { @@ -66,7 +74,8 @@ extension Configuration: Codable { environment: container.decode(Environment.self, forKey: .environment), site: container.decode(String.self, forKey: .site), visitorContext: container.decodeIfPresent(VisitorContext.self, forKey: .visitorContext), - pushNotifications: container.decodeIfPresent(PushNotifications.self, forKey: .pushNotifications) ?? .disabled + pushNotifications: container.decodeIfPresent(PushNotifications.self, forKey: .pushNotifications) ?? .disabled, + manualLocaleOverride: container.decodeIfPresent(String.self, forKey: .manualLocaleOverride) ?? nil ) } @@ -77,6 +86,7 @@ extension Configuration: Codable { try container.encode(site, forKey: .site) try container.encode(visitorContext, forKey: .visitorContext) try container.encode(pushNotifications, forKey: .pushNotifications) + try container.encode(manualLocaleOverride, forKey: .manualLocaleOverride) } } @@ -163,6 +173,8 @@ extension Configuration.PushNotifications: RawRepresentable, Codable { return "sandbox" case .production: return "production" + @unknown default: + return "" } } diff --git a/TestingApp/Settings/SettingsViewController.swift b/TestingApp/Settings/SettingsViewController.swift index f09d123ac..141c1c227 100644 --- a/TestingApp/Settings/SettingsViewController.swift +++ b/TestingApp/Settings/SettingsViewController.swift @@ -15,6 +15,7 @@ final class SettingsViewController: UIViewController { private var queueIDCell: SettingsTextCell! private var environmentCell: EnvironmentSettingsTextCell! private var visitorContextAssedIdCell: SettingsTextCell! + private var manualLocaleOverrideCell: SettingsTextCell! private var bubbleFeatureCell: SettingsSwitchCell! private var primaryColorCell: SettingsColorCell! private var secondaryColorCell: SettingsColorCell! @@ -151,6 +152,13 @@ private extension SettingsViewController { text: props.config.visitorContext?.assetId.uuidString ?? "" ) visitorContextAssedIdCell.textField.accessibilityIdentifier = "settings_visitor_context_assetId_textfield" + + manualLocaleOverrideCell = SettingsTextCell( + title: "Manual locale override:", + text: props.config.manualLocaleOverride ?? "" + ) + manualLocaleOverrideCell.textField.accessibilityIdentifier = "settings_manual_locale_override_textfield" + bubbleFeatureCell = SettingsSwitchCell( title: "Present \"Bubble\" overlay in engagement time", isOn: props.features ~= .bubbleView @@ -272,7 +280,8 @@ private extension SettingsViewController { siteApiKeyIdCell, siteApiKeySecretCell, queueIDCell, - visitorContextAssedIdCell + visitorContextAssedIdCell, + manualLocaleOverrideCell ] configurationSection = Section( title: "Glia configuration", @@ -284,12 +293,16 @@ private extension SettingsViewController { private func updateConfiguration() { let uuid = UUID(uuidString: visitorContextAssedIdCell.textField.text ?? "") + let manualLocaleOverrideText = manualLocaleOverrideCell.textField.text ?? "" + let manualLocaleOverride = manualLocaleOverrideText.isEmpty ? nil : manualLocaleOverrideText + props.changeConfig( Configuration( authorizationMethod: siteApiKey, environment: environmentCell.environment, site: siteCell.textField.text ?? "", - visitorContext: uuid.map { Configuration.VisitorContext(assetId: $0) } + visitorContext: uuid.map { Configuration.VisitorContext(assetId: $0) }, + manualLocaleOverride: manualLocaleOverride ) ) diff --git a/TestingApp/ViewController/ViewController.swift b/TestingApp/ViewController/ViewController.swift index e90b66357..09f0b36d5 100644 --- a/TestingApp/ViewController/ViewController.swift +++ b/TestingApp/ViewController/ViewController.swift @@ -91,7 +91,6 @@ class ViewController: UIViewController { private func showErrorAlert(using error: Error) { if let gliaError = error as? GliaError { - switch gliaError { case GliaError.engagementExists: alert(message: "Failed to start\nEngagement is ongoing, please use 'Resume' button") @@ -101,6 +100,10 @@ class ViewController: UIViewController { alert(message: "Failed to start\nCall Visualizer engagement is ongoing") case GliaError.configuringDuringEngagementIsNotAllowed: alert(message: "The operation couldn't be completed. '\(gliaError)'.") + case GliaError.invalidSiteApiKeyCredentials: + alert(message: "Failed to configure the SDK, invalid credentials") + case GliaError.invalidLocale: + alert(message: "Failed to configure the SDK, invalid locale override specified") default: alert(message: "Failed to start\nCheck Glia parameters in Settings") } @@ -240,6 +243,7 @@ extension ViewController { self?.configureButton.accessibilityIdentifier = originalIdentifier debugPrint(printable) } + do { try Glia.sharedInstance.configure( with: configuration @@ -249,7 +253,7 @@ extension ViewController { completionBlock("SDK has been configured") completion?(.success(())) case let .failure(error): - completionBlock(error) + completionBlock("Error configuring the SDK") completion?(.failure(error)) } } @@ -373,7 +377,6 @@ extension ViewController { } func setupPushHandler() { - let waitForActiveEngagement = GliaCore.sharedInstance.waitForActiveEngagement(completion:) GliaCore.sharedInstance.pushNotifications.handler = { [weak self] push in switch (push.type, push.timing) { // Open chat transcript only when the push notification has come @@ -403,19 +406,26 @@ extension ViewController { @IBAction private func toggleAuthentication() { catchingError { - try Glia.sharedInstance.configure(with: configuration) { [weak self] in + try Glia.sharedInstance.configure(with: configuration) { [weak self] result in guard let self = self else { return } - self.catchingError { - let authentication = try Self.authentication() - switch authentication.isAuthenticated { - case false: - self.showAuthorize(with: authentication) - case true: - self.showDeauthorize( - authorization: authentication, - from: self.toggleAuthenticateButton - ) + + switch result { + case .success: + self.catchingError { + let authentication = try Self.authentication() + switch authentication.isAuthenticated { + case false: + self.showAuthorize(with: authentication) + case true: + self.showDeauthorize( + authorization: authentication, + from: self.toggleAuthenticateButton + ) + } } + + case .failure(let error): + self.showErrorAlert(using: error) } } } diff --git a/swiftgen-strings.stencil b/swiftgen-strings.stencil index db9773940..d1cc07106 100644 --- a/swiftgen-strings.stencil +++ b/swiftgen-strings.stencil @@ -54,10 +54,10 @@ import Foundation {% elif param.lookupFunction %} {{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { return {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") } {% else %} - {{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}} = {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") + {{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}: String { {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}") } {% if string.key == "general.company_name" %} /// {{translation}} without asking string provider - {{accessModifier}} static let {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}LocalFallbackOnly = {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}", stringProviding: nil) + {{accessModifier}} static var {{string.name|swiftIdentifier:"pretty"|lowerFirstWord|escapeReservedKeywords}}LocalFallbackOnly: String { {{enumName}}.tr("{{table}}", "{{string.key}}", fallback: "{{translation}}", stringProviding: nil) } {% endif %} {% endif %} {% endfor %}