From cc2728aaa8893db70ab249d2bc5212d48dfa33e0 Mon Sep 17 00:00:00 2001 From: Dmitry Lyzlov Date: Wed, 21 Jun 2023 13:42:31 +0300 Subject: [PATCH] Added localization into iOS share extension (#7351) --- app/utils/file/index.ts | 13 +- assets/base/i18n/en.json | 6 +- fastlane/Fastfile | 19 +- ios/Mattermost.xcodeproj/project.pbxproj | 272 +++++++++++++++++- .../i18n/ar.lproj/Localizable.strings | 0 .../i18n/bg.lproj/Localizable.strings | 0 .../i18n/de.lproj/Localizable.strings | 0 .../i18n/en.lproj/Localizable.strings | 0 .../i18n/en_AU.lproj/Localizable.strings | 0 .../i18n/es.lproj/Localizable.strings | 0 .../i18n/fa.lproj/Localizable.strings | 0 .../i18n/fr.lproj/Localizable.strings | 0 .../i18n/hu.lproj/Localizable.strings | 0 .../i18n/it.lproj/Localizable.strings | 0 .../i18n/ja.lproj/Localizable.strings | 0 .../i18n/ko.lproj/Localizable.strings | 0 .../i18n/nl.lproj/Localizable.strings | 0 .../i18n/pl.lproj/Localizable.strings | 0 .../i18n/pt-BR.lproj/Localizable.strings | 0 .../i18n/ro.lproj/Localizable.strings | 0 .../i18n/ru.lproj/Localizable.strings | 0 .../i18n/sv.lproj/Localizable.strings | 0 .../i18n/tr.lproj/Localizable.strings | 0 .../i18n/uk.lproj/Localizable.strings | 0 .../i18n/zh-CN.lproj/Localizable.strings | 0 .../i18n/zh-TW.lproj/Localizable.strings | 0 ios/MattermostShare/Extensions/Int64.swift | 5 +- .../Extensions/NumberFormatter.swift | 25 ++ ios/MattermostShare/Info.plist | 2 + .../AttachmentsViews/AttachmentsView.swift | 22 +- .../MultipleAttachmentView.swift | 14 +- .../ChannelListView/ChannelListView.swift | 9 +- .../ChannelListView/SearchBarView.swift | 14 +- .../Views/ContentViews/ContentView.swift | 18 +- .../ContentViews/FloatingTextField.swift | 11 +- .../Views/ErrorViews/ErrorSharingView.swift | 41 ++- .../Views/ErrorViews/NoMembershipView.swift | 22 +- .../Views/ErrorViews/NoServersView.swift | 22 +- ios/MattermostShare/Views/InitialView.swift | 12 +- share_extension/screens/channels.tsx | 12 +- share_extension/screens/share.tsx | 26 +- 41 files changed, 495 insertions(+), 70 deletions(-) create mode 100644 ios/Mattermost/i18n/ar.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/bg.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/de.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/en.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/en_AU.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/es.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/fa.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/fr.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/hu.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/it.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/ja.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/ko.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/nl.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/pl.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/pt-BR.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/ro.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/ru.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/sv.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/tr.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/uk.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/zh-CN.lproj/Localizable.strings create mode 100644 ios/Mattermost/i18n/zh-TW.lproj/Localizable.strings create mode 100644 ios/MattermostShare/Extensions/NumberFormatter.swift diff --git a/app/utils/file/index.ts b/app/utils/file/index.ts index 8b1e124cce6..0edde674f41 100644 --- a/app/utils/file/index.ts +++ b/app/utils/file/index.ts @@ -495,11 +495,14 @@ export const hasWriteStoragePermission = async (intl: IntlShape) => { }, {applicationName}, ); - const text = intl.formatMessage({ - id: 'mobile.write_storage_permission_denied_description', - defaultMessage: - 'Save files to your device. Open Settings to grant {applicationName} write access to files on this device.', - }); + const text = intl.formatMessage( + { + id: 'mobile.write_storage_permission_denied_description', + defaultMessage: + 'Save files to your device. Open Settings to grant {applicationName} write access to files on this device.', + }, + {applicationName}, + ); Alert.alert(title, text, [ { diff --git a/assets/base/i18n/en.json b/assets/base/i18n/en.json index d3f8a7ca9ce..8d287c6ae03 100644 --- a/assets/base/i18n/en.json +++ b/assets/base/i18n/en.json @@ -952,7 +952,11 @@ "settings.save": "Save", "share_extension.channel_error": "You are not a member of a team on the selected server. Select another server or open Mattermost to join a team.", "share_extension.channel_label": "Channel", + "share_extension.channels_screen.title": "Select channel", "share_extension.count_limit": "You can only share {count, number} {count, plural, one {file} other {files}} on this server", + "share_extension.error_screen.description": "There was an error when attempting to share the content to {applicationName}.", + "share_extension.error_screen.label": "An error ocurred", + "share_extension.error_screen.reason": "Reason: {reason}", "share_extension.file_limit.multiple": "Each file must be less than {size}", "share_extension.file_limit.single": "File must be less than {size}", "share_extension.max_resolution": "Image exceeds maximum dimensions of 7680 x 4320 px", @@ -960,7 +964,7 @@ "share_extension.multiple_label": "{count, number} attachments", "share_extension.server_label": "Server", "share_extension.servers_screen.title": "Select server", - "share_extension.share_screen.title": "Share to Mattermost", + "share_extension.share_screen.title": "Share to {applicationName}", "share_extension.upload_disabled": "File uploads are disabled for the selected server", "share_feedback.button.no": "No, thanks", "share_feedback.button.yes": "Yes", diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 313a9734cbb..b68c01d824e 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -415,7 +415,7 @@ platform :ios do end lane :update_identifiers do - # Set the name for the app + # Set the name for the app and share extension app_name = ENV['APP_NAME'] || 'Mattermost Beta' update_info_plist( xcodeproj: './ios/Mattermost.xcodeproj', @@ -423,6 +423,12 @@ platform :ios do display_name: app_name ) + update_info_plist( + xcodeproj: './ios/Mattermost.xcodeproj', + plist_path: 'MattermostShare/Info.plist', + display_name: app_name + ) + # Set the notification service extension bundle identifier notification_bundle_id = ENV['NOTIFICATION_SERVICE_IDENTIFIER'] || 'com.mattermost.rnbeta.NotificationService' update_app_identifier( @@ -563,20 +569,27 @@ platform :ios do json = JSON.parse(localization_file) plist_strings = '' + localized_strings = '' json.each do |key, value| - if key.match?('mobile.ios.plist') - unless value.nil? || value.empty? + unless value.nil? || value.empty? + if key.match?('mobile.ios.plist') plist_strings.concat("#{key.split('.').last} = \"#{value}\";\n") + else + value.gsub!('\\', '\\\\\\\\') # How to replace backslash with double backslash https://stackoverflow.com/a/6209532 + value.gsub!('"', '\"') + localized_strings.concat("\"#{key}\" = \"#{value}\";\n") end end end plist_strings.gsub!('{applicationName}', "#{app_name}") + localized_strings.gsub!('{applicationName}', "#{app_name}") language = item.split('.').first project_localization_path = "../ios/Mattermost/i18n/#{language}.lproj" FileUtils.mkdir_p project_localization_path File.write("#{project_localization_path}/InfoPlist.strings", plist_strings) + File.write("#{project_localization_path}/Localizable.strings", localized_strings) end end diff --git a/ios/Mattermost.xcodeproj/project.pbxproj b/ios/Mattermost.xcodeproj/project.pbxproj index 9616503f4dc..c3525776bfe 100644 --- a/ios/Mattermost.xcodeproj/project.pbxproj +++ b/ios/Mattermost.xcodeproj/project.pbxproj @@ -62,6 +62,29 @@ 672D98B029F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D988229F1927F004228D6 /* InfoPlist.strings */; }; 672D98B129F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D988529F1927F004228D6 /* InfoPlist.strings */; }; 672D98B229F1927F004228D6 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 672D988529F1927F004228D6 /* InfoPlist.strings */; }; + 67AE0FC52A0556A500810C56 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67AE0FC32A0556A500810C56 /* Localizable.strings */; }; + 67FEADD92A0E96DD00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADD62A0E96DD00DDF4AE /* Localizable.strings */; }; + 67FEADDD2A12602A00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADDA2A12602A00DDF4AE /* Localizable.strings */; }; + 67FEADE12A12603600DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADDE2A12603600DDF4AE /* Localizable.strings */; }; + 67FEADE52A12603F00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADE22A12603F00DDF4AE /* Localizable.strings */; }; + 67FEADE92A12604900DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADE62A12604900DDF4AE /* Localizable.strings */; }; + 67FEADED2A12608900DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADEA2A12608900DDF4AE /* Localizable.strings */; }; + 67FEADF12A12609300DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADEE2A12609300DDF4AE /* Localizable.strings */; }; + 67FEADF52A1260A900DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADF22A1260A900DDF4AE /* Localizable.strings */; }; + 67FEADF92A1260B200DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADF62A1260B200DDF4AE /* Localizable.strings */; }; + 67FEAE012A1260C200DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADFE2A1260C200DDF4AE /* Localizable.strings */; }; + 67FEAE052A1260CA00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE022A1260C900DDF4AE /* Localizable.strings */; }; + 67FEAE092A12611B00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE062A12611B00DDF4AE /* Localizable.strings */; }; + 67FEAE0D2A12612500DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE0A2A12612500DDF4AE /* Localizable.strings */; }; + 67FEAE112A12613000DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE0E2A12613000DDF4AE /* Localizable.strings */; }; + 67FEAE152A12614F00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE122A12614F00DDF4AE /* Localizable.strings */; }; + 67FEAE192A12615900DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE162A12615900DDF4AE /* Localizable.strings */; }; + 67FEAE1D2A12616500DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE1A2A12616500DDF4AE /* Localizable.strings */; }; + 67FEAE212A12616F00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE1E2A12616F00DDF4AE /* Localizable.strings */; }; + 67FEAE252A12618000DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE222A12618000DDF4AE /* Localizable.strings */; }; + 67FEAE292A1261A000DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEAE262A1261A000DDF4AE /* Localizable.strings */; }; + 67FEAE2A2A1261EA00DDF4AE /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 67FEADFA2A1260B900DDF4AE /* Localizable.strings */; }; + 67FEAE2C2A127C3600DDF4AE /* NumberFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67FEAE2B2A127C3600DDF4AE /* NumberFormatter.swift */; }; 6C9B1EFD6561083917AF06CF /* libPods-Mattermost.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 8DEEFB3ED6175724A2653247 /* libPods-Mattermost.a */; }; 7F0F4B0A24BA173900E14C60 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 7F0F4B0924BA173900E14C60 /* LaunchScreen.storyboard */; }; 7F151D3E221B062700FAD8F3 /* RuntimeUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F151D3D221B062700FAD8F3 /* RuntimeUtils.swift */; }; @@ -246,6 +269,29 @@ 672D988029F1927F004228D6 /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = InfoPlist.strings; sourceTree = ""; }; 672D988329F1927F004228D6 /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = InfoPlist.strings; sourceTree = ""; }; 672D988629F1927F004228D6 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = InfoPlist.strings; sourceTree = ""; }; + 67AE0FC42A0556A500810C56 /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = Localizable.strings; sourceTree = ""; }; + 67FEADD72A0E96DD00DDF4AE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = Localizable.strings; sourceTree = ""; }; + 67FEADDB2A12602A00DDF4AE /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = Localizable.strings; sourceTree = ""; }; + 67FEADDF2A12603600DDF4AE /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = Localizable.strings; sourceTree = ""; }; + 67FEADE32A12603F00DDF4AE /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = Localizable.strings; sourceTree = ""; }; + 67FEADE72A12604900DDF4AE /* en_AU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en_AU; path = Localizable.strings; sourceTree = ""; }; + 67FEADEB2A12608900DDF4AE /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = Localizable.strings; sourceTree = ""; }; + 67FEADEF2A12609300DDF4AE /* fa */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fa; path = Localizable.strings; sourceTree = ""; }; + 67FEADF32A1260A900DDF4AE /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = Localizable.strings; sourceTree = ""; }; + 67FEADF72A1260B200DDF4AE /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = Localizable.strings; sourceTree = ""; }; + 67FEADFB2A1260B900DDF4AE /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = Localizable.strings; sourceTree = ""; }; + 67FEADFF2A1260C200DDF4AE /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = Localizable.strings; sourceTree = ""; }; + 67FEAE032A1260C900DDF4AE /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = Localizable.strings; sourceTree = ""; }; + 67FEAE072A12611B00DDF4AE /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = Localizable.strings; sourceTree = ""; }; + 67FEAE0B2A12612500DDF4AE /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = Localizable.strings; sourceTree = ""; }; + 67FEAE0F2A12613000DDF4AE /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = Localizable.strings; sourceTree = ""; }; + 67FEAE132A12614F00DDF4AE /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = Localizable.strings; sourceTree = ""; }; + 67FEAE172A12615900DDF4AE /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = Localizable.strings; sourceTree = ""; }; + 67FEAE1B2A12616500DDF4AE /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = Localizable.strings; sourceTree = ""; }; + 67FEAE1F2A12616F00DDF4AE /* zh-CN */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-CN"; path = Localizable.strings; sourceTree = ""; }; + 67FEAE232A12618000DDF4AE /* zh-TW */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-TW"; path = Localizable.strings; sourceTree = ""; }; + 67FEAE272A1261A000DDF4AE /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = Localizable.strings; sourceTree = ""; }; + 67FEAE2B2A127C3600DDF4AE /* NumberFormatter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NumberFormatter.swift; sourceTree = ""; }; 6BAF8296411D4657B5A0E8F8 /* libRNReactNativeDocViewer.a */ = {isa = PBXFileReference; explicitFileType = undefined; fileEncoding = 9; includeInIndex = 0; lastKnownFileType = archive.ar; path = libRNReactNativeDocViewer.a; sourceTree = ""; }; 7F0F4B0924BA173900E14C60 /* LaunchScreen.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = LaunchScreen.storyboard; path = SplashScreenResource/LaunchScreen.storyboard; sourceTree = ""; }; 7F151D3D221B062700FAD8F3 /* RuntimeUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RuntimeUtils.swift; path = Mattermost/RuntimeUtils.swift; sourceTree = ""; }; @@ -512,6 +558,7 @@ 672D984529F1927E004228D6 /* de.lproj */ = { isa = PBXGroup; children = ( + 67FEADE22A12603F00DDF4AE /* Localizable.strings */, 672D984629F1927E004228D6 /* InfoPlist.strings */, ); name = de.lproj; @@ -521,6 +568,7 @@ 672D984829F1927E004228D6 /* ja.lproj */ = { isa = PBXGroup; children = ( + 67FEADFE2A1260C200DDF4AE /* Localizable.strings */, 672D984929F1927E004228D6 /* InfoPlist.strings */, ); name = ja.lproj; @@ -530,6 +578,7 @@ 672D984B29F1927E004228D6 /* fa.lproj */ = { isa = PBXGroup; children = ( + 67FEADEE2A12609300DDF4AE /* Localizable.strings */, 672D984C29F1927E004228D6 /* InfoPlist.strings */, ); name = fa.lproj; @@ -539,6 +588,7 @@ 672D984E29F1927F004228D6 /* pl.lproj */ = { isa = PBXGroup; children = ( + 67FEAE0A2A12612500DDF4AE /* Localizable.strings */, 672D984F29F1927F004228D6 /* InfoPlist.strings */, ); name = pl.lproj; @@ -548,6 +598,7 @@ 672D985129F1927F004228D6 /* ar.lproj */ = { isa = PBXGroup; children = ( + 67FEADDA2A12602A00DDF4AE /* Localizable.strings */, 672D985229F1927F004228D6 /* InfoPlist.strings */, ); name = ar.lproj; @@ -557,6 +608,7 @@ 672D985429F1927F004228D6 /* sv.lproj */ = { isa = PBXGroup; children = ( + 67FEAE122A12614F00DDF4AE /* Localizable.strings */, 672D985529F1927F004228D6 /* InfoPlist.strings */, ); name = sv.lproj; @@ -566,6 +618,7 @@ 672D985729F1927F004228D6 /* ru.lproj */ = { isa = PBXGroup; children = ( + 67AE0FC32A0556A500810C56 /* Localizable.strings */, 672D985829F1927F004228D6 /* InfoPlist.strings */, ); name = ru.lproj; @@ -575,6 +628,7 @@ 672D985A29F1927F004228D6 /* ro.lproj */ = { isa = PBXGroup; children = ( + 67FEAE262A1261A000DDF4AE /* Localizable.strings */, 672D985B29F1927F004228D6 /* InfoPlist.strings */, ); name = ro.lproj; @@ -584,6 +638,7 @@ 672D985D29F1927F004228D6 /* bg.lproj */ = { isa = PBXGroup; children = ( + 67FEADDE2A12603600DDF4AE /* Localizable.strings */, 672D985E29F1927F004228D6 /* InfoPlist.strings */, ); name = bg.lproj; @@ -593,6 +648,7 @@ 672D986029F1927F004228D6 /* tr.lproj */ = { isa = PBXGroup; children = ( + 67FEAE162A12615900DDF4AE /* Localizable.strings */, 672D986129F1927F004228D6 /* InfoPlist.strings */, ); name = tr.lproj; @@ -602,6 +658,7 @@ 672D986329F1927F004228D6 /* zh-TW.lproj */ = { isa = PBXGroup; children = ( + 67FEAE222A12618000DDF4AE /* Localizable.strings */, 672D986429F1927F004228D6 /* InfoPlist.strings */, ); name = "zh-TW.lproj"; @@ -611,6 +668,7 @@ 672D986629F1927F004228D6 /* en.lproj */ = { isa = PBXGroup; children = ( + 67FEADD62A0E96DD00DDF4AE /* Localizable.strings */, 672D986729F1927F004228D6 /* InfoPlist.strings */, ); name = en.lproj; @@ -620,6 +678,7 @@ 672D986929F1927F004228D6 /* en_AU.lproj */ = { isa = PBXGroup; children = ( + 67FEADE62A12604900DDF4AE /* Localizable.strings */, 672D986A29F1927F004228D6 /* InfoPlist.strings */, ); name = en_AU.lproj; @@ -629,6 +688,7 @@ 672D986C29F1927F004228D6 /* hu.lproj */ = { isa = PBXGroup; children = ( + 67FEADF62A1260B200DDF4AE /* Localizable.strings */, 672D986D29F1927F004228D6 /* InfoPlist.strings */, ); name = hu.lproj; @@ -638,6 +698,7 @@ 672D986F29F1927F004228D6 /* fr.lproj */ = { isa = PBXGroup; children = ( + 67FEADF22A1260A900DDF4AE /* Localizable.strings */, 672D987029F1927F004228D6 /* InfoPlist.strings */, ); name = fr.lproj; @@ -647,6 +708,7 @@ 672D987229F1927F004228D6 /* ko.lproj */ = { isa = PBXGroup; children = ( + 67FEAE022A1260C900DDF4AE /* Localizable.strings */, 672D987329F1927F004228D6 /* InfoPlist.strings */, ); name = ko.lproj; @@ -656,6 +718,7 @@ 672D987529F1927F004228D6 /* zh-CN.lproj */ = { isa = PBXGroup; children = ( + 67FEAE1E2A12616F00DDF4AE /* Localizable.strings */, 672D987629F1927F004228D6 /* InfoPlist.strings */, ); name = "zh-CN.lproj"; @@ -665,6 +728,7 @@ 672D987829F1927F004228D6 /* es.lproj */ = { isa = PBXGroup; children = ( + 67FEADEA2A12608900DDF4AE /* Localizable.strings */, 672D987929F1927F004228D6 /* InfoPlist.strings */, ); name = es.lproj; @@ -674,6 +738,7 @@ 672D987B29F1927F004228D6 /* it.lproj */ = { isa = PBXGroup; children = ( + 67FEADFA2A1260B900DDF4AE /* Localizable.strings */, 672D987C29F1927F004228D6 /* InfoPlist.strings */, ); name = it.lproj; @@ -683,6 +748,7 @@ 672D987E29F1927F004228D6 /* nl.lproj */ = { isa = PBXGroup; children = ( + 67FEAE062A12611B00DDF4AE /* Localizable.strings */, 672D987F29F1927F004228D6 /* InfoPlist.strings */, ); name = nl.lproj; @@ -692,6 +758,7 @@ 672D988129F1927F004228D6 /* pt-BR.lproj */ = { isa = PBXGroup; children = ( + 67FEAE0E2A12613000DDF4AE /* Localizable.strings */, 672D988229F1927F004228D6 /* InfoPlist.strings */, ); name = "pt-BR.lproj"; @@ -701,6 +768,7 @@ 672D988429F1927F004228D6 /* uk.lproj */ = { isa = PBXGroup; children = ( + 67FEAE1A2A12616500DDF4AE /* Localizable.strings */, 672D988529F1927F004228D6 /* InfoPlist.strings */, ); name = uk.lproj; @@ -784,6 +852,7 @@ 7F7E9F432864E6AF0064BFAF /* Extensions */ = { isa = PBXGroup; children = ( + 67FEAE2B2A127C3600DDF4AE /* NumberFormatter.swift */, 7F7E9F442864E6C60064BFAF /* Color.swift */, 7F7E9F452864E6C60064BFAF /* View.swift */, 7F93AAAD287725660047B89F /* Int64.swift */, @@ -1197,8 +1266,17 @@ 672D98AA29F1927F004228D6 /* InfoPlist.strings in Resources */, 672D989029F1927F004228D6 /* InfoPlist.strings in Resources */, 672D989A29F1927F004228D6 /* InfoPlist.strings in Resources */, + 67FEADF52A1260A900DDF4AE /* Localizable.strings in Resources */, + 67FEADD92A0E96DD00DDF4AE /* Localizable.strings in Resources */, + 67FEAE092A12611B00DDF4AE /* Localizable.strings in Resources */, + 67FEADE52A12603F00DDF4AE /* Localizable.strings in Resources */, 7FD4825E2864DC5800A5B18B /* Metropolis-Regular.ttf in Resources */, + 67FEAE252A12618000DDF4AE /* Localizable.strings in Resources */, + 67FEADF92A1260B200DDF4AE /* Localizable.strings in Resources */, + 67FEAE1D2A12616500DDF4AE /* Localizable.strings in Resources */, 7FD4825F2864DC5800A5B18B /* Metropolis-SemiBold.ttf in Resources */, + 67FEAE0D2A12612500DDF4AE /* Localizable.strings in Resources */, + 67FEADE92A12604900DDF4AE /* Localizable.strings in Resources */, 7FD482602864DC5800A5B18B /* OpenSans-Bold.ttf in Resources */, 7FD482612864DC5800A5B18B /* OpenSans-BoldItalic.ttf in Resources */, 672D988829F1927F004228D6 /* InfoPlist.strings in Resources */, @@ -1207,21 +1285,34 @@ 672D989429F1927F004228D6 /* InfoPlist.strings in Resources */, 672D98A029F1927F004228D6 /* InfoPlist.strings in Resources */, 672D989229F1927F004228D6 /* InfoPlist.strings in Resources */, + 67FEAE292A1261A000DDF4AE /* Localizable.strings in Resources */, 7FD482632864DC5900A5B18B /* OpenSans-ExtraBoldItalic.ttf in Resources */, 672D988E29F1927F004228D6 /* InfoPlist.strings in Resources */, 7FD482642864DC5900A5B18B /* OpenSans-Italic.ttf in Resources */, 672D989C29F1927F004228D6 /* InfoPlist.strings in Resources */, 672D98A229F1927F004228D6 /* InfoPlist.strings in Resources */, 672D988C29F1927F004228D6 /* InfoPlist.strings in Resources */, + 67FEADF12A12609300DDF4AE /* Localizable.strings in Resources */, + 67FEAE112A12613000DDF4AE /* Localizable.strings in Resources */, + 67AE0FC52A0556A500810C56 /* Localizable.strings in Resources */, + 67FEAE152A12614F00DDF4AE /* Localizable.strings in Resources */, 7FD482652864DC5900A5B18B /* OpenSans-Light.ttf in Resources */, 672D98AE29F1927F004228D6 /* InfoPlist.strings in Resources */, + 67FEAE052A1260CA00DDF4AE /* Localizable.strings in Resources */, + 67FEAE2A2A1261EA00DDF4AE /* Localizable.strings in Resources */, + 67FEAE012A1260C200DDF4AE /* Localizable.strings in Resources */, 7FD482662864DC5900A5B18B /* OpenSans-LightItalic.ttf in Resources */, 7FD482672864DC5900A5B18B /* OpenSans-Regular.ttf in Resources */, 672D98B229F1927F004228D6 /* InfoPlist.strings in Resources */, 672D989829F1927F004228D6 /* InfoPlist.strings in Resources */, + 67FEADE12A12603600DDF4AE /* Localizable.strings in Resources */, + 67FEAE192A12615900DDF4AE /* Localizable.strings in Resources */, + 67FEADDD2A12602A00DDF4AE /* Localizable.strings in Resources */, 7FD482682864DC5900A5B18B /* OpenSans-SemiBold.ttf in Resources */, 672D98AC29F1927F004228D6 /* InfoPlist.strings in Resources */, + 67FEAE212A12616F00DDF4AE /* Localizable.strings in Resources */, 7FD482692864DC5900A5B18B /* OpenSans-SemiBoldItalic.ttf in Resources */, + 67FEADED2A12608900DDF4AE /* Localizable.strings in Resources */, 7FD4825C2864DC4200A5B18B /* compass-icons.ttf in Resources */, 7FD482292864D69700A5B18B /* Assets.xcassets in Resources */, 672D98A829F1927F004228D6 /* InfoPlist.strings in Resources */, @@ -1413,6 +1504,7 @@ 7F1EBFCE286F2AE200824AF1 /* MultipleAttachmentView.swift in Sources */, 7F7E9F792864E8160064BFAF /* SearchBarView.swift in Sources */, 7FB50D222856E1AB0035ACB5 /* ShareUIView.swift in Sources */, + 67FEAE2C2A127C3600DDF4AE /* NumberFormatter.swift in Sources */, 7F93AAA828761FA10047B89F /* NoMembershipView.swift in Sources */, 7F7E9F772864E8160064BFAF /* LinkPreview.swift in Sources */, 7F7E9F782864E8160064BFAF /* OptionView.swift in Sources */, @@ -1634,6 +1726,182 @@ name = InfoPlist.strings; sourceTree = ""; }; + 67AE0FC32A0556A500810C56 /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67AE0FC42A0556A500810C56 /* ru */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADD62A0E96DD00DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADD72A0E96DD00DDF4AE /* en */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADDA2A12602A00DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADDB2A12602A00DDF4AE /* ar */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADDE2A12603600DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADDF2A12603600DDF4AE /* bg */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADE22A12603F00DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADE32A12603F00DDF4AE /* de */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADE62A12604900DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADE72A12604900DDF4AE /* en_AU */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADEA2A12608900DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADEB2A12608900DDF4AE /* es */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADEE2A12609300DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADEF2A12609300DDF4AE /* fa */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADF22A1260A900DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADF32A1260A900DDF4AE /* fr */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADF62A1260B200DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADF72A1260B200DDF4AE /* hu */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADFA2A1260B900DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADFB2A1260B900DDF4AE /* it */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEADFE2A1260C200DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEADFF2A1260C200DDF4AE /* ja */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE022A1260C900DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE032A1260C900DDF4AE /* ko */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE062A12611B00DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE072A12611B00DDF4AE /* nl */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE0A2A12612500DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE0B2A12612500DDF4AE /* pl */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE0E2A12613000DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE0F2A12613000DDF4AE /* pt-BR */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE122A12614F00DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE132A12614F00DDF4AE /* sv */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE162A12615900DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE172A12615900DDF4AE /* tr */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE1A2A12616500DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE1B2A12616500DDF4AE /* uk */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE1E2A12616F00DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE1F2A12616F00DDF4AE /* zh-CN */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE222A12618000DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE232A12618000DDF4AE /* zh-TW */, + ); + name = Localizable.strings; + sourceTree = ""; + }; + 67FEAE262A1261A000DDF4AE /* Localizable.strings */ = { + isa = PBXVariantGroup; + children = ( + 67FEAE272A1261A000DDF4AE /* ro */, + ); + name = Localizable.strings; + sourceTree = ""; + }; 7FC5698A28563FDB000B0905 /* MainInterface.storyboard */ = { isa = PBXVariantGroup; children = ( @@ -1848,8 +2116,6 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = MattermostShare/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = MattermostShare; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved."; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1899,8 +2165,6 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GENERATE_INFOPLIST_FILE = YES; INFOPLIST_FILE = MattermostShare/Info.plist; - INFOPLIST_KEY_CFBundleDisplayName = MattermostShare; - INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved."; IPHONEOS_DEPLOYMENT_TARGET = 15.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", diff --git a/ios/Mattermost/i18n/ar.lproj/Localizable.strings b/ios/Mattermost/i18n/ar.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/bg.lproj/Localizable.strings b/ios/Mattermost/i18n/bg.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/de.lproj/Localizable.strings b/ios/Mattermost/i18n/de.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/en.lproj/Localizable.strings b/ios/Mattermost/i18n/en.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/en_AU.lproj/Localizable.strings b/ios/Mattermost/i18n/en_AU.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/es.lproj/Localizable.strings b/ios/Mattermost/i18n/es.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/fa.lproj/Localizable.strings b/ios/Mattermost/i18n/fa.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/fr.lproj/Localizable.strings b/ios/Mattermost/i18n/fr.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/hu.lproj/Localizable.strings b/ios/Mattermost/i18n/hu.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/it.lproj/Localizable.strings b/ios/Mattermost/i18n/it.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/ja.lproj/Localizable.strings b/ios/Mattermost/i18n/ja.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/ko.lproj/Localizable.strings b/ios/Mattermost/i18n/ko.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/nl.lproj/Localizable.strings b/ios/Mattermost/i18n/nl.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/pl.lproj/Localizable.strings b/ios/Mattermost/i18n/pl.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/pt-BR.lproj/Localizable.strings b/ios/Mattermost/i18n/pt-BR.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/ro.lproj/Localizable.strings b/ios/Mattermost/i18n/ro.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/ru.lproj/Localizable.strings b/ios/Mattermost/i18n/ru.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/sv.lproj/Localizable.strings b/ios/Mattermost/i18n/sv.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/tr.lproj/Localizable.strings b/ios/Mattermost/i18n/tr.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/uk.lproj/Localizable.strings b/ios/Mattermost/i18n/uk.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/zh-CN.lproj/Localizable.strings b/ios/Mattermost/i18n/zh-CN.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/Mattermost/i18n/zh-TW.lproj/Localizable.strings b/ios/Mattermost/i18n/zh-TW.lproj/Localizable.strings new file mode 100644 index 00000000000..e69de29bb2d diff --git a/ios/MattermostShare/Extensions/Int64.swift b/ios/MattermostShare/Extensions/Int64.swift index a816b3606fe..11eb0bc9229 100644 --- a/ios/MattermostShare/Extensions/Int64.swift +++ b/ios/MattermostShare/Extensions/Int64.swift @@ -22,10 +22,7 @@ extension Int64 { let i = floor(log(size) / log(k)) // Format number with thousands separator and everything below 1 giga with no decimal places. - let numberFormatter = NumberFormatter() - numberFormatter.maximumFractionDigits = i < 3 ? 0 : 1 - numberFormatter.numberStyle = .decimal - + let numberFormatter = i < 3 ? NumberFormatter.noFractionDigitsDecimalFormatter : NumberFormatter.oneFractionDigitDecimalFormatter let numberString = numberFormatter.string(from: NSNumber(value: size / pow(k, i))) ?? "Unknown" let suffix = suffixes[Int(i)] return "\(numberString) \(suffix)" diff --git a/ios/MattermostShare/Extensions/NumberFormatter.swift b/ios/MattermostShare/Extensions/NumberFormatter.swift new file mode 100644 index 00000000000..37c63e52186 --- /dev/null +++ b/ios/MattermostShare/Extensions/NumberFormatter.swift @@ -0,0 +1,25 @@ +// +// NumberFormatter.swift +// MattermostShare +// +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. +// + +import Foundation + +extension NumberFormatter { + static let noFractionDigitsDecimalFormatter: NumberFormatter = { + let numberFormatter = NumberFormatter() + numberFormatter.maximumFractionDigits = 0 + numberFormatter.numberStyle = .decimal + return numberFormatter + }() + + static let oneFractionDigitDecimalFormatter: NumberFormatter = { + let numberFormatter = NumberFormatter() + numberFormatter.maximumFractionDigits = 1 + numberFormatter.numberStyle = .decimal + return numberFormatter + }() +} diff --git a/ios/MattermostShare/Info.plist b/ios/MattermostShare/Info.plist index c34fcbcaff8..10cc0dd26eb 100644 --- a/ios/MattermostShare/Info.plist +++ b/ios/MattermostShare/Info.plist @@ -77,5 +77,7 @@ $(SENTRY_DSN_IOS) SENTRY_ENABLED $(SENTRY_ENABLED) + NSHumanReadableCopyright + Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. diff --git a/ios/MattermostShare/Views/ContentViews/AttachmentsViews/AttachmentsView.swift b/ios/MattermostShare/Views/ContentViews/AttachmentsViews/AttachmentsView.swift index 747a998807c..4ec438106cd 100644 --- a/ios/MattermostShare/Views/ContentViews/AttachmentsViews/AttachmentsView.swift +++ b/ios/MattermostShare/Views/ContentViews/AttachmentsViews/AttachmentsView.swift @@ -15,16 +15,30 @@ struct AttachmentsView: View { var error: String? { if let server = shareViewModel.server { if server.uploadsDisabled { - return "File uploads are disabled for the selected server" + return NSLocalizedString("share_extension.upload_disabled", + value: "File uploads are disabled for the selected server", + comment: "" + ) } let sizeError = attachments.contains { $0.sizeError(server: server)} let resolutionError = attachments.contains { $0.resolutionError(server: server)} if sizeError && attachments.count == 1 { - return "File must be less than \(server.maxFileSize.formattedFileSize)" + return NSLocalizedString("share_extension.file_limit.single", + value: "File must be less than {size}", + comment: "" + ) + .replacingOccurrences(of: "{size}", with: server.maxFileSize.formattedFileSize) } else if sizeError { - return "Each file must be less than \(server.maxFileSize.formattedFileSize)" + return NSLocalizedString("share_extension.file_limit.multiple", + value: "Each file must be less than {size}", + comment: "" + ) + .replacingOccurrences(of: "{size}", with: server.maxFileSize.formattedFileSize) } else if resolutionError { - return "Image exceeds maximum dimensions of 7680 x 4320 px" + return NSLocalizedString("share_extension.max_resolution", + value: "Image exceeds maximum dimensions of 7680 x 4320 px", + comment: "" + ) } } diff --git a/ios/MattermostShare/Views/ContentViews/AttachmentsViews/MultipleAttachmentView.swift b/ios/MattermostShare/Views/ContentViews/AttachmentsViews/MultipleAttachmentView.swift index 6fea9879ace..36ded952b69 100644 --- a/ios/MattermostShare/Views/ContentViews/AttachmentsViews/MultipleAttachmentView.swift +++ b/ios/MattermostShare/Views/ContentViews/AttachmentsViews/MultipleAttachmentView.swift @@ -65,10 +65,16 @@ struct MultipleAttachmentView: View { } if (attachments.count > 1) { - Text("\(attachments.count) attachments") - .foregroundColor(Color.theme.centerChannelColor.opacity(0.64)) - .font(Font.custom("OpenSans", size: 12)) - .padding(.leading, 20) + Text( + NSLocalizedString("share_extension.multiple_label", + value: "{count, number} attachments", + comment: "" + ) + .replacingOccurrences(of: "{count, number}", with: "\(attachments.count)") + ) + .foregroundColor(Color.theme.centerChannelColor.opacity(0.64)) + .font(Font.custom("OpenSans", size: 12)) + .padding(.leading, 20) } } } diff --git a/ios/MattermostShare/Views/ContentViews/ChannelListView/ChannelListView.swift b/ios/MattermostShare/Views/ContentViews/ChannelListView/ChannelListView.swift index 0221f0d1cdd..70dea64100b 100644 --- a/ios/MattermostShare/Views/ContentViews/ChannelListView/ChannelListView.swift +++ b/ios/MattermostShare/Views/ContentViews/ChannelListView/ChannelListView.swift @@ -16,9 +16,12 @@ struct ChannelListView: View { SearchBarView() if shareViewModel.search.isEmpty { HStack { - Text("RECENT") - .font(Font.custom("OpenSans-SemiBold", size: 12)) - .foregroundColor(Color.theme.centerChannelColor.opacity(0.64)) + Text( + NSLocalizedString("mobile.channel_list.recent", value: "Recent", comment: "") + .uppercased() + ) + .font(Font.custom("OpenSans-SemiBold", size: 12)) + .foregroundColor(Color.theme.centerChannelColor.opacity(0.64)) Spacer() } .padding(.top, 20) diff --git a/ios/MattermostShare/Views/ContentViews/ChannelListView/SearchBarView.swift b/ios/MattermostShare/Views/ContentViews/ChannelListView/SearchBarView.swift index 09f01fb1f17..98a65a7fcf1 100644 --- a/ios/MattermostShare/Views/ContentViews/ChannelListView/SearchBarView.swift +++ b/ios/MattermostShare/Views/ContentViews/ChannelListView/SearchBarView.swift @@ -16,8 +16,10 @@ struct SearchBarView: View { HStack { TextField("", text: $shareViewModel.search) .placeholder(when: shareViewModel.search.isEmpty) { - Text("Find channels...") - .foregroundColor(Color.theme.centerChannelColor.opacity(0.64)) + Text( + NSLocalizedString("channel_list.find_channels", value: "Find channels...", comment: "") + ) + .foregroundColor(Color.theme.centerChannelColor.opacity(0.64)) } .padding(.leading, 40) .padding(.trailing, 30) @@ -59,9 +61,11 @@ struct SearchBarView: View { if isEditing { Button(action: dismissKeyboard) { - Text("Cancel") - .foregroundColor(Color.theme.centerChannelColor) - .font(Font.custom("OpenSans", size: 14)) + Text( + NSLocalizedString("mobile.post.cancel", value: "Cancel", comment: "") + ) + .foregroundColor(Color.theme.centerChannelColor) + .font(Font.custom("OpenSans", size: 14)) } .transition(.move(edge: .trailing)) .animation(.linear(duration: 0.15)) diff --git a/ios/MattermostShare/Views/ContentViews/ContentView.swift b/ios/MattermostShare/Views/ContentViews/ContentView.swift index a8f992a76b0..c13c6800502 100644 --- a/ios/MattermostShare/Views/ContentViews/ContentView.swift +++ b/ios/MattermostShare/Views/ContentViews/ContentView.swift @@ -41,8 +41,8 @@ struct ContentView: View { VStack (spacing: 0) { if shareViewModel.allServers.count > 1 { OptionView( - navigationTitle: "Select server", - label: "Server", + navigationTitle: NSLocalizedString("share_extension.servers_screen.title", value: "Select server", comment: ""), + label: NSLocalizedString("share_extension.server_label", value: "Server", comment: ""), value: shareViewModel.server!.displayName ) { ServerListView() @@ -51,8 +51,8 @@ struct ContentView: View { } if hasChannels { OptionView( - navigationTitle: "Select channel", - label: "Channel", + navigationTitle: NSLocalizedString("share_extension.channels_screen.title", value: "Select channel", comment: ""), + label: NSLocalizedString("share_extension.channel_label", value: "Channel", comment: ""), value: "\(shareViewModel.channel!.displayName) \(shareViewModel.channel!.formattedTeamName)" ) { ChannelListView() @@ -66,10 +66,16 @@ struct ContentView: View { .padding(.bottom, 10) if hasChannels { - FloatingTextField(placeholderText: "Enter a message (optional)", text: $message) + FloatingTextField( + placeholderText: NSLocalizedString("share_extension.message", value: "Enter a message (optional)", comment: ""), + text: $message + ) } else { ErrorLabelView( - error: "You are not a member of a team on the selected server. Select another server or open Mattermost to join a team." + error: NSLocalizedString("share_extension.channel_error", + value: "You are not a member of a team on the selected server. Select another server or open Mattermost to join a team.", + comment: "" + ) ) } diff --git a/ios/MattermostShare/Views/ContentViews/FloatingTextField.swift b/ios/MattermostShare/Views/ContentViews/FloatingTextField.swift index cd0309c8d31..fb8b20057ff 100644 --- a/ios/MattermostShare/Views/ContentViews/FloatingTextField.swift +++ b/ios/MattermostShare/Views/ContentViews/FloatingTextField.swift @@ -53,9 +53,7 @@ struct FloatingTextField: View { } func formatLength(_ value: Int64) -> String { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.maximumFractionDigits = 0 + let formatter = NumberFormatter.noFractionDigitsDecimalFormatter let number = NSNumber(value: value) return formatter.string(from: number)! } @@ -64,7 +62,12 @@ struct FloatingTextField: View { VStack (alignment: .leading) { if (error) { ErrorLabelView( - error: "Message must be less than \(formatLength(shareViewModel.server!.maxMessageLength)) characters" + error: NSLocalizedString("mobile.message_length.message", + value: "Your current message is too long. Current character count: {count}/{max}", + comment: "" + ) + .replacingOccurrences(of: "{count}", with: formatLength(Int64(text.count))) + .replacingOccurrences(of: "{max}", with: formatLength(shareViewModel.server!.maxMessageLength)) ) } ZStack(alignment: .topLeading) { diff --git a/ios/MattermostShare/Views/ErrorViews/ErrorSharingView.swift b/ios/MattermostShare/Views/ErrorViews/ErrorSharingView.swift index beb9e3c910a..81e5293191d 100644 --- a/ios/MattermostShare/Views/ErrorViews/ErrorSharingView.swift +++ b/ios/MattermostShare/Views/ErrorViews/ErrorSharingView.swift @@ -22,21 +22,40 @@ struct ErrorSharingView: View { NotificationCenter.default.post(name: Notification.Name("submit"), object: nil, userInfo: nil) } } else { - Text("An error ocurred") - .font(Font.custom("Metropolis-SemiBold", size: 20)) - .foregroundColor(Color.theme.centerChannelColor) - Text("There was an error when attempting to share the content to Mattermost.") - .font(Font.custom("OpenSans", size: 16)) + Text( + NSLocalizedString("share_extension.error_screen.label", value: "An error ocurred", comment: "") + ) + .font(Font.custom("Metropolis-SemiBold", size: 20)) + .foregroundColor(Color.theme.centerChannelColor) + Text( + NSLocalizedString("share_extension.error_screen.description", + value: "There was an error when attempting to share the content to {applicationName}.", + comment: "" + ) + .replacingOccurrences( + of: "{applicationName}", + with: Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "Mattermost Beta" + ) + ) + .font(Font.custom("OpenSans", size: 16)) .foregroundColor(Color.theme.centerChannelColor.opacity(0.72)) - Text("Reason: \(error)") - .font(Font.custom("OpenSans", size: 12)) - .foregroundColor(Color.theme.centerChannelColor.opacity(0.60)) + Text( + NSLocalizedString("share_extension.error_screen.reason", + value: "Reason: {reason}", + comment: "" + ) + .replacingOccurrences(of: "{reason}", with: error) + ) + .font(Font.custom("OpenSans", size: 12)) + .foregroundColor(Color.theme.centerChannelColor.opacity(0.60)) Button { retrying = true } label: { - Text("Try again") - .font(Font.custom("OpenSans", size: 16)) - .foregroundColor(Color.theme.buttonColor) + Text( + NSLocalizedString("mobile.post.failed_retry", value: "Try again", comment: "") + ) + .font(Font.custom("OpenSans", size: 16)) + .foregroundColor(Color.theme.buttonColor) } .buttonStyle(.borderedProminent) .tint(Color.theme.buttonBg) diff --git a/ios/MattermostShare/Views/ErrorViews/NoMembershipView.swift b/ios/MattermostShare/Views/ErrorViews/NoMembershipView.swift index ed29e537259..0a22264ca61 100644 --- a/ios/MattermostShare/Views/ErrorViews/NoMembershipView.swift +++ b/ios/MattermostShare/Views/ErrorViews/NoMembershipView.swift @@ -11,12 +11,22 @@ import SwiftUI struct NoMembershipView: View { var body: some View { VStack (spacing: 8) { - Text("Not a member of any team yet") - .font(Font.custom("Metropolis-SemiBold", size: 20)) - .foregroundColor(Color.theme.centerChannelColor) - Text("To share content, you'll need to be a member of a team on a Mattermost server.") - .font(Font.custom("OpenSans", size: 16)) - .foregroundColor(Color.theme.centerChannelColor.opacity(0.72)) + Text( + NSLocalizedString("extension.no_memberships.title", + value: "Not a member of any team yet", + comment: "" + ) + ) + .font(Font.custom("Metropolis-SemiBold", size: 20)) + .foregroundColor(Color.theme.centerChannelColor) + Text( + NSLocalizedString("extension.no_memberships.description", + value: "To share content, you'll need to be a member of a team on a Mattermost server.", + comment: "" + ) + ) + .font(Font.custom("OpenSans", size: 16)) + .foregroundColor(Color.theme.centerChannelColor.opacity(0.72)) } .padding(.horizontal, 12) } diff --git a/ios/MattermostShare/Views/ErrorViews/NoServersView.swift b/ios/MattermostShare/Views/ErrorViews/NoServersView.swift index 4600644411c..554321541a1 100644 --- a/ios/MattermostShare/Views/ErrorViews/NoServersView.swift +++ b/ios/MattermostShare/Views/ErrorViews/NoServersView.swift @@ -11,12 +11,22 @@ import SwiftUI struct NoServersView: View { var body: some View { VStack (spacing: 8) { - Text("Not connected to any servers") - .font(Font.custom("Metropolis-SemiBold", size: 20)) - .foregroundColor(Color.theme.centerChannelColor) - Text("To share content, you'll need to be logged in to a Mattermost server.") - .font(Font.custom("OpenSans", size: 16)) - .foregroundColor(Color.theme.centerChannelColor.opacity(0.72)) + Text( + NSLocalizedString("extension.no_servers.title", + value: "Not connected to any servers", + comment: "" + ) + ) + .font(Font.custom("Metropolis-SemiBold", size: 20)) + .foregroundColor(Color.theme.centerChannelColor) + Text( + NSLocalizedString("extension.no_servers.description", + value: "To share content, you'll need to be logged in to a Mattermost server.", + comment: "" + ) + ) + .font(Font.custom("OpenSans", size: 16)) + .foregroundColor(Color.theme.centerChannelColor.opacity(0.72)) } .padding(.horizontal, 12) } diff --git a/ios/MattermostShare/Views/InitialView.swift b/ios/MattermostShare/Views/InitialView.swift index daee5723325..87c2896bf75 100644 --- a/ios/MattermostShare/Views/InitialView.swift +++ b/ios/MattermostShare/Views/InitialView.swift @@ -61,7 +61,17 @@ struct InitialView: View { } } .accentColor(.white) - .navigationBarTitle("Share to Mattermost", displayMode: .inline) + .navigationBarTitle( + NSLocalizedString("share_extension.share_screen.title", + value: "Share to {applicationName}", + comment: "" + ) + .replacingOccurrences( + of: "{applicationName}", + with: Bundle.main.infoDictionary?["CFBundleDisplayName"] as? String ?? "Mattermost Beta" + ), + displayMode: .inline + ) .navigationBarItems( leading: CancelButton(attachments: attachments), trailing: PostButton( diff --git a/share_extension/screens/channels.tsx b/share_extension/screens/channels.tsx index 7d6e27351ac..5d361d938b1 100644 --- a/share_extension/screens/channels.tsx +++ b/share_extension/screens/channels.tsx @@ -1,7 +1,9 @@ // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. // See LICENSE.txt for license information. -import React, {useMemo, useState} from 'react'; +import {useNavigation} from '@react-navigation/native'; +import React, {useEffect, useMemo, useState} from 'react'; +import {useIntl} from 'react-intl'; import {View} from 'react-native'; import SearchBar from '@components/search'; @@ -39,6 +41,14 @@ const Channels = ({theme}: Props) => { const styles = getStyles(theme); const [term, setTerm] = useState(''); const color = useMemo(() => changeOpacity(theme.centerChannelColor, 0.72), [theme]); + const navigator = useNavigation(); + const intl = useIntl(); + + useEffect(() => { + navigator.setOptions({ + title: intl.formatMessage({id: 'share_extension.channels_screen.title', defaultMessage: 'Select channel'}), + }); + }, [intl.locale]); const cancelButtonProps = useMemo(() => ({ color, diff --git a/share_extension/screens/share.tsx b/share_extension/screens/share.tsx index 4d4431a3d22..4a0e64fe748 100644 --- a/share_extension/screens/share.tsx +++ b/share_extension/screens/share.tsx @@ -4,8 +4,9 @@ import withObservables from '@nozbe/with-observables'; import {useNavigation} from '@react-navigation/native'; import React, {useEffect, useMemo} from 'react'; -import {useIntl} from 'react-intl'; +import {defineMessages, useIntl} from 'react-intl'; import {StyleSheet, View} from 'react-native'; +import DeviceInfo from 'react-native-device-info'; import {from as from$} from 'rxjs'; import DatabaseManager from '@database/manager'; @@ -18,6 +19,21 @@ import PostButton from '@share/components/header/post_button'; import {hasChannels} from '@share/queries'; import {setShareExtensionState, useShareExtensionServerUrl} from '@share/state'; +export const errorScreenMessages = defineMessages({ + label: { + id: 'share_extension.error_screen.label', + defaultMessage: 'An error ocurred', + }, + description: { + id: 'share_extension.error_screen.description', + defaultMessage: 'There was an error when attempting to share the content to {applicationName}.', + }, + reason: { + id: 'share_extension.error_screen.reason', + defaultMessage: 'Reason: {reason}', + }, +}); + type Props = { hasChannelMemberships: boolean; initialServerUrl: string; @@ -52,8 +68,14 @@ const ShareScreen = ({hasChannelMemberships, initialServerUrl, files, linkPrevie }, [serverUrl]); useEffect(() => { + const applicationName = DeviceInfo.getApplicationName(); navigator.setOptions({ - title: intl.formatMessage({id: 'share_extension.share_screen.title', defaultMessage: 'Share to Mattermost'}), + title: intl.formatMessage({ + id: 'share_extension.share_screen.title', + defaultMessage: 'Share to {applicationName}', + }, + {applicationName}, + ), }); }, [intl.locale]);