diff --git a/Podfile b/Podfile index b4839673dd8a..19e0f0f9d840 100644 --- a/Podfile +++ b/Podfile @@ -47,9 +47,9 @@ def wordpress_ui end def wordpress_kit - pod 'WordPressKit', '~> 4.50.0' + pod 'WordPressKit', '~> 4.51.0' # pod 'WordPressKit', :git => 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', :tag => '' - # pod 'WordPressKit', :git => 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', :branch => 'task/18324-site-creation-with-site-name' + # pod 'WordPressKit', :git => 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', :branch => '' # pod 'WordPressKit', :git => 'https://github.com/wordpress-mobile/WordPressKit-iOS.git', :commit => '' # pod 'WordPressKit', :path => '../WordPressKit-iOS' end @@ -169,7 +169,7 @@ abstract_target 'Apps' do ## Gutenberg (React Native) ## ===================== ## - gutenberg :tag => 'v1.74.0' + gutenberg :tag => 'v1.75.0' ## Third party libraries ## ===================== diff --git a/Podfile.lock b/Podfile.lock index d7f5861963a9..1cfc032c484b 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -61,7 +61,7 @@ PODS: - AppAuth/Core (~> 1.4) - GTMSessionFetcher/Core (~> 1.5) - GTMSessionFetcher/Core (1.7.0) - - Gutenberg (1.74.0): + - Gutenberg (1.75.0): - React (= 0.66.2) - React-CoreModules (= 0.66.2) - React-RCTImage (= 0.66.2) @@ -464,7 +464,7 @@ PODS: - React-Core - RNSVG (9.13.6): - React-Core - - RNTAztecView (1.74.0): + - RNTAztecView (1.75.0): - React-Core - WordPress-Aztec-iOS (~> 1.19.8) - Sentry (6.2.1): @@ -487,7 +487,7 @@ PODS: - WordPressKit (~> 4.18-beta) - WordPressShared (~> 1.12-beta) - WordPressUI (~> 1.7-beta) - - WordPressKit (4.50.0): + - WordPressKit (4.51.0): - Alamofire (~> 4.8.0) - CocoaLumberjack (~> 3.4) - NSObject-SafeExpectations (= 0.0.4) @@ -525,19 +525,19 @@ DEPENDENCIES: - AppCenter (~> 4.1) - AppCenter/Distribute (~> 4.1) - Automattic-Tracks-iOS (~> 0.11.1) - - boost (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/boost.podspec.json`) - - BVLinearGradient (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/BVLinearGradient.podspec.json`) + - boost (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/boost.podspec.json`) + - BVLinearGradient (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/BVLinearGradient.podspec.json`) - Charts (~> 3.2.2) - CocoaLumberjack (~> 3.0) - CropViewController (= 2.5.3) - Down (~> 0.6.6) - - FBLazyVector (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/FBLazyVector.podspec.json`) - - FBReactNativeSpec (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/FBReactNativeSpec/FBReactNativeSpec.podspec.json`) + - FBLazyVector (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/FBLazyVector.podspec.json`) + - FBReactNativeSpec (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/FBReactNativeSpec/FBReactNativeSpec.podspec.json`) - FSInteractiveMap (from `https://github.com/wordpress-mobile/FSInteractiveMap.git`, tag `0.2.0`) - Gifu (= 3.2.0) - - glog (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/glog.podspec.json`) + - glog (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/glog.podspec.json`) - Gridicons (~> 1.1.0) - - Gutenberg (from `https://github.com/wordpress-mobile/gutenberg-mobile.git`, tag `v1.74.0`) + - Gutenberg (from `https://github.com/wordpress-mobile/gutenberg-mobile.git`, tag `v1.75.0`) - JTAppleCalendar (~> 8.0.2) - Kanvas (~> 1.2.7) - MediaEditor (~> 1.2.1) @@ -547,56 +547,56 @@ DEPENDENCIES: - "NSURL+IDN (~> 0.4)" - OCMock (~> 3.4.3) - OHHTTPStubs/Swift (~> 9.1.0) - - RCT-Folly (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RCT-Folly.podspec.json`) - - RCTRequired (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RCTRequired.podspec.json`) - - RCTTypeSafety (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RCTTypeSafety.podspec.json`) + - RCT-Folly (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RCT-Folly.podspec.json`) + - RCTRequired (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RCTRequired.podspec.json`) + - RCTTypeSafety (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RCTTypeSafety.podspec.json`) - Reachability (= 3.2) - - React (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React.podspec.json`) - - React-callinvoker (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-callinvoker.podspec.json`) - - React-Core (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-Core.podspec.json`) - - React-CoreModules (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-CoreModules.podspec.json`) - - React-cxxreact (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-cxxreact.podspec.json`) - - React-jsi (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-jsi.podspec.json`) - - React-jsiexecutor (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-jsiexecutor.podspec.json`) - - React-jsinspector (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-jsinspector.podspec.json`) - - React-logger (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-logger.podspec.json`) - - react-native-blur (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-blur.podspec.json`) - - react-native-get-random-values (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-get-random-values.podspec.json`) - - react-native-keyboard-aware-scroll-view (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-keyboard-aware-scroll-view.podspec.json`) - - react-native-safe-area (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-safe-area.podspec.json`) - - react-native-safe-area-context (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-safe-area-context.podspec.json`) - - react-native-slider (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-slider.podspec.json`) - - react-native-video (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-video.podspec.json`) - - react-native-webview (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-webview.podspec.json`) - - React-perflogger (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-perflogger.podspec.json`) - - React-RCTActionSheet (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTActionSheet.podspec.json`) - - React-RCTAnimation (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTAnimation.podspec.json`) - - React-RCTBlob (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTBlob.podspec.json`) - - React-RCTImage (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTImage.podspec.json`) - - React-RCTLinking (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTLinking.podspec.json`) - - React-RCTNetwork (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTNetwork.podspec.json`) - - React-RCTSettings (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTSettings.podspec.json`) - - React-RCTText (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTText.podspec.json`) - - React-RCTVibration (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTVibration.podspec.json`) - - React-runtimeexecutor (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-runtimeexecutor.podspec.json`) - - ReactCommon (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/ReactCommon.podspec.json`) - - RNCClipboard (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNCClipboard.podspec.json`) - - RNCMaskedView (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNCMaskedView.podspec.json`) - - RNGestureHandler (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNGestureHandler.podspec.json`) - - RNReanimated (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNReanimated.podspec.json`) - - RNScreens (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNScreens.podspec.json`) - - RNSVG (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNSVG.podspec.json`) - - RNTAztecView (from `https://github.com/wordpress-mobile/gutenberg-mobile.git`, tag `v1.74.0`) + - React (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React.podspec.json`) + - React-callinvoker (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-callinvoker.podspec.json`) + - React-Core (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-Core.podspec.json`) + - React-CoreModules (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-CoreModules.podspec.json`) + - React-cxxreact (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-cxxreact.podspec.json`) + - React-jsi (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-jsi.podspec.json`) + - React-jsiexecutor (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-jsiexecutor.podspec.json`) + - React-jsinspector (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-jsinspector.podspec.json`) + - React-logger (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-logger.podspec.json`) + - react-native-blur (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-blur.podspec.json`) + - react-native-get-random-values (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-get-random-values.podspec.json`) + - react-native-keyboard-aware-scroll-view (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-keyboard-aware-scroll-view.podspec.json`) + - react-native-safe-area (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-safe-area.podspec.json`) + - react-native-safe-area-context (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-safe-area-context.podspec.json`) + - react-native-slider (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-slider.podspec.json`) + - react-native-video (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-video.podspec.json`) + - react-native-webview (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-webview.podspec.json`) + - React-perflogger (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-perflogger.podspec.json`) + - React-RCTActionSheet (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTActionSheet.podspec.json`) + - React-RCTAnimation (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTAnimation.podspec.json`) + - React-RCTBlob (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTBlob.podspec.json`) + - React-RCTImage (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTImage.podspec.json`) + - React-RCTLinking (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTLinking.podspec.json`) + - React-RCTNetwork (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTNetwork.podspec.json`) + - React-RCTSettings (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTSettings.podspec.json`) + - React-RCTText (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTText.podspec.json`) + - React-RCTVibration (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTVibration.podspec.json`) + - React-runtimeexecutor (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-runtimeexecutor.podspec.json`) + - ReactCommon (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/ReactCommon.podspec.json`) + - RNCClipboard (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNCClipboard.podspec.json`) + - RNCMaskedView (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNCMaskedView.podspec.json`) + - RNGestureHandler (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNGestureHandler.podspec.json`) + - RNReanimated (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNReanimated.podspec.json`) + - RNScreens (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNScreens.podspec.json`) + - RNSVG (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNSVG.podspec.json`) + - RNTAztecView (from `https://github.com/wordpress-mobile/gutenberg-mobile.git`, tag `v1.75.0`) - Starscream (= 3.0.6) - SVProgressHUD (= 2.2.5) - WordPress-Editor-iOS (~> 1.19.8) - WordPressAuthenticator (~> 2.0.0) - - WordPressKit (~> 4.50.0) + - WordPressKit (~> 4.51.0) - WordPressMocks (~> 0.0.15) - WordPressShared (from `https://github.com/wordpress-mobile/WordPress-iOS-Shared.git`, branch `feature/site-design-revamp`) - WordPressUI (~> 1.12.5) - WPMediaPicker (~> 1.8.3) - - Yoga (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/Yoga.podspec.json`) + - Yoga (from `https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/Yoga.podspec.json`) - ZendeskSupportSDK (= 5.3.0) - ZIPFoundation (~> 0.9.8) @@ -656,107 +656,107 @@ SPEC REPOS: EXTERNAL SOURCES: boost: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/boost.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/boost.podspec.json BVLinearGradient: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/BVLinearGradient.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/BVLinearGradient.podspec.json FBLazyVector: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/FBLazyVector.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/FBLazyVector.podspec.json FBReactNativeSpec: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/FBReactNativeSpec/FBReactNativeSpec.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/FBReactNativeSpec/FBReactNativeSpec.podspec.json FSInteractiveMap: :git: https://github.com/wordpress-mobile/FSInteractiveMap.git :tag: 0.2.0 glog: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/glog.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/glog.podspec.json Gutenberg: :git: https://github.com/wordpress-mobile/gutenberg-mobile.git :submodules: true - :tag: v1.74.0 + :tag: v1.75.0 RCT-Folly: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RCT-Folly.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RCT-Folly.podspec.json RCTRequired: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RCTRequired.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RCTRequired.podspec.json RCTTypeSafety: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RCTTypeSafety.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RCTTypeSafety.podspec.json React: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React.podspec.json React-callinvoker: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-callinvoker.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-callinvoker.podspec.json React-Core: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-Core.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-Core.podspec.json React-CoreModules: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-CoreModules.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-CoreModules.podspec.json React-cxxreact: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-cxxreact.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-cxxreact.podspec.json React-jsi: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-jsi.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-jsi.podspec.json React-jsiexecutor: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-jsiexecutor.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-jsiexecutor.podspec.json React-jsinspector: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-jsinspector.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-jsinspector.podspec.json React-logger: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-logger.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-logger.podspec.json react-native-blur: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-blur.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-blur.podspec.json react-native-get-random-values: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-get-random-values.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-get-random-values.podspec.json react-native-keyboard-aware-scroll-view: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-keyboard-aware-scroll-view.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-keyboard-aware-scroll-view.podspec.json react-native-safe-area: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-safe-area.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-safe-area.podspec.json react-native-safe-area-context: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-safe-area-context.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-safe-area-context.podspec.json react-native-slider: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-slider.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-slider.podspec.json react-native-video: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-video.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-video.podspec.json react-native-webview: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/react-native-webview.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/react-native-webview.podspec.json React-perflogger: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-perflogger.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-perflogger.podspec.json React-RCTActionSheet: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTActionSheet.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTActionSheet.podspec.json React-RCTAnimation: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTAnimation.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTAnimation.podspec.json React-RCTBlob: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTBlob.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTBlob.podspec.json React-RCTImage: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTImage.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTImage.podspec.json React-RCTLinking: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTLinking.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTLinking.podspec.json React-RCTNetwork: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTNetwork.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTNetwork.podspec.json React-RCTSettings: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTSettings.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTSettings.podspec.json React-RCTText: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTText.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTText.podspec.json React-RCTVibration: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-RCTVibration.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-RCTVibration.podspec.json React-runtimeexecutor: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/React-runtimeexecutor.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/React-runtimeexecutor.podspec.json ReactCommon: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/ReactCommon.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/ReactCommon.podspec.json RNCClipboard: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNCClipboard.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNCClipboard.podspec.json RNCMaskedView: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNCMaskedView.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNCMaskedView.podspec.json RNGestureHandler: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNGestureHandler.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNGestureHandler.podspec.json RNReanimated: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNReanimated.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNReanimated.podspec.json RNScreens: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNScreens.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNScreens.podspec.json RNSVG: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/RNSVG.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/RNSVG.podspec.json RNTAztecView: :git: https://github.com/wordpress-mobile/gutenberg-mobile.git :submodules: true - :tag: v1.74.0 + :tag: v1.75.0 WordPressShared: :branch: feature/site-design-revamp :git: https://github.com/wordpress-mobile/WordPress-iOS-Shared.git Yoga: - :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.74.0/third-party-podspecs/Yoga.podspec.json + :podspec: https://raw.githubusercontent.com/wordpress-mobile/gutenberg-mobile/v1.75.0/third-party-podspecs/Yoga.podspec.json CHECKOUT OPTIONS: FSInteractiveMap: @@ -765,11 +765,11 @@ CHECKOUT OPTIONS: Gutenberg: :git: https://github.com/wordpress-mobile/gutenberg-mobile.git :submodules: true - :tag: v1.74.0 + :tag: v1.75.0 RNTAztecView: :git: https://github.com/wordpress-mobile/gutenberg-mobile.git :submodules: true - :tag: v1.74.0 + :tag: v1.75.0 WordPressShared: :commit: cd17c7c81d2ad7005a724b580f99e42a50a06bdb :git: https://github.com/wordpress-mobile/WordPress-iOS-Shared.git @@ -800,7 +800,7 @@ SPEC CHECKSUMS: Gridicons: 17d660b97ce4231d582101b02f8280628b141c9a GTMAppAuth: ad5c2b70b9a8689e1a04033c9369c4915bfcbe89 GTMSessionFetcher: 43748f93435c2aa068b1cbe39655aaf600652e91 - Gutenberg: 65b33a7f5b7b69851dd96be57520f95c6e095e66 + Gutenberg: fad4baac1a8fb2474bab90c65b6069f5cf71162c JTAppleCalendar: 932cadea40b1051beab10f67843451d48ba16c99 Kanvas: 9eab00cc89669b38858d42d5f30c810876b31344 MediaEditor: 20cdeb46bdecd040b8bc94467ac85a52b53b193a @@ -849,7 +849,7 @@ SPEC CHECKSUMS: RNReanimated: ce406e6a3de52d00d2a1c3a0b2bb5e09227d8ba5 RNScreens: bd1f43d7dfcd435bc11d4ee5c60086717c45a113 RNSVG: 259ef12cbec2591a45fc7c5f09d7aa09e6692533 - RNTAztecView: d8919259a74bec7df9ba359913c04614b7e253a4 + RNTAztecView: 097a8d12a7cb1566ce3a384983906e5994086eed Sentry: 9b922b396b0e0bca8516a10e36b0ea3ebea5faf7 Sodium: 23d11554ecd556196d313cf6130d406dfe7ac6da Starscream: ef3ece99d765eeccb67de105bfa143f929026cf5 @@ -858,7 +858,7 @@ SPEC CHECKSUMS: WordPress-Aztec-iOS: 7d11d598f14c82c727c08b56bd35fbeb7dafb504 WordPress-Editor-iOS: 9eb9f12f21a5209cb837908d81ffe1e31cb27345 WordPressAuthenticator: 5163f732e4e529781f931f158f54b1a1545bc536 - WordPressKit: b5d9b13e7e627134c583d7c6736efa720b306615 + WordPressKit: 79d309801a09fabe9564ac9e1e06554274fc5022 WordPressMocks: 6b52b0764d9939408151367dd9c6e8a910877f4d WordPressShared: 0c4bc5e25765732fcf5d07f28c81970ab28493fb WordPressUI: c5be816f6c7b3392224ac21de9e521e89fa108ac @@ -874,6 +874,6 @@ SPEC CHECKSUMS: ZendeskSupportSDK: 3a8e508ab1d9dd22dc038df6c694466414e037ba ZIPFoundation: ae5b4b813d216d3bf0a148773267fff14bd51d37 -PODFILE CHECKSUM: b8a2c329dc0c5787b885a9311d168d112338a918 +PODFILE CHECKSUM: 382e5e1e2f3ce13dedadb5612e42251e7e1f3fe9 COCOAPODS: 1.11.2 diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 729357acc9a7..d80798ef0115 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -1,9 +1,21 @@ +19.9 +----- + + 19.8 ----- * [**] Self hosted sites are not restricted by video length during media uploads [https://github.com/wordpress-mobile/WordPress-iOS/pull/18414] * [*] [internal] My Site Dashboard: Made some changes to the code architecture of the dashboard. The majority of the changes are related to the posts cards. It should have no visible changes but could cause regressions. Please test it by creating/trashing drafts and scheduled posts and testing that they appear correctly on the dashboard. [#18405] * [*] Quick Start: Updated the Stats tour. The tour can now be accessed from either the dashboard or the menu tab. [#18413] +* [*] Quick Start: Updated the Reader tour. The tour now highlights the Discover tab and guides users to follow topics via the Settings screen. [#18450] +* [*] [internal] Quick Start: Deleted the Edit your homepage tour. [#18469] * [*] [internal] Quick Start: Refactored some code related to the tasks displayed in the Quick Start Card and the Quick Start modal. It should have no visible changes but could cause regressions. [#18395] +* [**] Follow Conversation flow now enables in-app notifications by default. They were updated to be opt-out rather than opt-in. [#18449] +* [*] Block Editor: Latest Posts block: Add featured image settings [https://github.com/WordPress/gutenberg/pull/39257] +* [*] Block Editor: Prevent incorrect notices displaying when switching between HTML-Visual mode quickly [https://github.com/WordPress/gutenberg/pull/40415] +* [*] Block Editor: Embed block: Fix inline preview cut-off when editing URL [https://github.com/WordPress/gutenberg/pull/35326] +* [*] Block Editor: Prevent gaps shown around floating toolbar when using external keyboard [https://github.com/WordPress/gutenberg/pull/40266] +* [**] We'll now ask users logging in which area of the app they'd like to focus on to build towards a more personalized experience. [#18385] 19.7 ----- diff --git a/Scripts/BuildPhases/LintAppLocalizedStringsUsage.rb b/Scripts/BuildPhases/LintAppLocalizedStringsUsage.rb new file mode 100755 index 000000000000..1775c4ef0212 --- /dev/null +++ b/Scripts/BuildPhases/LintAppLocalizedStringsUsage.rb @@ -0,0 +1,41 @@ +#!/usr/bin/env ruby + +require 'xcodeproj' + +REPO_ROOT = Pathname.new(__dir__) + '../..' + +def lint(file_path:, target_name:) + violations_count = 0 + File.foreach(file_path, mode: 'rb:BOM|UTF-8').with_index do |line, line_no| + next if line.match? %r(^\s*//) # Skip commented lines + + col_no = line.index('NSLocalizedString') + next if col_no.nil? + + puts "#{file_path}:#{line_no+1}:#{col_no+1}: error: Use `AppLocalizedString` instead of `NSLocalizedString` in source files that are used in the `#{target_name}` extension target. See paNNhX-nP-p2 for more info." + violations_count += 1 + end + violations_count +end + +## Main ## + +project = Xcodeproj::Project.open(REPO_ROOT + 'WordPress/WordPress.xcodeproj') +targets_to_analyze = if ARGV.count.positive? + project.targets.select { |t| t.name == ARGV.first } +else + project.targets.select { |t| t.is_a?(Xcodeproj::Project::Object::PBXNativeTarget) && t.extension_target_type? } +end + +violations_count = 0 +targets_to_analyze.each do |target| + build_phase = target.build_phases.find { |p| p.is_a?(Xcodeproj::Project::Object::PBXSourcesBuildPhase) } + next if build_phase.nil? + + puts "Linting extension target #{target.name} for improper NSLocalizedString usage..." + source_files = build_phase.files_references.map(&:real_path).select { |f| ['.m', '.swift'].any? { |ext| f.extname == ext } } + source_files.each { |f| violations_count += lint(file_path: f, target_name: target.name) } + puts "Done." +end + +exit 1 if violations_count > 0 diff --git a/Scripts/BuildPhases/runRubyScript b/Scripts/BuildPhases/runRubyScript new file mode 100755 index 000000000000..14a208a97e2c --- /dev/null +++ b/Scripts/BuildPhases/runRubyScript @@ -0,0 +1,27 @@ +#!/bin/bash -eu + +# Use this to run a Ruby script from a "Script Build Phase" from Xcode. +# +# Since shell scripts ran by Xcode do not source the user shell profile, typical user setups like the configurations of `rbenv` or `rvm` would not be set up properly. +# This script check if either `rbenv` or `rvm` is installed on the Mac and runs the setup steps as appropriate, before running the ruby script via `bundle exec` +# +# Usage: +# `runRubyScript ` +# +# Where Void, + failure: @escaping (Error?) -> Void) { + let fromDate = date ?? defaultDate + remote.fetchPrompts(for: siteID, number: number, fromDate: fromDate) { result in + switch result { + case .success(let remotePrompts): + // TODO: Upsert into CoreData once the CoreData model is available. + success(remotePrompts.map { BloggingPrompt(with: $0) }) + case .failure(let error): + failure(error) + } + } + } + + required init?(context: NSManagedObjectContext = ContextManager.shared.mainContext, + remote: BloggingPromptsServiceRemote? = nil, + blog: Blog? = nil) { + guard let account = AccountService(managedObjectContext: context).defaultWordPressComAccount(), + let siteID = blog?.dotComID ?? account.primaryBlogID else { + return nil + } + + self.context = context + self.siteID = siteID + self.remote = remote ?? .init(wordPressComRestApi: account.wordPressComRestV2Api) + } +} + +// MARK: - Temporary model object + +/// TODO: This is a temporary model to be replaced with Core Data model once the fields have all been finalized. +struct BloggingPrompt { + let promptID: Int + let text: String + let title: String // for post title + let content: String // for post content + let date: Date + let answered: Bool + let answerCount: Int + let displayAvatarURLs: [URL] + + init(with remotePrompt: RemoteBloggingPrompt) { + promptID = remotePrompt.promptID + text = remotePrompt.text + title = remotePrompt.title + content = remotePrompt.content + date = remotePrompt.date + answered = remotePrompt.answered + answerCount = remotePrompt.answeredUsersCount + displayAvatarURLs = remotePrompt.answeredUserAvatarURLs + } +} diff --git a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift index fe3403daef07..a74b93bfe55c 100644 --- a/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift +++ b/WordPress/Classes/Utility/Analytics/WPAnalyticsEvent.swift @@ -80,6 +80,7 @@ import Foundation case readerChipsMoreToggled case readerToggleFollowConversation case readerToggleCommentNotifications + case readerMoreToggleFollowConversation case readerPostReported case readerArticleDetailMoreTapped case readerSharedItem @@ -337,6 +338,17 @@ import Foundation // Quick Start case quickStartStarted + case quickStartTapped + + // Onboarding Question Prompt + case onboardingQuestionsDisplayed + case onboardingQuestionsItemSelected + case onboardingQuestionsSkipped + + // Onboarding Enable Notifications Prompt + case onboardingEnableNotificationsDisplayed + case onboardingEnableNotificationsSkipped + case onboardingEnableNotificationsEnableTapped /// A String that represents the event var value: String { @@ -472,6 +484,8 @@ import Foundation return "reader_toggle_follow_conversation" case .readerToggleCommentNotifications: return "reader_toggle_comment_notifications" + case .readerMoreToggleFollowConversation: + return "reader_more_toggle_follow_conversation" case .readerPostReported: return "reader_post_reported" case .readerArticleDetailMoreTapped: @@ -878,6 +892,8 @@ import Foundation // Quick Start case .quickStartStarted: return "quick_start_started" + case .quickStartTapped: + return "quick_start_tapped" // Site Intent Question case .enhancedSiteCreationIntentQuestionCanceled: @@ -895,6 +911,21 @@ import Foundation case .enhancedSiteCreationIntentQuestionExperiment: return "enhanced_site_creation_intent_question_experiment" + // Onboarding Question Prompt + case .onboardingQuestionsDisplayed: + return "onboarding_questions_displayed" + case .onboardingQuestionsItemSelected: + return "onboarding_questions_item_selected" + case .onboardingQuestionsSkipped: + return "onboarding_questions_skipped" + + // Onboarding Enable Notifications Prompt + case .onboardingEnableNotificationsDisplayed: + return "onboarding_enable_notifications_displayed" + case .onboardingEnableNotificationsSkipped: + return "onboarding_enable_notifications_skipped" + case .onboardingEnableNotificationsEnableTapped: + return "onboarding_enable_notifications_enable_tapped" // Site Name case .enhancedSiteCreationSiteNameCanceled: return "enhanced_site_creation_site_name_canceled" diff --git a/WordPress/Classes/Utility/FormattableContent/Actions/FormattableContentAction.swift b/WordPress/Classes/Utility/FormattableContent/Actions/FormattableContentAction.swift index 9ce13b279aa8..c7c946c4216d 100644 --- a/WordPress/Classes/Utility/FormattableContent/Actions/FormattableContentAction.swift +++ b/WordPress/Classes/Utility/FormattableContent/Actions/FormattableContentAction.swift @@ -12,9 +12,9 @@ public enum NotificationDeletionKind { public var legendText: String { switch self { case .deletion: - return NSLocalizedString("Comment has been deleted", comment: "Displayed when a Comment is deleted") + return AppLocalizedString("Comment has been deleted", comment: "Displayed when a Comment is deleted") case .spamming: - return NSLocalizedString("Comment has been marked as Spam", comment: "Displayed when a Comment is spammed") + return AppLocalizedString("Comment has been marked as Spam", comment: "Displayed when a Comment is spammed") } } } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/BlogDashboardViewController.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/BlogDashboardViewController.swift index a972e3ad951e..350b87beb1c7 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/BlogDashboardViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/BlogDashboardViewController.swift @@ -170,7 +170,6 @@ final class BlogDashboardViewController: UIViewController { } else { self.collectionView.scrollToTop(animated: true) } - self.mySiteViewController?.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: Constants.bottomPaddingForQuickStartNotices, right: 0) default: break } @@ -294,7 +293,6 @@ extension BlogDashboardViewController { static let horizontalSectionInset: CGFloat = 20 static let verticalSectionInset: CGFloat = 20 static let cellSpacing: CGFloat = 20 - static let bottomPaddingForQuickStartNotices: CGFloat = 80 } } diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/DashboardEmptyPostsCardCell.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/DashboardEmptyPostsCardCell.swift index c73128b713a6..468c69b68f5d 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/DashboardEmptyPostsCardCell.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Posts/DashboardEmptyPostsCardCell.swift @@ -1,4 +1,5 @@ import UIKit +import WordPressShared /// Card cell prompting the user to create their first post final class DashboardFirstPostCardCell: DashboardEmptyPostsCardCell, BlogDashboardCardConfigurable { @@ -48,7 +49,7 @@ class DashboardEmptyPostsCardCell: UICollectionViewCell, Reusable { private lazy var titleLabel: UILabel = { let titleLabel = UILabel() titleLabel.text = "Create your first post" - titleLabel.font = WPStyleGuide.notoBoldFontForTextStyle(.title3) + titleLabel.font = WPStyleGuide.serifFontForTextStyle(.title3, fontWeight: .semibold) titleLabel.adjustsFontForContentSizeCategory = true titleLabel.adjustsFontSizeToFitWidth = true titleLabel.minimumScaleFactor = 0.5 diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/AvatarTrainView.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/AvatarTrainView.swift index c336b8f75373..ac73162ffd1e 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/AvatarTrainView.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/AvatarTrainView.swift @@ -43,10 +43,14 @@ final class AvatarTrainView: UIView { // redraw border when user interface style changes. if let previousTraitCollection = previousTraitCollection, previousTraitCollection.userInterfaceStyle != traitCollection.userInterfaceStyle { - avatarStackView.subviews.forEach { configureBorder(for: $0) } + configureAvatarBorders() } } + override func layoutSubviews() { + configureAvatarBorders() + } + } // MARK: Private Helpers @@ -62,7 +66,6 @@ private extension AvatarTrainView { func makeAvatarImageView(with avatarURL: URL? = nil) -> UIImageView { let imageView = CircularImageView(image: placeholderImage) imageView.translatesAutoresizingMaskIntoConstraints = false - configureBorder(for: imageView) NSLayoutConstraint.activate([ imageView.heightAnchor.constraint(equalToConstant: imageHeight), @@ -76,9 +79,12 @@ private extension AvatarTrainView { return imageView } - func configureBorder(for view: UIView) { - view.layer.borderWidth = Constants.borderWidth - view.layer.borderColor = UIColor.listForeground.cgColor + func configureAvatarBorders() { + avatarStackView.arrangedSubviews.forEach { view in + view.layer.masksToBounds = true + view.layer.borderWidth = Constants.borderWidth + view.layer.borderColor = UIColor.listForeground.cgColor + } } // MARK: Constants diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/DashboardPromptsCardCell.swift b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/DashboardPromptsCardCell.swift index 8d1da82324e5..19ddb41f1a9a 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/DashboardPromptsCardCell.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Dashboard/Cards/Prompts/DashboardPromptsCardCell.swift @@ -13,6 +13,32 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { } } + // This is public so it can be accessed from the BloggingPromptsFeatureDescriptionView. + private(set) lazy var cardFrameView: BlogDashboardCardFrameView = { + let frameView = BlogDashboardCardFrameView() + frameView.translatesAutoresizingMaskIntoConstraints = false + frameView.title = Strings.cardFrameTitle + frameView.icon = Style.frameIconImage + + // NOTE: Remove the logic for iOS 13 once we drop that version. + if #available (iOS 14.0, *) { + // assign an empty closure so the button appears. + frameView.onEllipsisButtonTap = {} + frameView.ellipsisButton.showsMenuAsPrimaryAction = true + frameView.ellipsisButton.menu = contextMenu + } else { + // Show a fallback implementation using `MenuSheetViewController`. + // iOS 13 doesn't support showing UIMenu programmatically. + frameView.onEllipsisButtonTap = { [weak self] in + self?.showMenuSheet() + } + } + + return frameView + }() + + // MARK: - Private Properties + /// When set to true, a "default" version of the card is displayed. That is: /// - `maxAvatarCount` number of avatars. /// - `maxAvatarCount` answer count. @@ -25,8 +51,6 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { } } - // MARK: - Private Properties - // Used to present the menu sheet for contextual menu. // NOTE: Remove this once we drop support for iOS 13. private weak var presenterViewController: BlogDashboardViewController? = nil @@ -39,35 +63,12 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { return stackView }() - private lazy var cardFrameView: BlogDashboardCardFrameView = { - let frameView = BlogDashboardCardFrameView() - frameView.translatesAutoresizingMaskIntoConstraints = false - frameView.title = Strings.cardFrameTitle - frameView.icon = Style.frameIconImage - - // NOTE: Remove the logic for iOS 13 once we drop that version. - if #available (iOS 14.0, *) { - // assign an empty closure so the button appears. - frameView.onEllipsisButtonTap = {} - frameView.ellipsisButton.showsMenuAsPrimaryAction = true - frameView.ellipsisButton.menu = contextMenu - } else { - // Show a fallback implementation using `MenuSheetViewController`. - // iOS 13 doesn't support showing UIMenu programmatically. - frameView.onEllipsisButtonTap = { [weak self] in - self?.showMenuSheet() - } - } - - return frameView - }() - // MARK: Top row views private lazy var promptLabel: UILabel = { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false - label.font = Style.promptContentFont + label.font = WPStyleGuide.BloggingPrompts.promptContentFont label.textAlignment = .center label.numberOfLines = 0 label.adjustsFontForContentSizeCategory = true @@ -129,8 +130,8 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { let label = UILabel() label.translatesAutoresizingMaskIntoConstraints = false label.text = answerInfoText - label.font = Style.answerInfoLabelFont - label.textColor = Style.answerInfoLabelColor + label.font = WPStyleGuide.BloggingPrompts.answerInfoLabelFont + label.textColor = WPStyleGuide.BloggingPrompts.answerInfoLabelColor label.textAlignment = (effectiveUserInterfaceLayoutDirection == .leftToRight ? .left : .right) label.numberOfLines = 0 label.adjustsFontForContentSizeCategory = true @@ -166,8 +167,8 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { let button = UIButton() button.translatesAutoresizingMaskIntoConstraints = false button.setTitle(Strings.answerButtonTitle, for: .normal) - button.setTitleColor(Style.buttonTitleColor, for: .normal) - button.titleLabel?.font = Style.buttonTitleFont + button.setTitleColor(WPStyleGuide.BloggingPrompts.buttonTitleColor, for: .normal) + button.titleLabel?.font = WPStyleGuide.BloggingPrompts.buttonTitleFont button.titleLabel?.adjustsFontForContentSizeCategory = true button.titleLabel?.adjustsFontSizeToFitWidth = true @@ -178,8 +179,8 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { private lazy var answeredLabel: UILabel = { let label = UILabel() - label.font = Style.buttonTitleFont - label.textColor = Style.answeredLabelColor + label.font = WPStyleGuide.BloggingPrompts.buttonTitleFont + label.textColor = WPStyleGuide.BloggingPrompts.answeredLabelColor label.text = Strings.answeredLabelTitle // The 'answered' label needs to be close to the Share button. @@ -195,8 +196,8 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { let button = UIButton() button.translatesAutoresizingMaskIntoConstraints = false button.setTitle(Strings.shareButtonTitle, for: .normal) - button.setTitleColor(Style.buttonTitleColor, for: .normal) - button.titleLabel?.font = Style.buttonTitleFont + button.setTitleColor(WPStyleGuide.BloggingPrompts.buttonTitleColor, for: .normal) + button.titleLabel?.font = WPStyleGuide.BloggingPrompts.buttonTitleFont button.titleLabel?.adjustsFontForContentSizeCategory = true button.titleLabel?.adjustsFontSizeToFitWidth = true button.contentHorizontalAlignment = .leading @@ -259,6 +260,14 @@ class DashboardPromptsCardCell: UICollectionViewCell, Reusable { super.init(coder: coder) } + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + // refresh when the appearance style changed so the placeholder images are correctly recolored. + if let previousTraitCollection = previousTraitCollection, + previousTraitCollection.userInterfaceStyle != traitCollection.userInterfaceStyle { + refreshStackView() + } + } + // MARK: - Public Methods func configureForExampleDisplay() { @@ -352,13 +361,10 @@ private extension DashboardPromptsCardCell { struct Style { static let frameIconImage = UIImage(named: "icon-lightbulb-outline")?.resizedImage(Constants.cardIconSize, interpolationQuality: .default) - static let avatarPlaceholderImage = UIImage(color: .quaternarySystemFill) - static let promptContentFont = WPStyleGuide.serifFontForTextStyle(.headline, fontWeight: .semibold) - static let answerInfoLabelFont = WPStyleGuide.fontForTextStyle(.caption1) - static let answerInfoLabelColor = UIColor.primary - static let buttonTitleFont = WPStyleGuide.fontForTextStyle(.subheadline) - static let buttonTitleColor = UIColor.primary - static let answeredLabelColor = UIColor.muriel(name: .green, .shade50) + static var avatarPlaceholderImage: UIImage { + // this needs to be computed so the color is correct depending on the user interface style. + return UIImage(color: .init(light: .quaternarySystemFill, dark: .systemGray4)) + } } struct Constants { diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+FancyAlerts.swift b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+FancyAlerts.swift index 1da890ea213b..a99afa346ec0 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+FancyAlerts.swift +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController+FancyAlerts.swift @@ -5,8 +5,6 @@ private var observer: NSObjectProtocol? extension BlogDetailsViewController { - @objc static let bottomPaddingForQuickStartNotices: CGFloat = 80.0 - @objc func startObservingQuickStart() { observer = NotificationCenter.default.addObserver(forName: .QuickStartTourElementChangedNotification, object: nil, queue: nil) { [weak self] (notification) in guard self?.blog.managedObjectContext != nil else { @@ -22,7 +20,7 @@ extension BlogDetailsViewController { return } fallthrough - case .pages, .editHomepage, .sharing: + case .pages, .sharing: self?.scroll(to: info) default: break @@ -118,13 +116,6 @@ extension BlogDetailsViewController { createButtonCoordinator?.hideCreateButtonTooltip() } - @objc func cancelCompletedToursIfNeeded() { - if shouldShowQuickStartChecklist() && blog.homepagePageID == nil { - // Ends the tour Edit Homepage if the site doesn't have a homepage set or uses the blog. - QuickStartTourGuide.shared.complete(tour: QuickStartEditHomepageTour(), for: blog, postNotification: false) - } - } - @objc func quickStartSectionViewModel() -> BlogDetailsSection { let row = BlogDetailsRow() row.callback = {} diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.h b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.h index 5b9839ed2aee..f3a9cc3ee927 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.h +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.h @@ -60,7 +60,7 @@ typedef NS_ENUM(NSInteger, QuickStartTourElement) { QuickStartTourElementSharing = 8, QuickStartTourElementConnections = 9, QuickStartTourElementReaderTab = 10, - QuickStartTourElementReaderSearch = 12, + QuickStartTourElementReaderDiscoverSettings = 12, QuickStartTourElementTourCompleted = 13, QuickStartTourElementCongratulations = 14, QuickStartTourElementSiteIcon = 15, @@ -69,8 +69,8 @@ typedef NS_ENUM(NSInteger, QuickStartTourElement) { QuickStartTourElementStats = 18, QuickStartTourElementPlans = 19, QuickStartTourElementSiteTitle = 20, - QuickStartTourElementEditHomepage = 21, - QuickStartTourElementSiteMenu = 22, + QuickStartTourElementSiteMenu = 21, + QuickStartTourElementNotifications = 22, QuickStartTourElementSetupQuickStart = 23, QuickStartTourElementRemoveQuickStart = 24, }; @@ -160,5 +160,5 @@ typedef NS_ENUM(NSUInteger, BlogDetailsNavigationSource) { - (void)showStatsFromSource:(BlogDetailsNavigationSource)source; - (void)updateTableView:(nullable void(^)(void))completion; - (void)preloadMetadata; -- (void)pulledToRefreshWith:(nonnull UIRefreshControl *)refreshControl onCompletion:(nullable void(^)(void))completion; +- (void)pulledToRefreshWith:(nonnull UIRefreshControl *)refreshControl onCompletion:(nullable void(^)(void))completion; @end diff --git a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m index d620a2007288..85daf2e9cb39 100644 --- a/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m +++ b/WordPress/Classes/ViewRelated/Blog/Blog Details/BlogDetailsViewController.m @@ -379,14 +379,6 @@ - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; - MySiteViewController *parentVC = (MySiteViewController *)self.parentViewController; - - if ([[QuickStartTourGuide shared] currentElementInt] != NSNotFound) { - parentVC.additionalSafeAreaInsets = UIEdgeInsetsMake(0, 0, [BlogDetailsViewController bottomPaddingForQuickStartNotices], 0); - } else { - parentVC.additionalSafeAreaInsets = UIEdgeInsetsZero; - } - if (self.splitViewControllerIsHorizontallyCompact) { self.restorableSelectedIndexPath = nil; } @@ -403,7 +395,6 @@ - (void)viewWillAppear:(BOOL)animated - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; - [self cancelCompletedToursIfNeeded]; [self createUserActivity]; [self startAlertTimer]; @@ -1400,7 +1391,6 @@ - (void)scrollToElement:(QuickStartTourElement) element for (BlogDetailsRow *row in section.rows) { if (row.quickStartIdentifier == element) { NSIndexPath *path = [NSIndexPath indexPathForRow:rowCount inSection:sectionCount]; - parentVC.additionalSafeAreaInsets = UIEdgeInsetsMake(0, 0, [BlogDetailsViewController bottomPaddingForQuickStartNotices], 0); UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:path]; [parentVC.scrollView scrollVerticallyToView:cell animated:true]; } @@ -1638,7 +1628,6 @@ - (void)showViewSiteFromSource:(BlogDetailsNavigationSource)source [[QuickStartTourGuide shared] completeViewSiteTourForBlog:self.blog]; } - parentVC.additionalSafeAreaInsets = UIEdgeInsetsZero; } - (void)showViewAdmin @@ -1760,9 +1749,6 @@ - (void)updateTableView:(void(^)(void))completion } #pragma mark - Pull To Refresh -- (void)pulledToRefresh { - [self pulledToRefreshWith:self.tableView.refreshControl onCompletion:^{}]; -} - (void)pulledToRefreshWith:(UIRefreshControl *)refreshControl onCompletion:( void(^)(void))completion { @@ -1772,7 +1758,7 @@ - (void)pulledToRefreshWith:(UIRefreshControl *)refreshControl onCompletion:( vo // down to refresh the site. dispatch_async(dispatch_get_main_queue(), ^(void){ [refreshControl endRefreshing]; - + completion(); }); }]; diff --git a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController+OnboardingPrompt.swift b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController+OnboardingPrompt.swift new file mode 100644 index 000000000000..56141bcb0526 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController+OnboardingPrompt.swift @@ -0,0 +1,43 @@ +import Foundation + +extension MySiteViewController { + func startObservingOnboardingPrompt() { + NotificationCenter.default.addObserver(self, selector: #selector(onboardingPromptWasDismissed(_:)), name: .onboardingPromptWasDismissed, object: nil) + } + + @objc func onboardingPromptWasDismissed(_ notification: NSNotification) { + guard + let userInfo = notification.userInfo, + let option = userInfo["option"] as? OnboardingOption + else { + return + } + + switch option { + case .stats: + // Show the stats view for the current blog + if let blog = blog { + StatsViewController.show(for: blog, from: self) + } + case .writing: + // Open the editor + let controller = tabBarController as? WPTabBarController + controller?.showPostTab(completion: { + self.startAlertTimer() + }) + + case .showMeAround: + // Start the quick start + if let blog = blog { + let type: QuickStartType = FeatureFlag.quickStartForExistingUsers.enabled ? .existingSite : .newSite + QuickStartTourGuide.shared.setup(for: blog, type: type) + } + + case .skip, .reader, .notifications: + // Skip: Do nothing + // Reader and notifications will be handled by: + // WPAuthenticationManager.handleOnboardingQuestionsWillDismiss + break + } + } +} diff --git a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController+QuickStart.swift b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController+QuickStart.swift index debd54e588b7..eb28ffae3eb2 100644 --- a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController+QuickStart.swift +++ b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController+QuickStart.swift @@ -9,16 +9,20 @@ extension MySiteViewController { let element = info[QuickStartTourGuide.notificationElementKey] as? QuickStartTourElement { switch element { - case .noSuchElement: + case .noSuchElement, .newpost: self?.additionalSafeAreaInsets = .zero + case .siteIcon, .siteTitle, .viewSite: self?.scrollView.scrollToTop(animated: true) + self?.additionalSafeAreaInsets = Constants.quickStartNoticeInsets - self?.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: Constants.bottomPaddingForQuickStartNotices, right: 0) case .siteMenu: self?.siteMenuSpotlightIsShown = true + fallthrough + + case .pages, .sharing, .stats, .readerTab, .notifications: + self?.additionalSafeAreaInsets = Constants.quickStartNoticeInsets - self?.additionalSafeAreaInsets = UIEdgeInsets(top: 0, left: 0, bottom: Constants.bottomPaddingForQuickStartNotices, right: 0) default: break } @@ -27,6 +31,6 @@ extension MySiteViewController { } private enum Constants { - static let bottomPaddingForQuickStartNotices: CGFloat = 80.0 + static let quickStartNoticeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 80, right: 0) } } diff --git a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift index 43d25a77d20c..95029b51cfb0 100644 --- a/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/My Site/MySiteViewController.swift @@ -155,6 +155,7 @@ class MySiteViewController: UIViewController, NoResultsViewHost { subscribeToModelChanges() subscribeToContentSizeCategory() startObservingQuickStart() + startObservingOnboardingPrompt() } override func viewWillAppear(_ animated: Bool) { @@ -268,8 +269,7 @@ class MySiteViewController: UIViewController, NoResultsViewHost { segmentedControlContainerView.isHidden = hideSegmentedControl if !hideSegmentedControl && switchTabsIfNeeded { - segmentedControl.selectedSegmentIndex = mySiteSettings.defaultSection.rawValue - segmentedControlValueChanged() + switchTab(to: mySiteSettings.defaultSection) } } @@ -427,8 +427,10 @@ class MySiteViewController: UIViewController, NoResultsViewHost { @objc private func pulledToRefresh() { - guard let section = currentSection else { - return + + guard let blog = blog, + let section = currentSection else { + return } switch section { @@ -438,13 +440,25 @@ class MySiteViewController: UIViewController, NoResultsViewHost { return } - self.sitePickerViewController?.blogDetailHeaderView.blog = self.blog + self.updateNavigationTitle(for: blog) + self.sitePickerViewController?.blogDetailHeaderView.blog = blog } - case .dashboard: + + /// The dashboard’s refresh control is intentionally not tied to blog syncing in order to keep + /// the dashboard updating fast. blogDashboardViewController?.pulledToRefresh { [weak self] in self?.refreshControl.endRefreshing() } + + blogService.syncBlogAndAllMetadata(blog) { [weak self] in + guard let self = self else { + return + } + + self.updateNavigationTitle(for: blog) + self.sitePickerViewController?.blogDetailHeaderView.blog = blog + } } WPAnalytics.track(.mySitePullToRefresh, properties: [WPAppAnalyticsKeyTabSource: section.analyticsDescription]) @@ -478,6 +492,13 @@ class MySiteViewController: UIViewController, NoResultsViewHost { } } + /// Changes between the site menu and dashboard + /// - Parameter section: The section to switch to + func switchTab(to section: Section) { + segmentedControl.selectedSegmentIndex = section.rawValue + segmentedControlValueChanged() + } + // MARK: - Child VC logic private func embedChildInStackView(_ child: UIViewController) { @@ -765,8 +786,7 @@ class MySiteViewController: UIViewController, NoResultsViewHost { } if !blog.isAccessibleThroughWPCom() && self.isShowingDashboard { - self.segmentedControl.selectedSegmentIndex = Section.siteMenu.rawValue - self.segmentedControlValueChanged() + self.switchTab(to: .siteMenu) } self.updateNavigationTitle(for: blog) diff --git a/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingEnableNotificationsViewController.swift b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingEnableNotificationsViewController.swift new file mode 100644 index 000000000000..b8f74f05fe88 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingEnableNotificationsViewController.swift @@ -0,0 +1,149 @@ +import UIKit + +class OnboardingEnableNotificationsViewController: UIViewController { + @IBOutlet weak var titleLabel: UILabel! + @IBOutlet weak var subTitleLabel: UILabel! + @IBOutlet weak var detailView: UIView! + + let option: OnboardingOption + let coordinator: OnboardingQuestionsCoordinator + + init(with coordinator: OnboardingQuestionsCoordinator, option: OnboardingOption) { + self.coordinator = coordinator + self.option = option + + super.init(nibName: nil, bundle: nil) + } + + required convenience init?(coder: NSCoder) { + self.init(with: OnboardingQuestionsCoordinator(), option: .notifications) + } + + override func viewDidLoad() { + super.viewDidLoad() + + navigationController?.navigationBar.isHidden = true + navigationController?.delegate = self + + applyStyles() + updateContent() + + coordinator.notificationsDisplayed(option: option) + } + + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + return [.portrait, .portraitUpsideDown] + } +} + +// MARK: - IBAction's +extension OnboardingEnableNotificationsViewController { + @IBAction func enableButtonTapped(_ sender: Any) { + coordinator.notificationsEnabledTapped(selection: option) + } + + @IBAction func skipButtonTapped(_ sender: Any) { + coordinator.notificationsSkipped(selection: option) + } +} + +// MARK: - Trait Collection Handling +extension OnboardingEnableNotificationsViewController { + func updateContent(for traitCollection: UITraitCollection) { + let contentSize = traitCollection.preferredContentSizeCategory + + // Hide the detail image if the text is too large + detailView.isHidden = contentSize.isAccessibilityCategory + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + updateContent(for: traitCollection) + } +} + +// MARK: - UINavigation Controller Delegate +extension OnboardingEnableNotificationsViewController: UINavigationControllerDelegate { + func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask { + return supportedInterfaceOrientations + } + + func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation { + return .portrait + } +} + +// MARK: - Private Helpers +private extension OnboardingEnableNotificationsViewController { + func applyStyles() { + navigationController?.navigationBar.isHidden = true + + titleLabel.font = WPStyleGuide.serifFontForTextStyle(.title1, fontWeight: .semibold) + titleLabel.textColor = .text + + subTitleLabel.font = .preferredFont(forTextStyle: .title3) + subTitleLabel.textColor = .secondaryLabel + } + + func updateContent() { + let text: String + let notificationContent: UnifiedPrologueNotificationsContent? + + switch option { + case .stats: + text = StatsStrings.subTitle + notificationContent = .init(topElementTitle: StatsStrings.notificationTopTitle, + middleElementTitle: StatsStrings.notificationMiddleTitle, + bottomElementTitle: StatsStrings.notificationBottomTitle, + topImage: "view-milestone-1k", + middleImage: "traffic-surge-icon") + case .writing: + text = WritingStrings.subTitle + notificationContent = nil + + case .notifications, .showMeAround, .skip: + text = DefaultStrings.subTitle + notificationContent = nil + + case .reader: + text = ReaderStrings.subTitle + notificationContent = .init(topElementTitle: ReaderStrings.notificationTopTitle, + middleElementTitle: ReaderStrings.notificationMiddleTitle, + bottomElementTitle: ReaderStrings.notificationBottomTitle) + } + + + subTitleLabel.text = text + + // Convert the image view to a UIView and embed it + let imageView = UIView.embedSwiftUIView(UnifiedPrologueNotificationsContentView(notificationContent)) + imageView.frame.size.width = detailView.frame.width + detailView.addSubview(imageView) + imageView.pinSubviewToAllEdges(detailView) + } +} + +// MARK: - Constants / Strings +private struct StatsStrings { + static let subTitle = NSLocalizedString("Know when your site is getting more traffic, new followers, or when it passes a new milestone!", comment: "Subtitle giving the user more context about why to enable notifications.") + + static let notificationTopTitle = NSLocalizedString("Congratulations! Your site passed *1000 all-time* views!", comment: "Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text.") + static let notificationMiddleTitle = NSLocalizedString("Your site appears to be getting *more traffic* than usual!", comment: "Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text.") + static let notificationBottomTitle = NSLocalizedString("*Johann Brandt* is now following your site!", comment: "Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text.") +} + +private struct WritingStrings { + static let subTitle = NSLocalizedString("Stay in touch with your audience with like and comment notifications.", comment: "Subtitle giving the user more context about why to enable notifications.") +} + +private struct DefaultStrings { + static let subTitle = NSLocalizedString("Stay in touch with like and comment notifications.", comment: "Subtitle giving the user more context about why to enable notifications.") +} + +private struct ReaderStrings { + static let subTitle = NSLocalizedString("Know when your favorite authors post new content.", comment: "Subtitle giving the user more context about why to enable notifications.") + static let notificationTopTitle = NSLocalizedString("*Madison Ruiz* added a new post to their site", comment: "Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text.") + static let notificationMiddleTitle = NSLocalizedString("You received *50 likes* on your comment", comment: "Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text.") + static let notificationBottomTitle = NSLocalizedString("*Johann Brandt* responded to your comment", comment: "Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text.") +} diff --git a/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingEnableNotificationsViewController.xib b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingEnableNotificationsViewController.xib new file mode 100644 index 000000000000..a70f0f0fdd6a --- /dev/null +++ b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingEnableNotificationsViewController.xib @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsCoordinator.swift b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsCoordinator.swift new file mode 100644 index 000000000000..14bb8bfb95f7 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsCoordinator.swift @@ -0,0 +1,121 @@ +import Foundation +import UIKit + +enum OnboardingOption: String { + case stats + case writing + case notifications + case reader + case showMeAround = "show_me_around" + case skip +} + +extension NSNotification.Name { + static let onboardingPromptWasDismissed = NSNotification.Name(rawValue: "OnboardingPromptWasDismissed") +} + +class OnboardingQuestionsCoordinator { + var navigationController: UINavigationController? + var onDismiss: ((_ selection: OnboardingOption) -> Void)? + + func dismiss(selection: OnboardingOption) { + onDismiss?(selection) + } + + func track(_ event: WPAnalyticsEvent, option: OnboardingOption? = nil) { + guard let option = option else { + WPAnalytics.track(event) + return + } + + let properties = ["item": option.rawValue] + WPAnalytics.track(event, properties: properties) + } +} + +// MARK: - Questions View Handling +extension OnboardingQuestionsCoordinator { + func questionsDisplayed() { + track(.onboardingQuestionsDisplayed) + } + + func questionsSkipped(option: OnboardingOption) { + dismiss(selection: option) + track(.onboardingQuestionsSkipped) + } + + func didSelect(option: OnboardingOption) { + guard option != .skip else { + questionsSkipped(option: option) + return + } + + track(.onboardingQuestionsItemSelected, option: option) + UserDefaults.standard.onboardingQuestionSelected = option + + // Check if notification's are already enabled + // If they are just dismiss, if not then prompt + UNUserNotificationCenter.current().getNotificationSettings(completionHandler: { [weak self] settings in + DispatchQueue.main.async { + guard settings.authorizationStatus == .notDetermined, let self = self else { + self?.dismiss(selection: option) + return + } + + let controller = OnboardingEnableNotificationsViewController(with: self, option: option) + self.navigationController?.pushViewController(controller, animated: true) + } + }) + } +} + +// MARK: - Notifications Handling +extension OnboardingQuestionsCoordinator { + func notificationsDisplayed(option: OnboardingOption) { + track(.onboardingEnableNotificationsDisplayed, option: option) + UserDefaults.standard.onboardingNotificationsPromptDisplayed = true + } + + func notificationsEnabledTapped(selection: OnboardingOption) { + track(.onboardingEnableNotificationsEnableTapped, option: selection) + + InteractiveNotificationsManager.shared.requestAuthorization { authorized in + DispatchQueue.main.async { + self.dismiss(selection: selection) + } + } + } + + func notificationsSkipped(selection: OnboardingOption) { + track(.onboardingEnableNotificationsSkipped, option: selection) + dismiss(selection: selection) + } +} + + +extension UserDefaults { + private static let promptKey = "onboarding_notifications_prompt_displayed" + private static let questionKey = "onboarding_question_selection" + + var onboardingNotificationsPromptDisplayed: Bool { + get { + bool(forKey: Self.promptKey) + } + set { + set(newValue, forKey: Self.promptKey) + } + } + + var onboardingQuestionSelected: OnboardingOption? { + get { + if let str = string(forKey: Self.questionKey) { + return OnboardingOption(rawValue: str) + } + + return nil + } + set { + set(newValue?.rawValue, forKey: Self.questionKey) + } + } +} diff --git a/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsPromptViewController.swift b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsPromptViewController.swift new file mode 100644 index 000000000000..50437be734cc --- /dev/null +++ b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsPromptViewController.swift @@ -0,0 +1,185 @@ +import UIKit +import WordPressUI +import WordPressShared + +class OnboardingQuestionsPromptViewController: UIViewController { + @IBOutlet weak var stackView: UIStackView! + @IBOutlet weak var titleLabel: UILabel! + + @IBOutlet weak var statsButton: UIButton! + @IBOutlet weak var postsButton: UIButton! + @IBOutlet weak var notificationsButton: UIButton! + @IBOutlet weak var readButton: UIButton! + @IBOutlet weak var notSureButton: UIButton! + @IBOutlet weak var skipButton: UIButton! + + let coordinator: OnboardingQuestionsCoordinator + + init(with coordinator: OnboardingQuestionsCoordinator) { + self.coordinator = coordinator + super.init(nibName: nil, bundle: nil) + } + + required convenience init?(coder: NSCoder) { + self.init(with: OnboardingQuestionsCoordinator()) + } + + override func viewDidLoad() { + super.viewDidLoad() + + navigationController?.navigationBar.isHidden = true + navigationController?.delegate = self + + applyStyles() + updateButtonTitles() + + coordinator.questionsDisplayed() + } + + // MARK: - View Methods + override func viewDidLayoutSubviews() { + super.viewDidLayoutSubviews() + + configureButtons() + } + + override var supportedInterfaceOrientations: UIInterfaceOrientationMask { + return [.portrait, .portraitUpsideDown] + } +} + +// MARK: - IBAction's +extension OnboardingQuestionsPromptViewController { + @IBAction func didTapStats(_ sender: Any) { + coordinator.didSelect(option: .stats) + } + + @IBAction func didTapWriting(_ sender: Any) { + coordinator.didSelect(option: .writing) + } + + @IBAction func didTapNotifications(_ sender: Any) { + coordinator.didSelect(option: .notifications) + } + + @IBAction func didTapReader(_ sender: Any) { + coordinator.didSelect(option: .reader) + } + + @IBAction func didTapNotSure(_ sender: Any) { + coordinator.didSelect(option: .showMeAround) + } + + @IBAction func skip(_ sender: Any) { + coordinator.didSelect(option: .skip) + } +} + +// MARK: - Private Helpers +private extension OnboardingQuestionsPromptViewController { + private func applyStyles() { + titleLabel.font = WPStyleGuide.serifFontForTextStyle(.title1, fontWeight: .semibold) + titleLabel.textColor = .text + + stackView.setCustomSpacing(32, after: titleLabel) + } + + private func updateButtonTitles() { + statsButton.setTitle(Strings.stats, for: .normal) + statsButton.setImage("📊".image(), for: .normal) + + postsButton.setTitle(Strings.writing, for: .normal) + postsButton.setImage("✍️".image(), for: .normal) + + notificationsButton.setTitle(Strings.notifications, for: .normal) + notificationsButton.setImage("🔔".image(), for: .normal) + + readButton.setTitle(Strings.reader, for: .normal) + readButton.setImage("📚".image(), for: .normal) + + notSureButton.setTitle(Strings.notSure, for: .normal) + notSureButton.setImage("🤔".image(), for: .normal) + + skipButton.setTitle(Strings.skip, for: .normal) + } + + private func configureButtons() { + [statsButton, postsButton, notificationsButton, readButton, notSureButton].forEach { + style(button: $0) + } + } + + private func style(button: UIButton) { + button.titleLabel?.font = WPStyleGuide.fontForTextStyle(.headline) + button.setTitleColor(.text, for: .normal) + button.titleLabel?.textAlignment = .natural + button.titleEdgeInsets.left = 10 + button.imageView?.contentMode = .scaleAspectFit + button.flipInsetsForRightToLeftLayoutDirection() + } +} + +// MARK: - UINavigation Controller Delegate +extension OnboardingQuestionsPromptViewController: UINavigationControllerDelegate { + func navigationControllerSupportedInterfaceOrientations(_ navigationController: UINavigationController) -> UIInterfaceOrientationMask { + return supportedInterfaceOrientations + } + + func navigationControllerPreferredInterfaceOrientationForPresentation(_ navigationController: UINavigationController) -> UIInterfaceOrientation { + return .portrait + } +} + + +// MARK: - CGSize Helper Extension +private extension CGSize { + + /// Get the center point of the size in the given rect + /// - Parameter rect: The rect to center the size in + /// - Returns: The center point + func centered(in rect: CGRect) -> CGPoint { + let x = rect.midX - (self.width * 0.5) + let y = rect.midY - (self.height * 0.5) + + return CGPoint(x: x, y: y) + } +} + +// MARK: - Emoji Drawing Helper Extension +private extension String { + func image() -> UIImage { + let size = Constants.iconSize + let imageSize = CGSize(width: size, height: size) + let rect = CGRect(origin: .zero, size: imageSize) + + UIGraphicsBeginImageContextWithOptions(imageSize, false, 0) + + UIColor.clear.set() + UIRectFill(rect) + + let attributes: [NSAttributedString.Key: Any] = [.font: UIFont.systemFont(ofSize: size)] + + let string = self as NSString + let drawingSize = string.size(withAttributes: attributes) + string.draw(at: drawingSize.centered(in: rect), withAttributes: attributes) + + let image = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return image?.withRenderingMode(.alwaysOriginal) ?? UIImage() + } +} + +// MARK: - Helper Structs +private struct Strings { + static let stats = NSLocalizedString("Checking stats", comment: "Title of button that asks the users if they'd like to focus on checking their sites stats") + static let writing = NSLocalizedString("Writing blog posts", comment: "Title of button that asks the users if they'd like to focus on checking their sites stats") + static let notifications = NSLocalizedString("Staying up to date with notifications", comment: "Title of button that asks the users if they'd like to focus on checking their sites stats") + static let reader = NSLocalizedString("Reading posts from other sites", comment: "Title of button that asks the users if they'd like to focus on checking their sites stats") + static let notSure = NSLocalizedString("Not sure, show me around", comment: "Button that allows users unsure of what selection they'd like ") + static let skip = NSLocalizedString("Skip", comment: "Button that allows the user to skip the prompt and be brought to the app") +} + +private struct Constants { + static let iconSize = 24.0 +} diff --git a/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsPromptViewController.xib b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsPromptViewController.xib new file mode 100644 index 000000000000..ac403d0e322f --- /dev/null +++ b/WordPress/Classes/ViewRelated/Blog/Onboarding Questions Prompt/OnboardingQuestionsPromptViewController.xib @@ -0,0 +1,203 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartCell.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartCell.swift index 64609badc89a..3748f0b139c6 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartCell.swift +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartCell.swift @@ -14,7 +14,11 @@ import UIKit selectionStyle = .none - tourStateView.configure(blog: blog, sourceController: viewController) + let checklistTappedTracker: QuickStartChecklistTappedTracker = (event: .quickStartTapped, properties: [:]) + + tourStateView.configure(blog: blog, + sourceController: viewController, + checklistTappedTracker: checklistTappedTracker) } private enum Metrics { diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartPromptViewController.xib b/WordPress/Classes/ViewRelated/Blog/QuickStartPromptViewController.xib index 1d964e4a8d3d..333c82332a46 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartPromptViewController.xib +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartPromptViewController.xib @@ -1,9 +1,9 @@ - + - + diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift index fc6e7c56fb38..c2c5280bd3b4 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartTourGuide.swift @@ -15,7 +15,6 @@ open class QuickStartTourGuide: NSObject { private var currentSuggestion: QuickStartTour? private var currentTourState: TourState? private var suggestionWorkItem: DispatchWorkItem? - private var taskCompleteWorkItem: DispatchWorkItem? private weak var recentlyTouredBlog: Blog? private let noticeTag: Notice.Tag = "QuickStartTour" static let notificationElementKey = "QuickStartElementKey" @@ -253,7 +252,7 @@ open class QuickStartTourGuide: NSObject { } if element != currentElement { let blogDetailEvents: [QuickStartTourElement] = [.blogDetailNavigation, .checklist, .themes, .viewSite, .sharing, .siteMenu] - let readerElements: [QuickStartTourElement] = [.readerTab, .readerSearch] + let readerElements: [QuickStartTourElement] = [.readerTab, .readerDiscoverSettings] if blogDetailEvents.contains(element) { endCurrentTour() diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift index a18a0720a494..c4357362c771 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartTours.swift @@ -191,22 +191,32 @@ struct QuickStartPublishTour: QuickStartTour { struct QuickStartFollowTour: QuickStartTour { let key = "quick-start-follow-tour" let analyticsKey = "follow_site" - let title = NSLocalizedString("Follow other sites", comment: "Title of a Quick Start Tour") - let titleMarkedCompleted = NSLocalizedString("Completed: Follow other sites", comment: "The Quick Start Tour title after the user finished the step.") - let description = NSLocalizedString("Find sites that speak to you, and follow them to get updates when they publish.", comment: "Description of a Quick Start Tour") + let title = NSLocalizedString("Connect with other sites", comment: "Title of a Quick Start Tour") + let titleMarkedCompleted = NSLocalizedString("Completed: Connect with other sites", comment: "The Quick Start Tour title after the user finished the step.") + let description = NSLocalizedString("Discover and follow sites that inspire you.", comment: "Description of a Quick Start Tour") let icon = UIImage.gridicon(.readerFollow) let suggestionNoText = Strings.notNow let suggestionYesText = Strings.yesShowMe let possibleEntryPoints: Set = [.blogDetails, .blogDashboard] var waypoints: [WayPoint] = { - let step1DescriptionBase = NSLocalizedString("Select %@ to continue", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") + let step1DescriptionBase = NSLocalizedString("Select %@ to find other sites.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") let step1DescriptionTarget = NSLocalizedString("Reader", comment: "The menu item to select during a guided tour.") let step1: WayPoint = (element: .readerTab, description: step1DescriptionBase.highlighting(phrase: step1DescriptionTarget, icon: .gridicon(.reader))) - let step2DescriptionBase = NSLocalizedString("Select %@ to look for sites with similar interests", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") - let step2DescriptionTarget = NSLocalizedString("Search", comment: "The menu item to select during a guided tour.") - let step2: WayPoint = (element: .readerSearch, description: step2DescriptionBase.highlighting(phrase: step2DescriptionTarget, icon: .gridicon(.search))) + let step2DiscoverDescriptionBase = NSLocalizedString("Use %@ to find sites and tags.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") + let step2DiscoverDescriptionTarget = NSLocalizedString("Discover", comment: "The menu item to select during a guided tour.") + let step2DiscoverDescription = step2DiscoverDescriptionBase.highlighting(phrase: step2DiscoverDescriptionTarget, icon: nil) + + let step2SettingsDescriptionBase = NSLocalizedString("Try selecting %@ to add topics you like.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") + let step2SettingsDescriptionTarget = NSLocalizedString("Settings", comment: "The menu item to select during a guided tour.") + let step2SettingsDescription = step2SettingsDescriptionBase.highlighting(phrase: step2SettingsDescriptionTarget, icon: .gridicon(.cog)) + + /// Combined description for step 2 + let step2Format = NSAttributedString(string: "%@ %@") + let step2Description = NSAttributedString(format: step2Format, args: step2DiscoverDescription, step2SettingsDescription) + + let step2: WayPoint = (element: .readerDiscoverSettings, description: step2Description) return [step1, step2] }() @@ -289,31 +299,6 @@ struct QuickStartReviewPagesTour: QuickStartTour { let accessibilityHintText = NSLocalizedString("Guides you through the process of creating a new page for your site.", comment: "This value is used to set the accessibility hint text for creating a new page for the user's site.") } -struct QuickStartEditHomepageTour: QuickStartTour { - let key = "quick-start-edit-homepage-tour" - let analyticsKey = "edit_homepage" - let title = NSLocalizedString("Edit your homepage", comment: "Title of a Quick Start Tour") - let titleMarkedCompleted = NSLocalizedString("Completed: Edit your homepage", comment: "The Quick Start Tour title after the user finished the step.") - let description = NSLocalizedString("Change, add, or remove content from your site's homepage.", comment: "Description of a Quick Start Tour") - let icon = UIImage.gridicon(.house) - let suggestionNoText = Strings.notNow - let suggestionYesText = Strings.yesShowMe - let possibleEntryPoints: Set = [.blogDetails] - - var waypoints: [WayPoint] = { - let descriptionBase = NSLocalizedString("Select %@ to see your page list.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") - let descriptionTarget = NSLocalizedString("Pages", comment: "The item to select during a guided tour.") - let descriptionHomepage = NSLocalizedString("Select %@ to edit your Homepage.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") - let homepageTarget = NSLocalizedString("Homepage", comment: "The item to select during a guided tour.") - return [ - (element: .pages, description: descriptionBase.highlighting(phrase: descriptionTarget, icon: .gridicon(.pages))), - (element: .editHomepage, description: descriptionHomepage.highlighting(phrase: homepageTarget, icon: .gridicon(.house))) - ] - }() - - let accessibilityHintText = NSLocalizedString("Guides you through the process of creating a new page for your site.", comment: "This value is used to set the accessibility hint text for creating a new page for the user's site.") -} - struct QuickStartCheckStatsTour: QuickStartTour { let key = "quick-start-check-stats-tour" let analyticsKey = "check_stats" @@ -360,6 +345,32 @@ struct QuickStartExplorePlansTour: QuickStartTour { let accessibilityHintText = NSLocalizedString("Guides you through the process of exploring plans for your site.", comment: "This value is used to set the accessibility hint text for exploring plans on the user's site.") } +struct QuickStartNotificationsTour: QuickStartTour { + let key = "quick-start-notifications-tour" + let analyticsKey = "notifications" + let title = NSLocalizedString("Check your notifications", comment: "Title of a Quick Start Tour") + let titleMarkedCompleted = NSLocalizedString("Completed: Check your notifications", comment: "The Quick Start Tour title after the user finished the step.") + let description = NSLocalizedString("Get real time updates from your pocket.", comment: "Description of a Quick Start Tour") + let icon = UIImage.gridicon(.bell) + let suggestionNoText = Strings.notNow + let suggestionYesText = Strings.yesShowMe + let possibleEntryPoints: Set = [.blogDetails, .blogDashboard] + + var taskCompleteDescription: NSAttributedString? = { + let descriptionBase = NSLocalizedString("%@ Tip: get updates faster by enabling push notifications.", comment: "Title of the task complete hint for the Quick Start Tour") + let descriptionTarget = NSLocalizedString("Task complete.", comment: "A hint about the completed guided tour.") + return descriptionBase.highlighting(phrase: descriptionTarget, icon: .gridicon(.checkmark)) + }() + + var waypoints: [WayPoint] = { + let descriptionBase = NSLocalizedString("Select the %@ tab to get updates on the go.", comment: "A step in a guided tour for quick start. %@ will be the name of the item to select.") + let descriptionTarget = NSLocalizedString("Notifications", comment: "The item to select during a guided tour.") + return [(element: .notifications, description: descriptionBase.highlighting(phrase: descriptionTarget, icon: .gridicon(.bell)))] + }() + + let accessibilityHintText = NSLocalizedString("Guides you through the process of checking your notifications.", comment: "This value is used to set the accessibility hint text for viewing the user's notifications.") +} + private let congratsTitle = NSLocalizedString("Congrats on finishing Quick Start 🎉", comment: "Title of a Quick Start Tour") private let congratsDescription = NSLocalizedString("doesn’t it feel good to cross things off a list?", comment: "subhead shown to users when they complete all Quick Start items") struct QuickStartCongratulationsTour: QuickStartTour { @@ -430,3 +441,15 @@ private extension String { } } } + +private extension NSAttributedString { + convenience init(format: NSAttributedString, args: NSAttributedString...) { + let mutableNSAttributedString = NSMutableAttributedString(attributedString: format) + + args.forEach { (attributedString) in + let range = NSString(string: mutableNSAttributedString.string).range(of: "%@") + mutableNSAttributedString.replaceCharacters(in: range, with: attributedString) + } + self.init(attributedString: mutableNSAttributedString) + } +} diff --git a/WordPress/Classes/ViewRelated/Blog/QuickStartToursCollection.swift b/WordPress/Classes/ViewRelated/Blog/QuickStartToursCollection.swift index d1cfd44e20a4..4e3e1bcb7c9b 100644 --- a/WordPress/Classes/ViewRelated/Blog/QuickStartToursCollection.swift +++ b/WordPress/Classes/ViewRelated/Blog/QuickStartToursCollection.swift @@ -28,7 +28,6 @@ struct QuickStartCustomizeToursCollection: QuickStartToursCollection { QuickStartCreateTour(), QuickStartSiteTitleTour(blog: blog), QuickStartSiteIconTour(), - QuickStartEditHomepageTour(), QuickStartReviewPagesTour(), QuickStartViewTour(blog: blog) ] @@ -76,6 +75,7 @@ struct QuickStartGetToKnowAppCollection: QuickStartToursCollection { self.analyticsKey = "get-to-know" self.tours = [ QuickStartCheckStatsTour(), + QuickStartNotificationsTour(), QuickStartViewTour(blog: blog), QuickStartFollowTour() ] diff --git a/WordPress/Classes/ViewRelated/Blog/Site Picker/SitePickerViewController+QuickStart.swift b/WordPress/Classes/ViewRelated/Blog/Site Picker/SitePickerViewController+QuickStart.swift index e2d098de9302..528b4d52a487 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Picker/SitePickerViewController+QuickStart.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Picker/SitePickerViewController+QuickStart.swift @@ -47,8 +47,4 @@ extension SitePickerViewController { QuickStartTourGuide.shared.suggest(tourToSuggest, for: blog) } } - - private enum Constants { - static let bottomPaddingForQuickStartNotices: CGFloat = 80.0 - } } diff --git a/WordPress/Classes/ViewRelated/Blog/Site Picker/SitePickerViewController.swift b/WordPress/Classes/ViewRelated/Blog/Site Picker/SitePickerViewController.swift index d1553e3c0140..e1c1c5fa1077 100644 --- a/WordPress/Classes/ViewRelated/Blog/Site Picker/SitePickerViewController.swift +++ b/WordPress/Classes/ViewRelated/Blog/Site Picker/SitePickerViewController.swift @@ -252,11 +252,6 @@ extension SitePickerViewController { // currently working on the View Site tour. tourGuide.completeViewSiteTour(forBlog: blog) } - - guard let parentVC = parent as? MySiteViewController else { - return - } - parentVC.additionalSafeAreaInsets = .zero } } diff --git a/WordPress/Classes/ViewRelated/Blog/WPStyleGuide+BloggingPrompts.swift b/WordPress/Classes/ViewRelated/Blog/WPStyleGuide+BloggingPrompts.swift new file mode 100644 index 000000000000..b75731dc6033 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Blog/WPStyleGuide+BloggingPrompts.swift @@ -0,0 +1,12 @@ +/// This class groups styles used by blogging prompts +/// +extension WPStyleGuide { + public struct BloggingPrompts { + static let promptContentFont = WPStyleGuide.serifFontForTextStyle(.headline, fontWeight: .semibold) + static let answerInfoLabelFont = WPStyleGuide.fontForTextStyle(.caption1) + static let answerInfoLabelColor = UIColor.primary + static let buttonTitleFont = WPStyleGuide.fontForTextStyle(.subheadline) + static let buttonTitleColor = UIColor.primary + static let answeredLabelColor = UIColor.muriel(name: .green, .shade50) + } +} diff --git a/WordPress/Classes/ViewRelated/Feature Highlight/TooltipAnchor.swift b/WordPress/Classes/ViewRelated/Feature Highlight/TooltipAnchor.swift new file mode 100644 index 000000000000..8acb2eea5659 --- /dev/null +++ b/WordPress/Classes/ViewRelated/Feature Highlight/TooltipAnchor.swift @@ -0,0 +1,83 @@ +import UIKit + +final class TooltipAnchor: UIControl { + private enum Constants { + static let horizontalMarginToBounds: CGFloat = 16 + static let verticalMarginToBounds: CGFloat = 9 + static let stackViewSpacing: CGFloat = 4 + static let viewHeight: CGFloat = 40 + } + + var title: String? { + didSet { + titleLabel.text = title + accessibilityLabel = title + } + } + + private lazy var titleLabel: UILabel = { + $0.textColor = .invertedLabel + $0.font = WPStyleGuide.fontForTextStyle(.body) + return $0 + }(UILabel()) + + private lazy var highlightLabel: UILabel = { + $0.font = WPStyleGuide.fontForTextStyle(.body) + $0.text = "✨" + return $0 + }(UILabel()) + + private lazy var stackView: UIStackView = { + $0.addArrangedSubviews([highlightLabel, titleLabel]) + $0.spacing = Constants.stackViewSpacing + return $0 + }(UIStackView()) + + init() { + super.init(frame: .zero) + commonInit() + } + + func dismissByFadingOut() { + UIView.animate(withDuration: 0.3) { + self.alpha = 0 + } completion: { _ in + self.removeFromSuperview() + } + } + + required init?(coder: NSCoder) { + super.init(coder: coder) + commonInit() + } + + private func commonInit() { + setUpViewHierarchy() + configureUI() + } + + private func setUpViewHierarchy() { + stackView.translatesAutoresizingMaskIntoConstraints = false + addSubview(stackView) + + NSLayoutConstraint.activate([ + heightAnchor.constraint(equalToConstant: Constants.viewHeight), + stackView.topAnchor.constraint(equalTo: topAnchor, constant: Constants.verticalMarginToBounds), + stackView.leadingAnchor.constraint(equalTo: leadingAnchor, constant: Constants.horizontalMarginToBounds), + trailingAnchor.constraint(equalTo: stackView.trailingAnchor, constant: Constants.horizontalMarginToBounds), + bottomAnchor.constraint(equalTo: stackView.bottomAnchor, constant: Constants.verticalMarginToBounds) + ]) + } + + private func configureUI() { + backgroundColor = .invertedSystem5 + layer.cornerRadius = Constants.viewHeight / 2 + addShadow() + } + + private func addShadow() { + layer.shadowColor = UIColor.black.cgColor + layer.shadowOffset = CGSize(width: 0, height: 2) + layer.shadowOpacity = 0.5 + } +} diff --git a/WordPress/Classes/ViewRelated/Feature Introduction/Blogging Prompts/BloggingPromptsFeatureDescriptionView.swift b/WordPress/Classes/ViewRelated/Feature Introduction/Blogging Prompts/BloggingPromptsFeatureDescriptionView.swift index 02aa5347db42..efe2499d71d0 100644 --- a/WordPress/Classes/ViewRelated/Feature Introduction/Blogging Prompts/BloggingPromptsFeatureDescriptionView.swift +++ b/WordPress/Classes/ViewRelated/Feature Introduction/Blogging Prompts/BloggingPromptsFeatureDescriptionView.swift @@ -28,15 +28,17 @@ private extension BloggingPromptsFeatureDescriptionView { func configurePromptCard() { let promptCard = DashboardPromptsCardCell() promptCard.configureForExampleDisplay() - promptCard.translatesAutoresizingMaskIntoConstraints = false - promptCard.layer.cornerRadius = Style.cardCornerRadius - promptCard.layer.shadowOffset = Style.cardShadowOffset - promptCard.layer.shadowOpacity = Style.cardShadowOpacity - promptCard.layer.shadowRadius = Style.cardShadowRadius + // The DashboardPromptsCardCell doesn't resize dynamically when used in this context. + // So use its cardFrameView instead. + promptCard.cardFrameView.translatesAutoresizingMaskIntoConstraints = false + promptCard.cardFrameView.layer.cornerRadius = Style.cardCornerRadius + promptCard.cardFrameView.layer.shadowOffset = Style.cardShadowOffset + promptCard.cardFrameView.layer.shadowOpacity = Style.cardShadowOpacity + promptCard.cardFrameView.layer.shadowRadius = Style.cardShadowRadius - promptCardView.addSubview(promptCard) - promptCardView.pinSubviewToSafeArea(promptCard) + promptCardView.addSubview(promptCard.cardFrameView) + promptCardView.pinSubviewToAllEdges(promptCard.cardFrameView) } func configureDescription() { diff --git a/WordPress/Classes/ViewRelated/Feature Introduction/Blogging Prompts/BloggingPromptsFeatureDescriptionView.xib b/WordPress/Classes/ViewRelated/Feature Introduction/Blogging Prompts/BloggingPromptsFeatureDescriptionView.xib index 63dfc17cd737..c51b8e1ce7d2 100644 --- a/WordPress/Classes/ViewRelated/Feature Introduction/Blogging Prompts/BloggingPromptsFeatureDescriptionView.xib +++ b/WordPress/Classes/ViewRelated/Feature Introduction/Blogging Prompts/BloggingPromptsFeatureDescriptionView.xib @@ -16,20 +16,20 @@ - + - + - + @@ -40,11 +40,11 @@ + - - + diff --git a/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/CollapsableHeaderViewController.swift b/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/CollapsableHeaderViewController.swift index 92d22f95fdac..7ae90a5d4a7d 100644 --- a/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/CollapsableHeaderViewController.swift +++ b/WordPress/Classes/ViewRelated/Gutenberg/Collapsable Header/CollapsableHeaderViewController.swift @@ -509,6 +509,7 @@ class CollapsableHeaderViewController: UIViewController, NoResultsViewHost { func configureVerticalButtonView() { usesVerticalActionButtons = true + footerView.backgroundColor = .systemBackground footerHeightContraint.constant = footerHeight selectedStateButtonsContainer.axis = .vertical @@ -521,6 +522,7 @@ class CollapsableHeaderViewController: UIViewController, NoResultsViewHost { visualEffects.forEach { (visualEffect) in visualEffect.isHidden = true } + navigationController?.navigationBar.backgroundColor = .systemBackground } /// In scenarios where the content offset before content changes doesn't align with the available space after the content changes then the offset can be lost. In diff --git a/WordPress/Classes/ViewRelated/NUX/ContentViews/Editor/UnifiedPrologueNotificationsContentView.swift b/WordPress/Classes/ViewRelated/NUX/ContentViews/Editor/UnifiedPrologueNotificationsContentView.swift index 67b350b07d7e..831d0b71f6e7 100644 --- a/WordPress/Classes/ViewRelated/NUX/ContentViews/Editor/UnifiedPrologueNotificationsContentView.swift +++ b/WordPress/Classes/ViewRelated/NUX/ContentViews/Editor/UnifiedPrologueNotificationsContentView.swift @@ -1,7 +1,23 @@ import SwiftUI +struct UnifiedPrologueNotificationsContent { + let topElementTitle: String + let middleElementTitle: String + let bottomElementTitle: String + + var topImage: String = UnifiedPrologueNotificationsContentView.Appearance.topImage + var middleImage: String = UnifiedPrologueNotificationsContentView.Appearance.middleImage + var bottomImage: String = UnifiedPrologueNotificationsContentView.Appearance.bottomImage +} + /// Prologue notifications page contents struct UnifiedPrologueNotificationsContentView: View { + private let textContent: UnifiedPrologueNotificationsContent + + init(_ textContent: UnifiedPrologueNotificationsContent? = nil) { + self.textContent = textContent ?? Appearance.textContent + } + var body: some View { GeometryReader { content in let spacingUnit = content.size.height * 0.06 @@ -13,12 +29,13 @@ struct UnifiedPrologueNotificationsContentView: View { weight: .regular, design: .default) + VStack { Spacer() RoundRectangleView { HStack { - NotificationIcon(image: Appearance.topImage, size: notificationIconSize) - Text(string: Appearance.topElementTitle) + NotificationIcon(image: textContent.topImage, size: notificationIconSize) + Text(string: textContent.topElementTitle) .font(notificationFont) .fixedSize(horizontal: false, vertical: true) .lineLimit(.none) @@ -49,8 +66,8 @@ struct UnifiedPrologueNotificationsContentView: View { RoundRectangleView { HStack { - NotificationIcon(image: Appearance.middleImage, size: notificationIconSize) - Text(string: Appearance.middleElementTitle) + NotificationIcon(image: textContent.middleImage, size: notificationIconSize) + Text(string: textContent.middleElementTitle) .font(notificationFont) .fixedSize(horizontal: false, vertical: true) .lineLimit(.none) @@ -66,8 +83,8 @@ struct UnifiedPrologueNotificationsContentView: View { RoundRectangleView { HStack { - NotificationIcon(image: Appearance.bottomImage, size: notificationIconSize) - Text(string: Appearance.bottomElementTitle) + NotificationIcon(image: textContent.bottomImage, size: notificationIconSize) + Text(string: textContent.bottomElementTitle) .font(notificationFont) .fixedSize(horizontal: false, vertical: true) .lineLimit(.none) @@ -113,5 +130,9 @@ private extension UnifiedPrologueNotificationsContentView { static let topElementTitle: String = NSLocalizedString("*Madison Ruiz* liked your post", comment: "Example Like notification displayed in the prologue carousel of the app. Username should be marked with * characters and will be displayed as bold text.") static let middleElementTitle: String = NSLocalizedString("You received *50 likes* on your site today", comment: "Example Likes notification displayed in the prologue carousel of the app. Number of likes should marked with * characters and will be displayed as bold text.") static let bottomElementTitle: String = NSLocalizedString("*Johann Brandt* responded to your post", comment: "Example Comment notification displayed in the prologue carousel of the app. Username should be marked with * characters and will be displayed as bold text.") + + static let textContent = UnifiedPrologueNotificationsContent(topElementTitle: Self.topElementTitle, + middleElementTitle: Self.middleElementTitle, + bottomElementTitle: Self.bottomElementTitle) } } diff --git a/WordPress/Classes/ViewRelated/NUX/WordPressAuthenticationManager.swift b/WordPress/Classes/ViewRelated/NUX/WordPressAuthenticationManager.swift index 06e7753b4a4a..8ff99041acf8 100644 --- a/WordPress/Classes/ViewRelated/NUX/WordPressAuthenticationManager.swift +++ b/WordPress/Classes/ViewRelated/NUX/WordPressAuthenticationManager.swift @@ -335,7 +335,8 @@ extension WordPressAuthenticationManager: WordPressAuthenticatorDelegate { // If adding a self-hosted site, skip the Epilogue if let wporg = credentials.wporg, let blog = Blog.lookup(username: wporg.username, xmlrpc: wporg.xmlrpc, in: ContextManager.shared.mainContext) { - presentQuickStartPrompt(for: blog, in: navigationController, onDismiss: onDismissQuickStartPromptForExistingSiteHandler) + let onDismissHandler = FeatureFlag.quickStartForExistingUsers.enabled ? onDismissQuickStartPromptForExistingSiteHandler : onDismissQuickStartPromptForNewSiteHandler + presentQuickStartPrompt(for: blog, in: navigationController, onDismiss: onDismissHandler) return } @@ -344,33 +345,33 @@ extension WordPressAuthenticationManager: WordPressAuthenticatorDelegate { return } - //Present the epilogue view + // Present the epilogue view let storyboard = UIStoryboard(name: "LoginEpilogue", bundle: .main) guard let epilogueViewController = storyboard.instantiateInitialViewController() as? LoginEpilogueViewController else { fatalError() } - epilogueViewController.credentials = credentials - - epilogueViewController.onBlogSelected = { [weak self] blog in + let onBlogSelected: ((Blog) -> Void) = { [weak self] blog in guard let self = self else { return } + // If the user just signed in, refresh the A/B assignments + ABTest.start() + self.recentSiteService.touch(blog: blog) + self.presentOnboardingQuestionsPrompt(in: navigationController, onDismiss: onDismiss) + } - guard self.quickStartSettings.isQuickStartAvailable(for: blog) else { - if self.windowManager.isShowingFullscreenSignIn { - self.windowManager.dismissFullscreenSignIn(blogToShow: blog) - } else { - self.windowManager.showAppUI(for: blog) - } - return - } - let onDismissHandler = FeatureFlag.quickStartForExistingUsers.enabled ? onDismissQuickStartPromptForExistingSiteHandler : onDismissQuickStartPromptForNewSiteHandler - self.presentQuickStartPrompt(for: blog, in: navigationController, onDismiss: onDismissHandler) + // If the user has only 1 blog, skip the site selector and go right to the next step + if numberOfBlogs() == 1, let firstBlog = firstBlog() { + onBlogSelected(firstBlog) + return } + epilogueViewController.credentials = credentials + epilogueViewController.onBlogSelected = onBlogSelected + epilogueViewController.onCreateNewSite = { let wizardLauncher = SiteCreationWizardLauncher(onDismiss: onDismissQuickStartPromptForNewSiteHandler) guard let wizard = wizardLauncher.ui else { @@ -383,6 +384,7 @@ extension WordPressAuthenticationManager: WordPressAuthenticatorDelegate { navigationController.delegate = epilogueViewController navigationController.pushViewController(epilogueViewController, animated: true) + } /// Presents the Signup Epilogue, in the specified NavigationController. @@ -430,11 +432,7 @@ extension WordPressAuthenticationManager: WordPressAuthenticatorDelegate { return true } - let context = ContextManager.sharedInstance().mainContext - let service = AccountService(managedObjectContext: context) - let numberOfBlogs = service.defaultWordPressComAccount()?.blogs?.count ?? 0 - - return numberOfBlogs > 0 + return numberOfBlogs() > 0 } /// Indicates if the Signup Epilogue should be displayed. @@ -532,6 +530,68 @@ extension WordPressAuthenticationManager: WordPressAuthenticatorDelegate { } } +// MARK: - Blog Count Helpers +private extension WordPressAuthenticationManager { + private func numberOfBlogs() -> Int { + let context = ContextManager.sharedInstance().mainContext + let service = AccountService(managedObjectContext: context) + let numberOfBlogs = service.defaultWordPressComAccount()?.blogs?.count ?? 0 + + return numberOfBlogs + } + + private func firstBlog() -> Blog? { + let context = ContextManager.sharedInstance().mainContext + let service = AccountService(managedObjectContext: context) + + return service.defaultWordPressComAccount()?.blogs?.first + } +} + +// MARK: - Onboarding Questions Prompt +private extension WordPressAuthenticationManager { + private func presentOnboardingQuestionsPrompt(in navigationController: UINavigationController, onDismiss: (() -> Void)? = nil) { + let windowManager = self.windowManager + + let coordinator = OnboardingQuestionsCoordinator() + coordinator.navigationController = navigationController + + let viewController = OnboardingQuestionsPromptViewController(with: coordinator) + + coordinator.onDismiss = { selectedOption in + self.handleOnboardingQuestionsWillDismiss(option: selectedOption) + + let completion: (() -> Void)? = { + let userInfo = ["option": selectedOption] + NotificationCenter.default.post(name: .onboardingPromptWasDismissed, object: nil, userInfo: userInfo) + } + + if windowManager.isShowingFullscreenSignIn { + windowManager.dismissFullscreenSignIn(completion: completion) + } else { + navigationController.dismiss(animated: true, completion: completion) + } + + onDismiss?() + } + + navigationController.pushViewController(viewController, animated: true) + } + + + /// To prevent a weird jump from the MySite tab to the reader/notifications tab + /// We'll pre-switch to the users selected tab before the login flow dismisses + private func handleOnboardingQuestionsWillDismiss(option: OnboardingOption) { + if option == .reader { + WPTabBarController.sharedInstance().showReaderTab() + } else if option == .notifications { + WPTabBarController.sharedInstance().showNotificationsTab() + } + } + + +} + // MARK: - Quick Start Prompt private extension WordPressAuthenticationManager { diff --git a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift index f2eaf85d36c0..5bef417ff4f8 100644 --- a/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift +++ b/WordPress/Classes/ViewRelated/Notifications/Controllers/NotificationsViewController.swift @@ -200,6 +200,13 @@ class NotificationsViewController: UITableViewController, UIViewControllerRestor override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) + + defer { + if AppConfiguration.showsWhatIsNew { + WPTabBarController.sharedInstance()?.presentWhatIsNew(on: self) + } + } + syncNewNotifications() markSelectedNotificationAsRead() @@ -211,18 +218,20 @@ class NotificationsViewController: UITableViewController, UIViewControllerRestor userDefaults.notificationsTabAccessCount += 1 } + // Don't show the notification primers if we already asked during onboarding + if userDefaults.onboardingNotificationsPromptDisplayed, userDefaults.notificationsTabAccessCount == 1 { + return + } + if shouldShowPrimeForPush { setupNotificationPrompt() } else if AppRatingUtility.shared.shouldPromptForAppReview(section: InlinePrompt.section) { setupAppRatings() self.showInlinePrompt() } + showNotificationPrimerAlertIfNeeded() showSecondNotificationsAlertIfNeeded() - - if AppConfiguration.showsWhatIsNew { - WPTabBarController.sharedInstance()?.presentWhatIsNew(on: self) - } } override func viewWillDisappear(_ animated: Bool) { @@ -1939,13 +1948,12 @@ extension NotificationsViewController: UIViewControllerTransitioningDelegate { } private func showNotificationPrimerAlertIfNeeded() { - - guard !userDefaults.notificationPrimerAlertWasDisplayed else { + guard shouldShowPrimeForPush, !userDefaults.notificationPrimerAlertWasDisplayed else { return } DispatchQueue.main.asyncAfter(deadline: .now() + Constants.displayAlertDelay) { - self.showNotificationPrimerAlert() + self.showNotificationPrimerAlert() } } diff --git a/WordPress/Classes/ViewRelated/Pages/PageListViewController.swift b/WordPress/Classes/ViewRelated/Pages/PageListViewController.swift index 1f8371ad958f..031d12326dcb 100644 --- a/WordPress/Classes/ViewRelated/Pages/PageListViewController.swift +++ b/WordPress/Classes/ViewRelated/Pages/PageListViewController.swift @@ -420,13 +420,6 @@ class PageListViewController: AbstractPostListViewController, UIViewControllerRe let page = pageAtIndexPath(indexPath) if page.isSiteHomepage { - let guide = QuickStartTourGuide.shared - if guide.isCurrentElement(.editHomepage) { - QuickStartTourGuide.shared.visited(.editHomepage) - } else { - QuickStartTourGuide.shared.complete(tour: QuickStartEditHomepageTour(), silentlyForBlog: blog) - } - tableView.reloadRows(at: [indexPath], with: .automatic) } else if page.isSitePostsPage { showSitePostPageUneditableNotice() @@ -461,12 +454,6 @@ class PageListViewController: AbstractPostListViewController, UIViewControllerRe configureCell(cell, at: indexPath) - if page.isSiteHomepage && QuickStartTourGuide.shared.isCurrentElement(.editHomepage) { - cell.accessoryView = QuickStartSpotlightView() - } else { - cell.accessoryView = nil - } - return cell } @@ -771,21 +758,9 @@ class PageListViewController: AbstractPostListViewController, UIViewControllerRe } override func deletePost(_ apost: AbstractPost) { - completeQuickStartStepIfNeeded(apost) super.deletePost(apost) } - private func completeQuickStartStepIfNeeded(_ page: AbstractPost) { - guard let page = page as? Page else { return } - guard page.isSiteHomepage else { return } - - if QuickStartTourGuide.shared.isCurrentElement(.editHomepage) { - QuickStartTourGuide.shared.visited(.editHomepage) - } else { - QuickStartTourGuide.shared.complete(tour: QuickStartEditHomepageTour(), for: blog, postNotification: false) - } - } - private func addEditAction(to controller: UIAlertController, for page: AbstractPost) { guard let page = page as? Page else { return } diff --git a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsFollowPresenter.swift b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsFollowPresenter.swift index bd7709969b65..d3d24c21c008 100644 --- a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsFollowPresenter.swift +++ b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsFollowPresenter.swift @@ -32,7 +32,7 @@ class ReaderCommentsFollowPresenter: NSObject { // MARK: - Subscriptions /// Toggles the state of conversation subscription. - /// When enabled, the user will receive emails for new comments. + /// When enabled, the user will receive emails and in-app notifications for new comments. /// @objc func handleFollowConversationButtonTapped() { trackFollowToggled() @@ -65,13 +65,8 @@ class ReaderCommentsFollowPresenter: NSObject { return } - // Show notice with Enable option. - self?.presentingViewController.displayActionableNotice(title: Messages.promptTitle, - message: Messages.promptMessage, - actionTitle: Messages.enableActionTitle, - actionHandler: { (accepted: Bool) in - self?.handleNotificationsButtonTapped(canUndo: true) - }) + // Show notice with Undo option. Push Notifications are opt-out. + self?.updateNotificationSettings(shouldEnableNotifications: true, canUndo: true) } } @@ -98,12 +93,33 @@ class ReaderCommentsFollowPresenter: NSObject { /// - Parameter completion: Block called as soon the view controller has been removed. /// @objc func handleNotificationsButtonTapped(canUndo: Bool, completion: ((Bool) -> Void)? = nil) { - trackNotificationsToggled() + trackNotificationsToggled(isNotificationEnabled: !post.receivesCommentNotifications) - let desiredState = !self.post.receivesCommentNotifications - let action: PostSubscriptionAction = desiredState ? .enableNotification : .disableNotification + let shouldEnableNotifications = !self.post.receivesCommentNotifications - followCommentsService?.toggleNotificationSettings(desiredState, success: { [weak self] in + updateNotificationSettings(shouldEnableNotifications: shouldEnableNotifications, canUndo: canUndo, completion: completion) + } + + // MARK: - Notification Sheet + + @objc func showNotificationSheet(sourceBarButtonItem: UIBarButtonItem?) { + showBottomSheet(sourceBarButtonItem: sourceBarButtonItem) + } + + func showNotificationSheet(sourceView: UIView?) { + showBottomSheet(sourceView: sourceView) + } + +} + +// MARK: - Private Extension + +private extension ReaderCommentsFollowPresenter { + + private func updateNotificationSettings(shouldEnableNotifications: Bool, canUndo: Bool, completion: ((Bool) -> Void)? = nil) { + let action: ReaderHelpers.PostSubscriptionAction = shouldEnableNotifications ? .enableNotification : .disableNotification + + followCommentsService?.toggleNotificationSettings(shouldEnableNotifications, success: { [weak self] in completion?(true) self?.informDelegateNotificationComplete(success: true) @@ -112,43 +128,27 @@ class ReaderCommentsFollowPresenter: NSObject { } guard canUndo else { - let title = self.noticeTitle(forAction: action, success: true) + let title = ReaderHelpers.noticeTitle(forAction: action, success: true) self.presentingViewController.displayNotice(title: title) return } - let title = self.noticeTitle(forAction: action, success: true) - - self.presentingViewController.displayActionableNotice(title: title, - actionTitle: Messages.undoActionTitle, - actionHandler: { (accepted: Bool) in + self.presentingViewController.displayActionableNotice( + title: Messages.promptTitle, + message: Messages.promptMessage, + actionTitle: Messages.undoActionTitle, + actionHandler: { (accepted: Bool) in self.handleNotificationsButtonTapped(canUndo: false) }) }, failure: { [weak self] error in DDLogError("Reader Comments: error toggling notification status: \(String(describing: error)))") - let title = self?.noticeTitle(forAction: action, success: false) ?? "" + let title = ReaderHelpers.noticeTitle(forAction: action, success: false) self?.presentingViewController.displayNotice(title: title) completion?(false) self?.informDelegateNotificationComplete(success: false) }) } - // MARK: - Notification Sheet - - @objc func showNotificationSheet(sourceBarButtonItem: UIBarButtonItem?) { - showBottomSheet(sourceBarButtonItem: sourceBarButtonItem) - } - - func showNotificationSheet(sourceView: UIView?) { - showBottomSheet(sourceView: sourceView) - } - -} - -// MARK: - Private Extension - -private extension ReaderCommentsFollowPresenter { - func showBottomSheet(sourceView: UIView? = nil, sourceBarButtonItem: UIBarButtonItem? = nil) { let sheetViewController = ReaderCommentsNotificationSheetViewController(isNotificationEnabled: post.receivesCommentNotifications, delegate: self) let bottomSheet = BottomSheetViewController(childViewController: sheetViewController) @@ -176,31 +176,11 @@ private extension ReaderCommentsFollowPresenter { // In-app notifications prompt static let promptTitle = NSLocalizedString("Following this conversation", comment: "The app successfully subscribed to the comments for the post") - static let promptMessage = NSLocalizedString("Enable in-app notifications?", comment: "Hint for the action button that enables notification for new comments") + static let promptMessage = NSLocalizedString("You'll get notifications in the app", comment: "Message for the action with opt-out revert action.") static let enableActionTitle = NSLocalizedString("Enable", comment: "Button title to enable notifications for new comments") static let undoActionTitle = NSLocalizedString("Undo", comment: "Button title. Reverts the previous notification operation") } - /// Enumerates the kind of actions available in relation to post subscriptions. - /// TODO: Add `followConversation` and `unfollowConversation` once the "Follow Conversation" feature flag is removed. - enum PostSubscriptionAction: Int { - case enableNotification - case disableNotification - } - - func noticeTitle(forAction action: PostSubscriptionAction, success: Bool) -> String { - switch (action, success) { - case (.enableNotification, true): - return NSLocalizedString("In-app notifications enabled", comment: "The app successfully enabled notifications for the subscription") - case (.enableNotification, false): - return NSLocalizedString("Could not enable notifications", comment: "The app failed to enable notifications for the subscription") - case (.disableNotification, true): - return NSLocalizedString("In-app notifications disabled", comment: "The app successfully disabled notifications for the subscription") - case (.disableNotification, false): - return NSLocalizedString("Could not disable notifications", comment: "The app failed to disable notifications for the subscription") - } - } - // MARK: - Tracks func trackFollowToggled() { @@ -212,9 +192,9 @@ private extension ReaderCommentsFollowPresenter { WPAnalytics.trackReader(.readerToggleFollowConversation, properties: properties) } - func trackNotificationsToggled() { + func trackNotificationsToggled(isNotificationEnabled: Bool) { var properties = [String: Any]() - properties[AnalyticsKeys.notificationsEnabled] = !post.receivesCommentNotifications + properties[AnalyticsKeys.notificationsEnabled] = isNotificationEnabled properties[WPAppAnalyticsKeyBlogID] = post.siteID properties[WPAppAnalyticsKeySource] = sourceForTracks() WPAnalytics.trackReader(.readerToggleCommentNotifications, properties: properties) diff --git a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsNotificationSheetViewController.swift b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsNotificationSheetViewController.swift index b3eb39742dda..dccb6db733f3 100644 --- a/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsNotificationSheetViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Comments/ReaderCommentsNotificationSheetViewController.swift @@ -299,6 +299,6 @@ private extension String { + "notifications in Reader Comments.") static let notificationSwitchLabelText = NSLocalizedString("Enable in-app notifications", comment: "Describes a switch component that toggles in-app notifications for a followed post.") - static let unfollowButtonTitle = NSLocalizedString("Unfollow conversation", + static let unfollowButtonTitle = NSLocalizedString("Unfollow Conversation", comment: "Title for a button that unsubscribes the user from the post.") } diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift index 7b72748dbf23..744c47243607 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailCoordinator.swift @@ -100,6 +100,8 @@ class ReaderDetailCoordinator { return URL(string: postURLString) } + private var followCommentsService: FollowCommentsService? + /// The total number of Likes for the post. /// Passed to ReaderDetailLikesListController to display in the view title. private var totalLikes = 0 @@ -408,17 +410,23 @@ class ReaderDetailCoordinator { /// private func showMenu(_ anchorView: UIView) { guard let post = post, - let context = post.managedObjectContext, - let viewController = viewController else { + let context = post.managedObjectContext, + let viewController = viewController, + let followCommentsService = FollowCommentsService(post: post) else { return } - ReaderMenuAction(logged: ReaderHelpers.isLoggedIn()).execute(post: post, - context: context, - readerTopic: readerTopic, - anchor: anchorView, - vc: viewController, - source: ReaderPostMenuSource.details) + self.followCommentsService = followCommentsService + + ReaderMenuAction(logged: ReaderHelpers.isLoggedIn()).execute( + post: post, + context: context, + readerTopic: readerTopic, + anchor: anchorView, + vc: viewController, + source: ReaderPostMenuSource.details, + followCommentsService: followCommentsService + ) WPAnalytics.trackReader(.readerArticleDetailMoreTapped) } diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift index 71ea94e25471..1930176eb1c5 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/ReaderDetailViewController.swift @@ -396,7 +396,7 @@ class ReaderDetailViewController: UIViewController, ReaderDetailView { commentsTableView.reloadData() } - private func updateFollowButtonState() { + func updateFollowButtonState() { guard let post = post else { return } diff --git a/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailLikesView.swift b/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailLikesView.swift index fdc13c9097d9..6e220b113af7 100644 --- a/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailLikesView.swift +++ b/WordPress/Classes/ViewRelated/Reader/Detail/Views/ReaderDetailLikesView.swift @@ -98,11 +98,11 @@ private extension ReaderDetailLikesView { case (true, 0): summaryLabel.attributedText = highlightedText(SummaryLabelFormats.onlySelf) case (true, 1): - summaryLabel.attributedText = highlightedText(String(format: SummaryLabelFormats.singularWithSelf)) + summaryLabel.attributedText = highlightedText(SummaryLabelFormats.singularWithSelf) case (true, _) where totalLikes > 1: summaryLabel.attributedText = highlightedText(String(format: SummaryLabelFormats.pluralWithSelf, totalLikes)) case (false, 1): - summaryLabel.attributedText = highlightedText(String(format: SummaryLabelFormats.singular)) + summaryLabel.attributedText = highlightedText(SummaryLabelFormats.singular) default: summaryLabel.attributedText = highlightedText(String(format: SummaryLabelFormats.plural, totalLikes)) } diff --git a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift index a4661a609dba..c15871f9f6b7 100644 --- a/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift +++ b/WordPress/Classes/ViewRelated/Reader/Manage/ReaderManageScenePresenter.swift @@ -53,6 +53,7 @@ class ReaderManageScenePresenter: ScenePresenter { presentedViewController = navigationController viewController.present(navigationController, animated: true, completion: nil) + QuickStartTourGuide.shared.visited(.readerDiscoverSettings) WPAnalytics.track(.readerManageViewDisplayed) } } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift index 73b4899673ed..1fe201110cea 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderHelpers.swift @@ -49,8 +49,8 @@ struct ReaderPostMenuButtonTitles { static let unsubscribe = NSLocalizedString("Turn off site notifications", comment: "Verb. An option to switch off site notifications.") static let markSeen = NSLocalizedString("Mark as seen", comment: "An option to mark a post as seen.") static let markUnseen = NSLocalizedString("Mark as unseen", comment: "An option to mark a post as unseen.") - static let followConversation = NSLocalizedString("Follow conversation by email", comment: "Verb. Button title. Follow the comments on a post.") - static let unFollowConversation = NSLocalizedString("Unfollow conversation by email", comment: "Verb. Button title. The user is following the comments on a post.") + static let followConversation = NSLocalizedString("Follow conversation", comment: "Verb. Button title. Follow the comments on a post.") + static let unFollowConversation = NSLocalizedString("Unfollow conversation", comment: "Verb. Button title. The user is following the comments on a post.") } /// A collection of helper methods used by the Reader. @@ -347,14 +347,32 @@ struct ReaderPostMenuButtonTitles { dispatchToggleFollowSiteMessage(siteTitle: site.title, siteID: site.siteID, follow: follow, success: success) } - class func dispatchToggleSubscribeCommentMessage(subscribing: Bool, success: Bool) { + class func dispatchToggleSubscribeCommentMessage(subscribing: Bool, success: Bool, actionHandler: ((Bool) -> Void)?) { let title: String + let message: String? + let actionTitle: String? if success { title = subscribing ? NoticeMessages.commentFollowSuccess : NoticeMessages.commentUnfollowSuccess + message = subscribing ? NoticeMessages.commentFollowSuccessMessage : nil + actionTitle = subscribing ? NoticeMessages.commentFollowActionTitle : nil } else { title = subscribing ? NoticeMessages.commentFollowFail : NoticeMessages.commentUnfollowFail + message = nil + actionTitle = nil } - dispatchNotice(Notice(title: title)) + dispatchNotice( + Notice( + title: title, + message: message, + actionTitle: actionTitle, + actionHandler: actionHandler + ) + ) + } + + class func dispatchToggleCommentNotificationMessage(subscribing: Bool, success: Bool) { + let action: ReaderHelpers.PostSubscriptionAction = subscribing ? .enableNotification : .disableNotification + dispatchNotice(Notice(title: noticeTitle(forAction: action, success: success))) } class func dispatchToggleSubscribeCommentErrorMessage(subscribing: Bool) { @@ -398,6 +416,28 @@ struct ReaderPostMenuButtonTitles { dispatchNotice(notice) } + /// Enumerates the kind of actions available in relation to post subscriptions. + /// TODO: Add `followConversation` and `unfollowConversation` once the "Follow Conversation" feature flag is removed. + enum PostSubscriptionAction: Int { + case enableNotification + case disableNotification + } + + class func noticeTitle(forAction action: PostSubscriptionAction, success: Bool) -> String { + switch (action, success) { + case (.enableNotification, true): + return NSLocalizedString("In-app notifications enabled", comment: "The app successfully enabled notifications for the subscription") + case (.enableNotification, false): + return NSLocalizedString("Could not enable notifications", comment: "The app failed to enable notifications for the subscription") + case (.disableNotification, true): + return NSLocalizedString("In-app notifications disabled", comment: "The app successfully disabled notifications for the subscription") + case (.disableNotification, false): + return NSLocalizedString("Could not disable notifications", comment: "The app failed to disable notifications for the subscription") + } + } + + + private class func dispatchNotice(_ notice: Notice) { ActionDispatcher.dispatch(NoticeAction.post(notice)) } @@ -432,7 +472,9 @@ struct ReaderPostMenuButtonTitles { static let enableButtonLabel = NSLocalizedString("Enable", comment: "Button title for the enable site notifications action.") static let blockSiteSuccess = NSLocalizedString("Blocked site", comment: "Notice title when blocking a site succeeds.") static let blockSiteFail = NSLocalizedString("Unable to block site", comment: "Notice title when blocking a site fails.") - static let commentFollowSuccess = NSLocalizedString("Successfully followed conversation", comment: "The app successfully subscribed to the comments for the post") + static let commentFollowSuccess = NSLocalizedString("Following this conversation", comment: "The app successfully subscribed to the comments for the post") + static let commentFollowSuccessMessage = NSLocalizedString("You'll get notifications in the app", comment: "The app successfully subscribed to the comments for the post") + static let commentFollowActionTitle = NSLocalizedString("Undo", comment: "Revert enabling notification after successfully subcribing to the comments for the post.") static let commentUnfollowSuccess = NSLocalizedString("Successfully unfollowed conversation", comment: "The app successfully unsubscribed from the comments for the post") static let commentFollowFail = NSLocalizedString("Unable to follow conversation", comment: "The app failed to subscribe to the comments for the post") static let commentUnfollowFail = NSLocalizedString("Failed to unfollow conversation", comment: "The app failed to unsubscribe from the comments for the post") diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift b/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift index 1fd52519abee..b9256c08e5e8 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderMenuAction.swift @@ -10,16 +10,21 @@ final class ReaderMenuAction { readerTopic: ReaderAbstractTopic? = nil, anchor: UIView, vc: UIViewController, - source: ReaderPostMenuSource) { + source: ReaderPostMenuSource, + followCommentsService: FollowCommentsService + ) { let service: ReaderTopicService = ReaderTopicService(managedObjectContext: context) let siteTopic: ReaderSiteTopic? = post.isFollowing ? service.findSiteTopic(withSiteID: post.siteID) : nil - ReaderShowMenuAction(loggedIn: isLoggedIn).execute(with: post, - context: context, - siteTopic: siteTopic, - readerTopic: readerTopic, - anchor: anchor, - vc: vc, - source: source) + ReaderShowMenuAction(loggedIn: isLoggedIn).execute( + with: post, + context: context, + siteTopic: siteTopic, + readerTopic: readerTopic, + anchor: anchor, + vc: vc, + source: source, + followCommentsService: followCommentsService + ) } } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderPostCellActions.swift b/WordPress/Classes/ViewRelated/Reader/ReaderPostCellActions.swift index 4803f2f58ece..368a99bde616 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderPostCellActions.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderPostCellActions.swift @@ -3,6 +3,7 @@ class ReaderPostCellActions: NSObject, ReaderPostCellDelegate { private let context: NSManagedObjectContext private weak var origin: UIViewController? private let topic: ReaderAbstractTopic? + private var followCommentsService: FollowCommentsService? var imageRequestAuthToken: String? = nil var isLoggedIn: Bool = false @@ -88,11 +89,23 @@ class ReaderPostCellActions: NSObject, ReaderPostCellDelegate { } func readerCell(_ cell: ReaderPostCardCell, menuActionForProvider provider: ReaderPostContentProvider, fromView sender: UIView) { - guard let post = provider as? ReaderPost, let origin = origin else { + guard let post = provider as? ReaderPost, + let origin = origin, + let followCommentsService = FollowCommentsService(post: post) else { return } - ReaderMenuAction(logged: isLoggedIn).execute(post: post, context: context, readerTopic: topic, anchor: sender, vc: origin, source: ReaderPostMenuSource.card) + self.followCommentsService = followCommentsService + + ReaderMenuAction(logged: isLoggedIn).execute( + post: post, + context: context, + readerTopic: topic, + anchor: sender, + vc: origin, + source: ReaderPostMenuSource.card, + followCommentsService: followCommentsService + ) WPAnalytics.trackReader(.postCardMoreTapped) } @@ -118,10 +131,10 @@ class ReaderPostCellActions: NSObject, ReaderPostCellDelegate { ReaderFollowAction().execute(with: post, context: context, completion: { follow in - ReaderHelpers.dispatchToggleFollowSiteMessage(post: post, follow: follow, success: true) - }, failure: { follow, _ in - ReaderHelpers.dispatchToggleFollowSiteMessage(post: post, follow: follow, success: false) - }) + ReaderHelpers.dispatchToggleFollowSiteMessage(post: post, follow: follow, success: true) + }, failure: { follow, _ in + ReaderHelpers.dispatchToggleFollowSiteMessage(post: post, follow: follow, success: false) + }) } func toggleSavedForLater(for post: ReaderPost) { diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift b/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift index d3752185a36c..d6261b5da785 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderShowMenuAction.swift @@ -1,3 +1,4 @@ +import UIKit /// Encapsulates a command to create and handle the extended menu for each post in Reader final class ReaderShowMenuAction { private let isLoggedIn: Bool @@ -12,7 +13,9 @@ final class ReaderShowMenuAction { readerTopic: ReaderAbstractTopic? = nil, anchor: UIView, vc: UIViewController, - source: ReaderPostMenuSource) { + source: ReaderPostMenuSource, + followCommentsService: FollowCommentsService + ) { // Create the action sheet let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) @@ -129,16 +132,25 @@ final class ReaderShowMenuAction { ReaderShareAction().execute(with: post, context: context, anchor: anchor, vc: vc) }) - // Comment Subscription (Follow Comments by Email) + // Comment Subscription (Follow Comments by Email & Notifications) if post.canSubscribeComments { let buttonTitle = post.isSubscribedComments ? ReaderPostMenuButtonTitles.unFollowConversation : ReaderPostMenuButtonTitles.followConversation - alertController.addActionWithTitle(buttonTitle, - style: .default, - handler: { (action: UIAlertAction) in - if let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) { - ReaderSubscribeCommentsAction().execute(with: post, context: context) - } - }) + alertController.addActionWithTitle( + buttonTitle, + style: .default, + handler: { (action: UIAlertAction) in + if let post: ReaderPost = ReaderActionHelpers.existingObject(for: post.objectID, in: context) { + Self.trackToggleCommentSubscription(isSubscribed: post.isSubscribedComments, post: post, sourceViewController: vc) + + ReaderSubscribeCommentsAction().execute( + with: post, + context: context, + followCommentsService: followCommentsService, + sourceViewController: vc) { + (vc as? ReaderDetailViewController)?.updateFollowButtonState() + } + } + }) } if WPDeviceIdentification.isiPad() { @@ -170,4 +182,22 @@ final class ReaderShowMenuAction { return shouldShowBlockSiteMenuItem(readerTopic: readerTopic, post: post) } + private static func trackToggleCommentSubscription(isSubscribed: Bool, post: ReaderPost, sourceViewController: UIViewController) { + var properties = [String: Any]() + properties[WPAppAnalyticsKeyFollowAction] = isSubscribed ? "followed" : "unfollowed" + properties["notifications_enabled"] = isSubscribed + properties[WPAppAnalyticsKeyBlogID] = post.siteID + properties[WPAppAnalyticsKeySource] = Self.sourceForTrackingEvents(sourceViewController: sourceViewController) + WPAnalytics.trackReader(.readerMoreToggleFollowConversation, properties: properties) + } + + private static func sourceForTrackingEvents(sourceViewController: UIViewController) -> String { + if sourceViewController is ReaderDetailViewController { + return "reader_post_details_comments" + } else if sourceViewController is ReaderStreamViewController { + return "reader" + } + + return "unknown" + } } diff --git a/WordPress/Classes/ViewRelated/Reader/ReaderSubscribeCommentsAction.swift b/WordPress/Classes/ViewRelated/Reader/ReaderSubscribeCommentsAction.swift index dc1285c7c560..7fd4486454b2 100644 --- a/WordPress/Classes/ViewRelated/Reader/ReaderSubscribeCommentsAction.swift +++ b/WordPress/Classes/ViewRelated/Reader/ReaderSubscribeCommentsAction.swift @@ -2,16 +2,56 @@ final class ReaderSubscribeCommentsAction { func execute(with post: ReaderPost, context: NSManagedObjectContext, + followCommentsService: FollowCommentsService, + sourceViewController: UIViewController, completion: (() -> Void)? = nil, failure: ((Error?) -> Void)? = nil) { let subscribing = !post.isSubscribedComments - let service = FollowCommentsService(post: post) - service?.toggleSubscribed(post.isSubscribedComments, success: { success in - ReaderHelpers.dispatchToggleSubscribeCommentMessage(subscribing: subscribing, success: success) + + followCommentsService.toggleSubscribed(post.isSubscribedComments, success: { subscribeSuccess in + followCommentsService.toggleNotificationSettings(subscribing, success: { + ReaderHelpers.dispatchToggleSubscribeCommentMessage(subscribing: subscribing, success: subscribeSuccess) { actionSuccess in + self.disableNotificationSettings(followCommentsService: followCommentsService) + Self.trackNotificationUndo(post: post, sourceViewController: sourceViewController) + } + completion?() + }, failure: { error in + DDLogError("Error toggling comment notification status: \(error.debugDescription)") + ReaderHelpers.dispatchToggleCommentNotificationMessage(subscribing: false, success: false) + failure?(error) + }) }, failure: { error in DDLogError("Error toggling comment subscription status: \(error.debugDescription)") ReaderHelpers.dispatchToggleSubscribeCommentErrorMessage(subscribing: subscribing) + failure?(error) + }) + } + + private func disableNotificationSettings(followCommentsService: FollowCommentsService) { + followCommentsService.toggleNotificationSettings(false, success: { + ReaderHelpers.dispatchToggleCommentNotificationMessage(subscribing: false, success: true) + }, failure: { error in + DDLogError("Error toggling comment notification status: \(error.debugDescription)") + ReaderHelpers.dispatchToggleCommentNotificationMessage(subscribing: false, success: false) }) } + + private static func trackNotificationUndo(post: ReaderPost, sourceViewController: UIViewController) { + var properties = [String: Any]() + properties["notifications_enabled"] = false + properties[WPAppAnalyticsKeyBlogID] = post.siteID + properties[WPAppAnalyticsKeySource] = sourceForTrackingEvents(sourceViewController: sourceViewController) + WPAnalytics.trackReader(.readerToggleCommentNotifications, properties: properties) + } + + private static func sourceForTrackingEvents(sourceViewController: UIViewController) -> String { + if sourceViewController is ReaderDetailViewController { + return "reader_post_details_menu" + } else if sourceViewController is ReaderStreamViewController { + return "reader" + } + + return "unknown" + } } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift index 41b2b2dda557..81e72009ffe6 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/ReaderTabViewController.swift @@ -11,7 +11,7 @@ class ReaderTabViewController: UIViewController { return makeReaderTabView(viewModel) }() - private let searchButton: SpotlightableButton = SpotlightableButton(type: .custom) + private let settingsButton: SpotlightableButton = SpotlightableButton(type: .custom) init(viewModel: ReaderTabViewModel, readerTabViewFactory: @escaping (ReaderTabViewModel) -> ReaderTabView) { self.viewModel = viewModel @@ -61,7 +61,16 @@ class ReaderTabViewController: UIViewController { } override func viewWillAppear(_ animated: Bool) { - searchButton.shouldShowSpotlight = QuickStartTourGuide.shared.isCurrentElement(.readerSearch) + super.viewWillAppear(animated) + + if QuickStartTourGuide.shared.isCurrentElement(.readerDiscoverSettings) { + + if viewModel.selectedIndex != ReaderTabConstants.discoverIndex { + viewModel.showTab(at: ReaderTabConstants.discoverIndex) + } + + settingsButton.shouldShowSpotlight = true + } } override func viewWillDisappear(_ animated: Bool) { @@ -71,22 +80,21 @@ class ReaderTabViewController: UIViewController { } func setupNavigationButtons() { - // Settings Button - let settingsButton = UIBarButtonItem(image: UIImage.gridicon(.cog), - style: .plain, - target: self, - action: #selector(didTapSettingsButton)) - settingsButton.accessibilityIdentifier = ReaderTabConstants.settingsButtonIdentifier - // Search Button - searchButton.spotlightOffset = UIOffset(horizontal: 20, vertical: -10) - searchButton.setImage(.gridicon(.search), for: .normal) - searchButton.addTarget(self, action: #selector(didTapSearchButton), for: .touchUpInside) + let searchButton = UIBarButtonItem(image: UIImage.gridicon(.search), + style: .plain, + target: self, + action: #selector(didTapSearchButton)) searchButton.accessibilityIdentifier = ReaderTabConstants.searchButtonAccessibilityIdentifier - let searchBarButton = UIBarButtonItem(customView: searchButton) + // Settings Button + settingsButton.spotlightOffset = ReaderTabConstants.spotlightOffset + settingsButton.setImage(.gridicon(.cog), for: .normal) + settingsButton.addTarget(self, action: #selector(didTapSettingsButton), for: .touchUpInside) + settingsButton.accessibilityIdentifier = ReaderTabConstants.settingsButtonIdentifier + let settingsButton = UIBarButtonItem(customView: settingsButton) - navigationItem.rightBarButtonItems = [searchBarButton, settingsButton] + navigationItem.rightBarButtonItems = [searchButton, settingsButton] } override func loadView() { @@ -115,6 +123,7 @@ class ReaderTabViewController: UIViewController { // MARK: - Navigation Buttons extension ReaderTabViewController { @objc private func didTapSettingsButton() { + settingsButton.shouldShowSpotlight = false viewModel.presentManage(from: self) } @@ -172,5 +181,6 @@ extension ReaderTabViewController { static let restorationIdentifier = "WPReaderTabControllerRestorationID" static let encodedIndexKey = "WPReaderTabControllerIndexRestorationKey" static let discoverIndex = 1 + static let spotlightOffset = UIOffset(horizontal: 20, vertical: -10) } } diff --git a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift index a6a92223ec46..1f18fb510b4e 100644 --- a/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift +++ b/WordPress/Classes/ViewRelated/Reader/Tab Navigation/WPTabBarController+ReaderTabNavigation.swift @@ -64,7 +64,6 @@ extension WPTabBarController { func navigateToReaderSearch() { let searchController = ReaderSearchViewController.controller() navigateToReader(searchController) - QuickStartTourGuide.shared.visited(.readerSearch) } func navigateToReaderSite(_ topic: ReaderSiteTopic) { diff --git a/WordPress/Classes/ViewRelated/Site Creation/Site Name/SiteNameView.swift b/WordPress/Classes/ViewRelated/Site Creation/Site Name/SiteNameView.swift index 85375f6e2bc3..0beef075296c 100644 --- a/WordPress/Classes/ViewRelated/Site Creation/Site Name/SiteNameView.swift +++ b/WordPress/Classes/ViewRelated/Site Creation/Site Name/SiteNameView.swift @@ -24,6 +24,8 @@ class SiteNameView: UIView { label.adjustsFontForContentSizeCategory = true label.numberOfLines = Metrics.numberOfLinesInTitle label.textAlignment = .center + label.adjustsFontSizeToFitWidth = true + label.minimumScaleFactor = Metrics.titleMinimumScaleFactor return label }() @@ -235,10 +237,22 @@ private extension SiteNameView { /// hides or shows titles based on the passed boolean parameter func hideTitlesIfNeeded() { - let isAccessibility = traitCollection.verticalSizeClass == .compact || traitCollection.preferredContentSizeCategory.isAccessibilityCategory - let isVerylarge = [UIContentSizeCategory.extraExtraLarge, UIContentSizeCategory.extraExtraExtraLarge].contains(traitCollection.preferredContentSizeCategory) + let isAccessibility = traitCollection.verticalSizeClass == .compact || + traitCollection.preferredContentSizeCategory.isAccessibilityCategory + + let isVerylarge = [ + UIContentSizeCategory.extraExtraLarge, + UIContentSizeCategory.extraExtraExtraLarge + ].contains(traitCollection.preferredContentSizeCategory) + titleLabelView.isHidden = isAccessibility - subtitleLabelView.isHidden = isAccessibility || isVerylarge + + subtitleLabelView.isHidden = isAccessibility || isVerylarge || isIphoneSEorSmaller + } + + var isIphoneSEorSmaller: Bool { + UIScreen.main.nativeBounds.height <= Metrics.smallerIphonesNativeBoundsHeight && + UIScreen.main.nativeScale <= Metrics.nativeScale } } @@ -264,9 +278,11 @@ private extension SiteNameView { // search bar static let searchbarHeight: CGFloat = 64 // title and subtitle - static let numberOfLinesInTitle = 0 + static let numberOfLinesInTitle = 3 static let numberOfLinesInSubtitle = 0 static let titlesInsets = UIEdgeInsets(top: 0, left: 16, bottom: 0, right: 16) + static let verticalNameDisplayLimit = 32 + static let titleMinimumScaleFactor: CGFloat = 0.75 //continue button static let continueButtonStandardPadding: CGFloat = 16 static let continueButtonAdditionaliPadPadding: CGFloat = 8 @@ -274,8 +290,10 @@ private extension SiteNameView { static func continueButtonViewFrame(_ accessoryWidth: CGFloat) -> CGRect { CGRect(x: 0, y: 0, width: accessoryWidth, height: 76) } + // native bounds height and scale of iPhone SE 3rd gen and iPhone 8 + static let smallerIphonesNativeBoundsHeight: CGFloat = 1334 + static let nativeScale: CGFloat = 2 } - } // MARK: search bar delegate diff --git a/WordPress/Classes/ViewRelated/Stats/Insights/Latest Post Summary/LatestPostSummaryCell.swift b/WordPress/Classes/ViewRelated/Stats/Insights/Latest Post Summary/LatestPostSummaryCell.swift index f0782243097b..0c6dd4e3ba8f 100644 --- a/WordPress/Classes/ViewRelated/Stats/Insights/Latest Post Summary/LatestPostSummaryCell.swift +++ b/WordPress/Classes/ViewRelated/Stats/Insights/Latest Post Summary/LatestPostSummaryCell.swift @@ -1,7 +1,11 @@ import UIKit import Gridicons -class LatestPostSummaryCell: StatsBaseCell, NibLoadable, Accessible { +protocol LatestPostSummaryConfigurable { + func configure(withInsightData lastPostInsight: StatsLastPostInsight?, chartData: StatsPostDetails?, andDelegate delegate: SiteStatsInsightsDelegate?) +} + +class LatestPostSummaryCell: StatsBaseCell, LatestPostSummaryConfigurable, NibLoadable, Accessible { // MARK: - Properties diff --git a/WordPress/Classes/ViewRelated/Stats/Insights/StatsLatestPostSummaryInsightsCell.swift b/WordPress/Classes/ViewRelated/Stats/Insights/StatsLatestPostSummaryInsightsCell.swift new file mode 100644 index 000000000000..a2d5a879228e --- /dev/null +++ b/WordPress/Classes/ViewRelated/Stats/Insights/StatsLatestPostSummaryInsightsCell.swift @@ -0,0 +1,269 @@ +import UIKit +import Gridicons + + +class StatsLatestPostSummaryInsightsCell: StatsBaseCell, LatestPostSummaryConfigurable { + private weak var siteStatsInsightsDelegate: SiteStatsInsightsDelegate? + private typealias Style = WPStyleGuide.Stats + private var lastPostInsight: StatsLastPostInsight? + private var lastPostDetails: StatsPostDetails? + private var postTitle = StatSection.noPostTitle + + private let outerStackView = UIStackView() + private let postStackView = UIStackView() + private let statsStackView = UIStackView() + private let postTitleLabel = UILabel() + private let postTimestampLabel = UILabel() + private let viewCountLabel = UILabel() + private let likeCountLabel = UILabel() + private let commentCountLabel = UILabel() + private let postImageView = CachedAnimatedImageView() + + private let noDataLabel = UILabel() + private let createPostButton = UIButton(type: .system) + + lazy var imageLoader: ImageLoader = { + return ImageLoader(imageView: postImageView, gifStrategy: .mediumGIFs) + }() + + // MARK: - Initialization + + required override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + + configureView() + } + + required init(coder: NSCoder) { + fatalError() + } + + override func prepareForReuse() { + super.prepareForReuse() + + toggleNoData(show: false) + } + + // MARK: - View Configuration + + private func configureView() { + configureOuterStackView() + contentView.addSubview(outerStackView) + + configurePostStackView() + configureStatsStackView() + outerStackView.addArrangedSubview(postStackView) + outerStackView.addArrangedSubview(statsStackView) + + topConstraint = outerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: StatsBaseCell.Metrics.padding) + + NSLayoutConstraint.activate([ + topConstraint, + outerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -StatsBaseCell.Metrics.padding), + outerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: StatsBaseCell.Metrics.padding), + outerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -StatsBaseCell.Metrics.padding), + ]) + + configureNoDataViews() + } + + private func configureOuterStackView() { + outerStackView.translatesAutoresizingMaskIntoConstraints = false + outerStackView.axis = .vertical + outerStackView.spacing = Metrics.outerStackViewSpacing + } + + private func configurePostStackView() { + postStackView.translatesAutoresizingMaskIntoConstraints = false + postStackView.axis = .horizontal + postStackView.alignment = .top + postStackView.spacing = Metrics.postStackViewHorizontalSpacing + + let postInfoStackView = UIStackView() + postInfoStackView.translatesAutoresizingMaskIntoConstraints = false + postInfoStackView.axis = .vertical + postInfoStackView.spacing = Metrics.postStackViewVerticalSpacing + + postTitleLabel.textColor = .text + postTitleLabel.numberOfLines = 2 + postTitleLabel.font = .preferredFont(forTextStyle: .headline) + + postTimestampLabel.textColor = .textSubtle + postTimestampLabel.font = .preferredFont(forTextStyle: .subheadline) + + postInfoStackView.addArrangedSubviews([postTitleLabel, postTimestampLabel]) + + postImageView.contentMode = .scaleAspectFill + postImageView.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + postImageView.widthAnchor.constraint(equalToConstant: Metrics.thumbnailSize), + postImageView.heightAnchor.constraint(equalTo: postImageView.widthAnchor) + ]) + + postImageView.layer.cornerRadius = Metrics.thumbnailCornerRadius + postImageView.layer.masksToBounds = true + + postStackView.addArrangedSubviews([postInfoStackView, postImageView]) + } + + private func configureStatsStackView() { + statsStackView.translatesAutoresizingMaskIntoConstraints = false + statsStackView.axis = .horizontal + statsStackView.alignment = .top + statsStackView.spacing = Metrics.postStackViewHorizontalSpacing + + let viewsStack = makeVerticalStatsStackView(with: viewCountLabel, title: TextContent.views) + let likesStack = makeVerticalStatsStackView(with: likeCountLabel, title: TextContent.likes) + let commentsStack = makeVerticalStatsStackView(with: commentCountLabel, title: TextContent.comments) + + let divider1 = makeVerticalDivider() + let divider2 = makeVerticalDivider() + + statsStackView.addArrangedSubviews([ + viewsStack, + divider1, + likesStack, + divider2, + commentsStack + ]) + + NSLayoutConstraint.activate([ + viewsStack.widthAnchor.constraint(equalTo: likesStack.widthAnchor), + likesStack.widthAnchor.constraint(equalTo: commentsStack.widthAnchor), + divider1.heightAnchor.constraint(equalTo: statsStackView.heightAnchor), + divider2.heightAnchor.constraint(equalTo: statsStackView.heightAnchor) + ]) + } + + private func makeVerticalStatsStackView(with countLabel: UILabel, title: String) -> UIStackView { + let stackView = UIStackView() + stackView.translatesAutoresizingMaskIntoConstraints = false + stackView.axis = .vertical + stackView.spacing = Metrics.statsStackViewVerticalSpacing + + let topLabel = UILabel() + topLabel.font = UIFont.preferredFont(forTextStyle: .subheadline) + topLabel.textColor = .text + topLabel.text = title + + countLabel.font = UIFont.preferredFont(forTextStyle: .title1).bold() + countLabel.textColor = .text + countLabel.adjustsFontSizeToFitWidth = true + countLabel.text = "0" + + stackView.addArrangedSubviews([topLabel, countLabel]) + + return stackView + } + + private func makeVerticalDivider() -> UIView { + let divider = UIView() + divider.translatesAutoresizingMaskIntoConstraints = false + divider.widthAnchor.constraint(equalToConstant: Metrics.dividerWidth).isActive = true + + WPStyleGuide.Stats.configureViewAsVerticalSeparator(divider) + + return divider + } + + private func configureNoDataViews() { + noDataLabel.font = .preferredFont(forTextStyle: .body) + noDataLabel.textColor = .textSubtle + noDataLabel.numberOfLines = 0 + noDataLabel.text = TextContent.noData + + createPostButton.setImage(.gridicon(.create), for: .normal) + createPostButton.setTitle(TextContent.createPost, for: .normal) + + // Increase the padding between the image and title of the button + createPostButton.titleEdgeInsets = UIEdgeInsets(top: 0, left: Metrics.createPostButtonInset, bottom: 0, right: -Metrics.createPostButtonInset) + createPostButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: Metrics.createPostButtonInset) + + createPostButton.addTarget(self, action: #selector(createPostTapped), for: .touchUpInside) + } + + // MARK: - Public Configuration + + func configure(withInsightData lastPostInsight: StatsLastPostInsight?, chartData: StatsPostDetails?, andDelegate delegate: SiteStatsInsightsDelegate?) { + siteStatsInsightsDelegate = delegate + statSection = .insightsLatestPostSummary + + guard let lastPostInsight = lastPostInsight else { + toggleNoData(show: true) + return + } + + postTitleLabel.text = lastPostInsight.title + + let formatter = RelativeDateTimeFormatter() + let date = formatter.localizedString(for: lastPostInsight.publishedDate, relativeTo: Date()) + postTimestampLabel.text = String(format: TextContent.publishDate, date) + + configureFeaturedImage(url: lastPostInsight.featuredImageURL) + + viewCountLabel.text = lastPostInsight.viewsCount.abbreviatedString() + likeCountLabel.text = lastPostInsight.likesCount.abbreviatedString() + commentCountLabel.text = lastPostInsight.commentsCount.abbreviatedString() + } + + // Switches out the no data views into the main stack view if we have no data. + // + private func toggleNoData(show: Bool) { + if !show && outerStackView.subviews.contains(noDataLabel) { + noDataLabel.removeFromSuperview() + createPostButton.removeFromSuperview() + outerStackView.addArrangedSubviews([postStackView, statsStackView]) + outerStackView.alignment = .fill + } else if show && outerStackView.subviews.contains(postStackView) { + postStackView.removeFromSuperview() + statsStackView.removeFromSuperview() + outerStackView.addArrangedSubviews([noDataLabel, createPostButton]) + outerStackView.alignment = .leading + } + } + + private func configureFeaturedImage(url: URL?) { + if let url = url, + let siteID = SiteStatsInformation.sharedInstance.siteID?.intValue, + let blog = try? Blog.lookup(withID: siteID, in: ContextManager.shared.mainContext) { + postImageView.isHidden = false + + let host = MediaHost(with: blog, failure: { error in + DDLogError("Failed to create media host: \(error.localizedDescription)") + }) + + imageLoader.loadImage(with: url, from: host, preferredSize: CGSize(width: Metrics.thumbnailSize, height: Metrics.thumbnailSize)) + } else { + postImageView.isHidden = true + } + } + + // MARK: - Actions + + @objc func createPostTapped() { + siteStatsInsightsDelegate?.showCreatePost?() + } + + // MARK: - Constants + + private enum Metrics { + static let outerStackViewSpacing: CGFloat = 16.0 + static let postStackViewHorizontalSpacing: CGFloat = 16.0 + static let postStackViewVerticalSpacing: CGFloat = 8.0 + static let statsStackViewVerticalSpacing: CGFloat = 8.0 + static let createPostButtonInset: CGFloat = 8.0 + static let thumbnailSize: CGFloat = 68.0 + static let thumbnailCornerRadius: CGFloat = 4.0 + static let dividerWidth: CGFloat = 1.0 + } + + private enum TextContent { + static let noData = NSLocalizedString("stats.insights.latestPostSummary.noData", value: "You haven't published any posts yet. Check back later once you've published your first post!", comment: "Prompt shown in the 'Latest Post Summary' stats card if a user hasn't yet published anything.") + static let createPost = NSLocalizedString("stats.insights.latestPostSummary.createPost", value: "Create Post", comment: "Title of button shown in Stats prompting the user to create a post on their site.") + static let publishDate = NSLocalizedString("stats.insights.latestPostSummary.publishDate", value: "Published %@", comment: "Publish date of a post displayed in Stats. Placeholder will be replaced with a localized relative time, e.g. 2 days ago") + static let views = NSLocalizedString("stats.insights.latestPostSummary.views", value: "Views", comment: "Title for Views count in Latest Post Summary stats card.") + static let likes = NSLocalizedString("stats.insights.latestPostSummary.likes", value: "Likes", comment: "Title for Likes count in Latest Post Summary stats card.") + static let comments = NSLocalizedString("stats.insights.latestPostSummary.comments", value: "Comments", comment: "Title for Comments count in Latest Post Summary stats card.") + } +} diff --git a/WordPress/Classes/ViewRelated/Stats/Insights/StatsMostPopularTimeInsightsCell.swift b/WordPress/Classes/ViewRelated/Stats/Insights/StatsMostPopularTimeInsightsCell.swift index 058ff6cf4735..5699accc0d99 100644 --- a/WordPress/Classes/ViewRelated/Stats/Insights/StatsMostPopularTimeInsightsCell.swift +++ b/WordPress/Classes/ViewRelated/Stats/Insights/StatsMostPopularTimeInsightsCell.swift @@ -7,6 +7,10 @@ class StatsMostPopularTimeInsightsCell: StatsBaseCell { // MARK: - Subviews + private var outerStackView: UIStackView! + + private var noDataLabel: UILabel! + private var topLeftLabel: UILabel! private var middleLeftLabel: UILabel! private var bottomLeftLabel: UILabel! @@ -27,20 +31,31 @@ class StatsMostPopularTimeInsightsCell: StatsBaseCell { fatalError() } + override func prepareForReuse() { + super.prepareForReuse() + + displayNoData(show: false) + } + // MARK: - View Configuration private func configureView() { - let stackView = makeOuterStackView() - contentView.addSubview(stackView) + outerStackView = makeOuterStackView() + contentView.addSubview(outerStackView) - topConstraint = stackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: StatsBaseCell.Metrics.padding) + topConstraint = outerStackView.topAnchor.constraint(equalTo: contentView.topAnchor, constant: StatsBaseCell.Metrics.padding) NSLayoutConstraint.activate([ topConstraint, - stackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -StatsBaseCell.Metrics.padding), - stackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: StatsBaseCell.Metrics.padding), - stackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -StatsBaseCell.Metrics.padding), + outerStackView.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -StatsBaseCell.Metrics.padding), + outerStackView.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: StatsBaseCell.Metrics.padding), + outerStackView.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -StatsBaseCell.Metrics.padding), ]) + + noDataLabel = makeNoDataLabel() + contentView.addSubview(noDataLabel) + outerStackView.pinSubviewToAllEdges(noDataLabel) + noDataLabel.isHidden = true } private func makeOuterStackView() -> UIStackView { @@ -112,6 +127,7 @@ class StatsMostPopularTimeInsightsCell: StatsBaseCell { let middleLabel = UILabel() middleLabel.textColor = .text middleLabel.font = .preferredFont(forTextStyle: .title1).bold() + middleLabel.adjustsFontSizeToFitWidth = true let bottomLabel = UILabel() bottomLabel.textColor = .textSubtle @@ -123,6 +139,22 @@ class StatsMostPopularTimeInsightsCell: StatsBaseCell { return (topLabel: topLabel, middleLabel: middleLabel, bottomLabel: bottomLabel) } + private func makeNoDataLabel() -> UILabel { + let label = UILabel() + label.translatesAutoresizingMaskIntoConstraints = false + label.font = .preferredFont(forTextStyle: .body) + label.textColor = .textSubtle + label.numberOfLines = 0 + label.text = TextContent.noData + + return label + } + + private func displayNoData(show: Bool) { + outerStackView.subviews.forEach({ $0.isHidden = show }) + noDataLabel.isHidden = !show + } + // MARK: Public configuration func configure(data: StatsMostPopularTimeData?, siteStatsInsightsDelegate: SiteStatsInsightsDelegate?) { @@ -130,22 +162,29 @@ class StatsMostPopularTimeInsightsCell: StatsBaseCell { self.statSection = .insightsMostPopularTime self.siteStatsInsightsDelegate = siteStatsInsightsDelegate - if let data = data { - topLeftLabel.text = data.mostPopularDayTitle - middleLeftLabel.text = data.mostPopularDay - bottomLeftLabel.text = data.dayPercentage - - topRightLabel.text = data.mostPopularTimeTitle - middleRightLabel.text = data.mostPopularTime - bottomRightLabel.text = data.timePercentage + guard let data = data else { + displayNoData(show: true) + return } + + topLeftLabel.text = data.mostPopularDayTitle + middleLeftLabel.text = data.mostPopularDay + bottomLeftLabel.text = data.dayPercentage + + topRightLabel.text = data.mostPopularTimeTitle + middleRightLabel.text = data.mostPopularTime + bottomRightLabel.text = data.timePercentage } private enum Metrics { - static let horizontalStackViewSpacing: CGFloat = 32.0 + static let horizontalStackViewSpacing: CGFloat = 16.0 static let verticalStackViewSpacing: CGFloat = 8.0 static let dividerWidth: CGFloat = 1.0 } + + private enum TextContent { + static let noData = NSLocalizedString("stats.insights.mostPopularTime.noData", value: "Not enough activity. Check back later when your site's had more visitors!", comment: "Hint displayed on the 'Most Popular Time' stats card when a user's site hasn't yet received enough traffic.") + } } // MARK: - Data / View Model diff --git a/WordPress/Classes/ViewRelated/Stats/SiteStatsTableViewCells.swift b/WordPress/Classes/ViewRelated/Stats/SiteStatsTableViewCells.swift index 5e2aa06ecddd..48d6e1b2cf0b 100644 --- a/WordPress/Classes/ViewRelated/Stats/SiteStatsTableViewCells.swift +++ b/WordPress/Classes/ViewRelated/Stats/SiteStatsTableViewCells.swift @@ -140,10 +140,12 @@ struct CustomizeInsightsRow: ImmuTableRow { struct LatestPostSummaryRow: ImmuTableRow { - typealias CellType = LatestPostSummaryCell - static let cell: ImmuTableCell = { - return ImmuTableCell.nib(CellType.defaultNib, CellType.self) + if FeatureFlag.statsNewInsights.enabled { + return ImmuTableCell.class(StatsLatestPostSummaryInsightsCell.self) + } else { + return ImmuTableCell.nib(LatestPostSummaryCell.defaultNib, LatestPostSummaryCell.self) + } }() let summaryData: StatsLastPostInsight? @@ -153,7 +155,7 @@ struct LatestPostSummaryRow: ImmuTableRow { func configureCell(_ cell: UITableViewCell) { - guard let cell = cell as? CellType else { + guard let cell = cell as? LatestPostSummaryConfigurable else { return } diff --git a/WordPress/Classes/ViewRelated/System/Action Sheet/BloggingPromptsHeaderView.swift b/WordPress/Classes/ViewRelated/System/Action Sheet/BloggingPromptsHeaderView.swift new file mode 100644 index 000000000000..853223cd8f91 --- /dev/null +++ b/WordPress/Classes/ViewRelated/System/Action Sheet/BloggingPromptsHeaderView.swift @@ -0,0 +1,92 @@ +import UIKit + +class BloggingPromptsHeaderView: UIView, NibLoadable { + @IBOutlet private weak var containerStackView: UIStackView! + @IBOutlet private weak var titleStackView: UIStackView! + @IBOutlet private weak var titleLabel: UILabel! + @IBOutlet private weak var promptLabel: UILabel! + @IBOutlet private weak var answerPromptButton: UIButton! + @IBOutlet private weak var answeredStackView: UIStackView! + @IBOutlet private weak var answeredLabel: UILabel! + @IBOutlet private weak var shareButton: UIButton! + @IBOutlet private weak var dividerView: UIView! + + override func awakeFromNib() { + super.awakeFromNib() + configureView() + } + + @IBAction private func answerPromptTapped(_ sender: Any) { + // TODO + } + + @IBAction private func shareTapped(_ sender: Any) { + // TODO + } +} + +// MARK: - Private methods + +private extension BloggingPromptsHeaderView { + + func configureView() { + // TODO: Hide correct UI based on if prompt is answered + answerPromptButton.isHidden = true + configureSpacing() + configureStrings() + configureStyles() + configureConstraints() + } + + func configureSpacing() { + containerStackView.setCustomSpacing(Constants.titleSpacing, after: titleStackView) + containerStackView.setCustomSpacing(Constants.answeredViewSpacing, after: answeredStackView) + containerStackView.setCustomSpacing(Constants.answerPromptButtonSpacing, after: answerPromptButton) + } + + func configureStrings() { + titleLabel.text = Strings.title + // TODO: Use prompt from backend + promptLabel.text = Strings.examplePrompt + answerPromptButton.titleLabel?.text = Strings.answerButtonTitle + answeredLabel.text = Strings.answeredLabelTitle + shareButton.titleLabel?.text = Strings.shareButtonTitle + } + + func configureStyles() { + titleLabel.font = WPStyleGuide.fontForTextStyle(.subheadline, fontWeight: .semibold) + promptLabel.font = WPStyleGuide.BloggingPrompts.promptContentFont + answerPromptButton.titleLabel?.font = WPStyleGuide.BloggingPrompts.buttonTitleFont + answerPromptButton.titleLabel?.adjustsFontForContentSizeCategory = true + answerPromptButton.setTitleColor(WPStyleGuide.BloggingPrompts.buttonTitleColor, for: .normal) + answeredLabel.font = WPStyleGuide.BloggingPrompts.buttonTitleFont + answeredLabel.textColor = WPStyleGuide.BloggingPrompts.answeredLabelColor + shareButton.titleLabel?.font = WPStyleGuide.BloggingPrompts.buttonTitleFont + shareButton.titleLabel?.adjustsFontForContentSizeCategory = true + shareButton.titleLabel?.adjustsFontSizeToFitWidth = true + shareButton.setTitleColor(WPStyleGuide.BloggingPrompts.buttonTitleColor, for: .normal) + } + + func configureConstraints() { + NSLayoutConstraint.activate([ + dividerView.heightAnchor.constraint(equalToConstant: .hairlineBorderWidth), + ]) + } + + // MARK: - Constants + + struct Constants { + static let titleSpacing: CGFloat = 8.0 + static let answeredViewSpacing: CGFloat = 9.0 + static let answerPromptButtonSpacing: CGFloat = 9.0 + } + + struct Strings { + static let examplePrompt = NSLocalizedString("Cast the movie of your life.", comment: "Example prompt for blogging prompts in the create new bottom action sheet.") + static let title = NSLocalizedString("Prompts", comment: "Title label for blogging prompts in the create new bottom action sheet.") + static let answerButtonTitle = NSLocalizedString("Answer Prompt", comment: "Title for a call-to-action button in the create new bottom action sheet.") + static let answeredLabelTitle = NSLocalizedString("✓ Answered", comment: "Title label that indicates the prompt has been answered.") + static let shareButtonTitle = NSLocalizedString("Share", comment: "Title for a button that allows the user to share their answer to the prompt.") + } + +} diff --git a/WordPress/Classes/ViewRelated/System/Action Sheet/BloggingPromptsHeaderView.xib b/WordPress/Classes/ViewRelated/System/Action Sheet/BloggingPromptsHeaderView.xib new file mode 100644 index 000000000000..1fd7a4f86362 --- /dev/null +++ b/WordPress/Classes/ViewRelated/System/Action Sheet/BloggingPromptsHeaderView.xib @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonActionSheet.swift b/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonActionSheet.swift index 769fe02b4f19..4a85f2e7a40e 100644 --- a/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonActionSheet.swift +++ b/WordPress/Classes/ViewRelated/System/Floating Create Button/CreateButtonActionSheet.swift @@ -11,8 +11,9 @@ class CreateButtonActionSheet: ActionSheetViewController { } init(actions: [ActionSheetItem]) { + let headerView = FeatureFlag.bloggingPrompts.enabled ? BloggingPromptsHeaderView.loadFromNib() : nil let buttons = actions.map { $0.makeButton() } - super.init(headerTitle: Constants.title, buttons: buttons) + super.init(headerView: headerView, headerTitle: Constants.title, buttons: buttons) } required init?(coder: NSCoder) { diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController+QuickStart.swift b/WordPress/Classes/ViewRelated/System/WPTabBarController+QuickStart.swift index ae2effc2585c..147b3b0cf509 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController+QuickStart.swift +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController+QuickStart.swift @@ -7,16 +7,18 @@ extension WPTabBarController { spotlightView?.removeFromSuperview() spotlightView = nil + let tabBarElements: [QuickStartTourElement] = [.readerTab, .notifications] + guard let userInfo = notification.userInfo, let element = userInfo[QuickStartTourGuide.notificationElementKey] as? QuickStartTourElement, - [.readerTab].contains(element) else { + tabBarElements.contains(element) else { return } let newSpotlight = QuickStartSpotlightView() self?.view.addSubview(newSpotlight) - guard let tabButton = self?.getTabButton(at: Int(WPTab.reader.rawValue)) else { + guard let tabButton = self?.getTabButton(for: element) else { return } @@ -39,6 +41,10 @@ extension WPTabBarController { QuickStartTourGuide.shared.visited(.readerTab) } + @objc func alertQuickStartThatNotificationsWasTapped() { + QuickStartTourGuide.shared.visited(.notifications) + } + @objc func alertQuickStartThatOtherTabWasTapped() { QuickStartTourGuide.shared.visited(.tabFlipped) } @@ -48,13 +54,27 @@ extension WPTabBarController { quickStartObserver = nil } - private func getTabButton(at index: Int) -> UIView? { + private func getTabButton(for element: QuickStartTourElement) -> UIView? { + guard let index = tabIndex(for: element) else { + return nil + } tabBar.layoutIfNeeded() var tabs = tabBar.subviews.compactMap { return $0 is UIControl ? $0 : nil } tabs.sort { $0.frame.origin.x < $1.frame.origin.x } return tabs[safe: index] } + private func tabIndex(for element: QuickStartTourElement) -> Int? { + switch element { + case .readerTab: + return Int(WPTab.reader.rawValue) + case .notifications: + return Int(WPTab.notifications.rawValue) + default: + return nil + } + } + private enum Constants { static let spotlightDiameter: CGFloat = 40 static let spotlightXOffset: CGFloat = 20 diff --git a/WordPress/Classes/ViewRelated/System/WPTabBarController.m b/WordPress/Classes/ViewRelated/System/WPTabBarController.m index cf5230313565..0640f0178247 100644 --- a/WordPress/Classes/ViewRelated/System/WPTabBarController.m +++ b/WordPress/Classes/ViewRelated/System/WPTabBarController.m @@ -457,6 +457,10 @@ - (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectView [self alertQuickStartThatReaderWasTapped]; break; } + case WPTabNotifications: { + [self alertQuickStartThatNotificationsWasTapped]; + break; + } default: break; } diff --git a/WordPress/Classes/WordPress.xcdatamodeld/.xccurrentversion b/WordPress/Classes/WordPress.xcdatamodeld/.xccurrentversion index 37fda4b9a61b..a6087e972746 100644 --- a/WordPress/Classes/WordPress.xcdatamodeld/.xccurrentversion +++ b/WordPress/Classes/WordPress.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - WordPress 138.xcdatamodel + WordPress 139.xcdatamodel diff --git a/WordPress/Classes/WordPress.xcdatamodeld/WordPress 139.xcdatamodel/contents b/WordPress/Classes/WordPress.xcdatamodeld/WordPress 139.xcdatamodel/contents new file mode 100644 index 000000000000..86c8aaf77bcf --- /dev/null +++ b/WordPress/Classes/WordPress.xcdatamodeld/WordPress 139.xcdatamodel/contents @@ -0,0 +1,1063 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WordPress/Jetpack/Resources/release_notes.txt b/WordPress/Jetpack/Resources/release_notes.txt index 16fdae8901ab..f565d1aff3a1 100644 --- a/WordPress/Jetpack/Resources/release_notes.txt +++ b/WordPress/Jetpack/Resources/release_notes.txt @@ -1,11 +1,12 @@ -We made a small but mighty change to the block editor: the “Add Block” button is more visible when you first open the editor with no blocks selected. We also removed one of three error notifications when a media or audio block fails to upload—it felt like overkill. +* [*] [internal] My Site Dashboard: Made some changes to the code architecture of the dashboard. The majority of the changes are related to the posts cards. It should have no visible changes but could cause regressions. Please test it by creating/trashing drafts and scheduled posts and testing that they appear correctly on the dashboard. [#18405] +* [*] Quick Start: Updated the Stats tour. The tour can now be accessed from either the dashboard or the menu tab. [#18413] +* [*] Quick Start: Updated the Reader tour. The tour now highlights the Discover tab and guides users to follow topics via the Settings screen. [#18450] +* [*] [internal] Quick Start: Deleted the Edit your homepage tour. [#18469] +* [*] [internal] Quick Start: Refactored some code related to the tasks displayed in the Quick Start Card and the Quick Start modal. It should have no visible changes but could cause regressions. [#18395] +* [**] Follow Conversation flow now enables in-app notifications by default. They were updated to be opt-out rather than opt-in. [#18449] +* [*] Block Editor: Latest Posts block: Add featured image settings [https://github.com/WordPress/gutenberg/pull/39257] +* [*] Block Editor: Prevent incorrect notices displaying when switching between HTML-Visual mode quickly [https://github.com/WordPress/gutenberg/pull/40415] +* [*] Block Editor: Embed block: Fix inline preview cut-off when editing URL [https://github.com/WordPress/gutenberg/pull/35326] +* [*] Block Editor: Prevent gaps shown around floating toolbar when using external keyboard [https://github.com/WordPress/gutenberg/pull/40266] +* [**] We'll now ask users logging in which area of the app they'd like to focus on to build towards a more personalized experience. [#18385] -You’ll hear some accessibility tweaks in the VoiceOver experience when you’re rearranging menu items. Instructions and notices are clearer, and the menu hierarchy makes more sense out loud. - -We added a new screen to the site creation process where you can enter your site’s intent. We tested this screen with a small group of users, and we think you’ll like it, too. - -Web previews won’t cut off bottom-of-the-screen notifications when your browser toolbar is visible. - -What’s in a name? Well, if your site has one, you’ll see it in the My Site navigation title. - -When you swipe left on a comment in your Notifications, you won’t see the “Trash” option anymore. Instead you’ll see “Unapprove Comment” and “Approve Comment.” We approve. diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/Contents.json b/WordPress/Resources/AppImages.xcassets/Notification Prompt/Contents.json new file mode 100644 index 000000000000..73c00596a7fc --- /dev/null +++ b/WordPress/Resources/AppImages.xcassets/Notification Prompt/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/Contents.json b/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/Contents.json new file mode 100644 index 000000000000..01b1925c2ee3 --- /dev/null +++ b/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "traffic-surge-icon.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "traffic-surge-icon@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "traffic-surge-icon@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon.png b/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon.png new file mode 100644 index 000000000000..cd121815efe0 Binary files /dev/null and b/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon.png differ diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon@2x.png b/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon@2x.png new file mode 100644 index 000000000000..c6df465ce9a0 Binary files /dev/null and b/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon@2x.png differ diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon@3x.png b/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon@3x.png new file mode 100644 index 000000000000..c9414d0f69fe Binary files /dev/null and b/WordPress/Resources/AppImages.xcassets/Notification Prompt/traffic-surge-icon.imageset/traffic-surge-icon@3x.png differ diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/Contents.json b/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/Contents.json new file mode 100644 index 000000000000..7f1ed27f52ac --- /dev/null +++ b/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/Contents.json @@ -0,0 +1,23 @@ +{ + "images" : [ + { + "filename" : "view-milestone-1k.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "filename" : "view-milestone-1k@2x.png", + "idiom" : "universal", + "scale" : "2x" + }, + { + "filename" : "view-milestone-1k@3x.png", + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k.png b/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k.png new file mode 100644 index 000000000000..de481e2fcd62 Binary files /dev/null and b/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k.png differ diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k@2x.png b/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k@2x.png new file mode 100644 index 000000000000..f310ce160211 Binary files /dev/null and b/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k@2x.png differ diff --git a/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k@3x.png b/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k@3x.png new file mode 100644 index 000000000000..c45c3f6e1cdb Binary files /dev/null and b/WordPress/Resources/AppImages.xcassets/Notification Prompt/view-milestone-1k.imageset/view-milestone-1k@3x.png differ diff --git a/WordPress/Resources/ar.lproj/Localizable.strings b/WordPress/Resources/ar.lproj/Localizable.strings index e0d99c06fb30..3ceb5010689c 100644 --- a/WordPress/Resources/ar.lproj/Localizable.strings +++ b/WordPress/Resources/ar.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-20 20:54:07+0000 */ +/* Translation-Revision-Date: 2022-04-25 15:46:19+0000 */ /* Plural-Forms: nplurals=6; plural=(n == 0) ? 0 : ((n == 1) ? 1 : ((n == 2) ? 2 : ((n % 100 >= 3 && n % 100 <= 10) ? 3 : ((n % 100 >= 11 && n % 100 <= 99) ? 4 : 5)))); */ /* Generator: GlotPress/3.0.0 */ /* Language: ar */ @@ -8387,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "استخدام زر الأيقونة"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "استخدم هذا الرابط لضمّ أعضاء فريقك دون الحاجة إلى دعوتهم واحدًا تلو الآخر. سيتمكن أي شخص يزور عنوان الموقع هذا من الاشتراك في مؤسستك، حتى إذا تلقى الرابط من شخص آخر، لذا تأكد من مشاركته مع أشخاص موثوق بهم."; - /* No comment provided by engineer. */ "Use this site" = "استخدام هذا الموقع"; @@ -9497,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "لإضافة صور أو مقاطع فيديو إلى مقالاتك."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "استخدم هذا الرابط لضم أعضاء فريقك من دون دعوتهم واحدًا تلو الآخر. سيتمكن أي شخص يزور عنوان URL هذا من التسجيل في مؤسستك، حتى إذا تلقى الرابط من شخص آخر، لذا تأكَّد من مشاركته مع أشخاص موثوق بهم."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "حفظ كمسودة"; diff --git a/WordPress/Resources/cs.lproj/Localizable.strings b/WordPress/Resources/cs.lproj/Localizable.strings index 71f1e4627a18..7ff6cf1ed7ea 100644 --- a/WordPress/Resources/cs.lproj/Localizable.strings +++ b/WordPress/Resources/cs.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-04 20:35:21+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:45:55+0000 */ /* Plural-Forms: nplurals=3; plural=(n == 1) ? 0 : ((n >= 2 && n <= 4) ? 1 : 2); */ /* Generator: GlotPress/3.0.0 */ /* Language: cs_CZ */ @@ -8323,9 +8323,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Použijte ikonu tlačítka"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Pomocí tohoto odkazu můžete připojit členy svého týmu, aniž byste je museli pozvat jeden po druhém. Kdokoli, kdo navštíví tuto adresu URL, se bude moci zaregistrovat do vaší organizace, i když obdržel odkaz od někoho jiného, takže se ujistěte, že jej sdílíte s důvěryhodnými lidmi."; - /* No comment provided by engineer. */ "Use this site" = "Vybrat tuto stránku"; @@ -9430,6 +9427,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Chcete přidat fotky a videa do vašeho příspěvku."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Pomocí tohoto odkazu můžete připojit členy svého týmu, aniž byste je museli pozvat jeden po druhém. Kdokoli, kdo navštíví tuto adresu URL, se bude moci zaregistrovat do vaší organizace, i když obdržel odkaz od někoho jiného, takže se ujistěte, že jej sdílíte s důvěryhodnými lidmi."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Uložit jako koncept"; diff --git a/WordPress/Resources/de.lproj/Localizable.strings b/WordPress/Resources/de.lproj/Localizable.strings index 55ddaf1c6d13..9f613419ffdb 100644 --- a/WordPress/Resources/de.lproj/Localizable.strings +++ b/WordPress/Resources/de.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-08 09:54:11+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:11:55+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: de */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d Gefällt mir"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d Antwort"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d Antworten"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "%1$d von %2$d komplett"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "Eine Datei enthält ein bösartiges Codemuster"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "Ein guter Name ist kurz und einprägsam.\nDu kannst es später jederzeit ändern."; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "Eine neue Möglichkeit zum Erstellen und Veröffentlichen ansprechender Inhalte auf deiner Website."; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "Block davor hinzufügen"; +/* No comment provided by engineer. */ +"Add Blocks" = "Blöcke hinzufügen"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "Inhalte in Beitrag einfügen"; @@ -621,6 +633,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "Erweitert"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "Nach %@"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -778,6 +793,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "Anonym"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "Auf Themenvorschlag antworten"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "App-Icon"; @@ -1036,6 +1054,9 @@ translators: Block name. %s: The localized block name */ /* Message shown encouraging the user to leave a comment on a post in the reader. */ "Be the first to leave a comment." = "Schreibe den ersten Kommentar."; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "Vor %@"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "Bester Tag"; @@ -1291,6 +1312,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "Vorsicht!"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "Dreh einen Film über dein Leben."; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "Kategorien"; @@ -1398,6 +1422,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "Überprüfe Käufe …"; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "Untergeordneter Menüeintrag von %@"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "Auswählen"; @@ -1437,6 +1464,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "Uhrzeit auswählen"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "Wähle ein Thema aus der unten stehenden Liste aus oder gib ein eigenes ein."; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "Ein einzigartiges Website-Icon auswählen"; @@ -2447,6 +2477,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "Zum Bearbeiten zweimal tippen und halten"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "Um diesen Menüeintrag nach oben oder unten zu verschieben, zweimal tippen und gedrückt halten. Horizontal verschieben, um die Hierarchie zu ändern."; + /* No comment provided by engineer. */ "Double tap to add a block" = "Zum Hinzufügen eines Blocks zweimal tippen"; @@ -2579,6 +2612,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Duplicate block" = "Block duplizieren"; +/* Placeholder text for the search field int the Site Intent screen. */ +"E.g. Fashion, Poetry, Politics" = "z. B. Mode, Poesie, Politik"; + /* No comment provided by engineer. */ "Each block has its own settings. To find them, tap on a block. Its settings will appear on the toolbar at the bottom of the screen." = "Jeder Block hat eigene Einstellungen. Tippe auf den jeweiligen Block, um sie zu finden. Die Einstellungen werden in der Werkzeugleiste unten auf dem Bildschirm angezeigt."; @@ -3366,6 +3402,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "Wähle einen Namen für deine Website, der am besten zu ihrer Persönlichkeit und Ausrichtung passt. Erste Eindrücke zählen!"; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "Gib deiner Website einen Namen"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "Gib deiner %@-Website einen Namen"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3763,6 +3806,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "Die Installation des ersten Plugins auf deiner Website kann bis zu einer Minute dauern. Während dieser Zeit kannst du keine Änderungen an deiner Website vornehmen."; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "Möchtest du eine Zielgruppe aufbauen? Top-Tipps ansehen"; + /* Interior Design site intent topic */ "Interior Design" = "Innenarchitektur"; @@ -4447,6 +4493,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "Beliebteste Zeit"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "%@ verschieben"; + /* No comment provided by engineer. */ "Move Image Backward" = "Bild nach hinten verschieben"; @@ -5705,6 +5754,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "Projekte"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "Themenvorschläge"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "Öffentlich"; @@ -5948,6 +6000,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "Block entfernen"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "Aus Dashboard entfernen"; + /* Option to remove Insight from view. */ "Remove from insights" = "Aus Einsichten entfernen"; @@ -6841,6 +6896,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "Schnellstart überspringen"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "Diesen Themenvorschlag überspringen"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "Ergebnisse der Schrägstrich-Eingabe"; @@ -8320,9 +8378,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Icon-Button verwenden"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Verwende diesen Link, um deine Teammitglieder einzuladen. Jeder, der diese URL besucht, kann sich bei deiner Organisation registrieren, auch wenn er oder sie den Link von jemand anderem erhalten hat. Teile ihn also nur mit vertrauenswürdigen Personen."; - /* No comment provided by engineer. */ "Use this site" = "Diese Website verwenden"; @@ -8434,6 +8489,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "Mehr anzeigen"; +/* Menu title to show more prompts. */ +"View more prompts" = "Mehr Themenvorschläge anzeigen"; + /* Description for view count. Singular. */ "View to your site so far" = "Bisheriger Aufruf deiner Website"; @@ -9427,6 +9485,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Um deinen Beiträgen Fotos oder Videos hinzuzufügen."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Verwende diesen Link, um deine Teammitglieder einzuladen. Jeder, der diese URL besucht, kann sich bei deiner Organisation registrieren, auch wenn er oder sie den Link von jemand anderem erhalten hat. Teile ihn also nur mit vertrauenswürdigen Personen."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Als Entwurf speichern"; @@ -9598,3 +9659,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "• Benutzer und Autoren"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ Geantwortet"; + diff --git a/WordPress/Resources/en-CA.lproj/Localizable.strings b/WordPress/Resources/en-CA.lproj/Localizable.strings index 7cf64c1d4a71..1a4dff47dbb5 100644 --- a/WordPress/Resources/en-CA.lproj/Localizable.strings +++ b/WordPress/Resources/en-CA.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-03-14 23:56:27+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:47:07+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: en_CA */ @@ -8204,9 +8204,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Use icon button"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted people."; - /* No comment provided by engineer. */ "Use this site" = "Use this site"; @@ -9281,6 +9278,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Text for related post cell preview */ "in \"Upgrade\"" = "in \"Upgrade\""; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted people."; + /* Later today */ "later today" = "later today"; diff --git a/WordPress/Resources/en-GB.lproj/Localizable.strings b/WordPress/Resources/en-GB.lproj/Localizable.strings index d431e70bfeb5..4d5dc0350ed1 100644 --- a/WordPress/Resources/en-GB.lproj/Localizable.strings +++ b/WordPress/Resources/en-GB.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-19 13:54:15+0000 */ +/* Translation-Revision-Date: 2022-04-22 21:59:41+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: en_GB */ @@ -8387,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Use icon button"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organisation, even if they received the link from somebody else, so make sure that you share it with trusted people."; - /* No comment provided by engineer. */ "Use this site" = "Use this site"; @@ -9497,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "To add photos or videos to your posts."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organisation, even if they received the link from somebody else, so make sure that you share it with trusted people."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Save as Draft"; diff --git a/WordPress/Resources/en.lproj/Localizable.strings b/WordPress/Resources/en.lproj/Localizable.strings index e4a4fab5aa62..c8fb1cfd3075 100644 --- a/WordPress/Resources/en.lproj/Localizable.strings +++ b/WordPress/Resources/en.lproj/Localizable.strings @@ -108,6 +108,9 @@ /* Accessibility label for value in quintillions. Ex: 66.6 quintillion. */ "%@ quintillion" = "%@ quintillion"; +/* Title of the task complete hint for the Quick Start Tour */ +"%@ Return to My Site screen when you're ready for the next task." = "%@ Return to My Site screen when you're ready for the next task."; + /* The number of tags in the writting settings. Singular. %@ is a placeholder for the number */ "%@ Tag" = "%@ Tag"; @@ -117,6 +120,9 @@ /* Accessibility label for value in thousands. Ex: 66.6 thousand. */ "%@ thousand" = "%@ thousand"; +/* Title of the task complete hint for the Quick Start Tour */ +"%@ Tip: get updates faster by enabling push notifications." = "%@ Tip: get updates faster by enabling push notifications."; + /* Accessibility label for value in trillions. Ex: 66.6 trillion. */ "%@ trillion" = "%@ trillion"; @@ -253,9 +259,18 @@ /* Menus title label text for a post that has no set title. */ "(Untitled)" = "(Untitled)"; +/* Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text. */ +"*Johann Brandt* is now following your site!" = "*Johann Brandt* is now following your site!"; + +/* Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text. */ +"*Johann Brandt* responded to your comment" = "*Johann Brandt* responded to your comment"; + /* Example Comment notification displayed in the prologue carousel of the app. Username should be marked with * characters and will be displayed as bold text. */ "*Johann Brandt* responded to your post" = "*Johann Brandt* responded to your post"; +/* Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text. */ +"*Madison Ruiz* added a new post to their site" = "*Madison Ruiz* added a new post to their site"; + /* Example Like notification displayed in the prologue carousel of the app. Username should be marked with * characters and will be displayed as bold text. */ "*Madison Ruiz* liked your post" = "*Madison Ruiz* liked your post"; @@ -343,18 +358,18 @@ /* Message of Close Account confirmation alert */ "\nTo confirm, please re-enter your username before closing.\n\n" = "\nTo confirm, please re-enter your username before closing.\n\n"; -/* Describes that only one user likes a post. %1$d is the number of likes. The underscores denote underline and is not displayed. */ -"_%1$d blogger_ likes this." = "_%1$d blogger_ likes this."; - /* Plural format string for displaying the number of post likes. %1$d is the number of likes. The underscores denote underline and is not displayed. */ "_%1$d bloggers_ like this." = "_%1$d bloggers_ like this."; -/* Describes that the current user and one other user like a post. %1$d is the number of likes, excluding the like by current user. The underscores denote underline and is not displayed. */ -"_You and %1$d blogger_ like this." = "_You and %1$d blogger_ like this."; +/* Describes that only one user likes a post. The underscores denote underline and is not displayed. */ +"_One blogger_ likes this." = "_One blogger_ likes this."; /* Plural format string for displaying the number of post likes, including the like from the current user. %1$d is the number of likes, excluding the like by current user. The underscores denote underline and is not displayed. */ "_You and %1$d bloggers_ like this." = "_You and %1$d bloggers_ like this."; +/* Describes that the current user and one other user like a post. The underscores denote underline and is not displayed. */ +"_You and another blogger_ like this." = "_You and another blogger_ like this."; + /* Describes that the current user is the only one liking a post. The underscores denote underline and is not displayed. */ "_You_ like this." = "_You_ like this."; @@ -379,6 +394,9 @@ /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "A new way to create and publish engaging content on your site."; +/* A VoiceOver hint to explain what the user gets when they select the 'Get to know the WordPress app' button. */ +"A series of steps helping you to explore the app." = "A series of steps helping you to explore the app."; + /* A VoiceOver hint to explain what the user gets when they select the 'Customize Your Site' button. */ "A series of steps showing you how to add a theme, site icon and more." = "A series of steps showing you how to add a theme, site icon and more."; @@ -539,9 +557,6 @@ /* No comment provided by engineer. */ "Add blocks" = "Add blocks"; -/* No comment provided by engineer. */ -"Add Blocks" = "Add Blocks"; - /* No comment provided by engineer. */ "Add button text" = "Add button text"; @@ -821,7 +836,8 @@ /* the comment has an anonymous author. */ "Anonymous" = "Anonymous"; -/* Title for a call-to-action button on the prompts card. */ +/* Title for a call-to-action button in the create new bottom action sheet. + Title for a call-to-action button on the prompts card. */ "Answer Prompt" = "Answer Prompt"; /* Navigates to picker screen to change the app's icon @@ -1260,7 +1276,6 @@ "Can't publish an empty post" = "Can't publish an empty post"; /* Alert dismissal title - Button label when canceling alert in quick start Button shown when the author is asked for publishing confirmation. Button title, cancel fixing all threats Button title. Cancels a pending action. @@ -1288,6 +1303,7 @@ Cancel registering a domain Cancel removing a plugin Cancel site creation + Cancel site creation. Cancel the crop Cancel updating User's Role Cancel. Action. @@ -1345,7 +1361,8 @@ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "Careful!"; -/* Example prompt for the Prompts card in Feature Introduction. */ +/* Example prompt for blogging prompts in the create new bottom action sheet. + Example prompt for the Prompts card in Feature Introduction. */ "Cast the movie of your life." = "Cast the movie of your life."; /* Label for Categories @@ -1399,9 +1416,6 @@ /* Button title to edit visibility of sites. */ "Change Visibility" = "Change Visibility"; -/* Description of a Quick Start Tour */ -"Change, add, or remove content from your site's homepage." = "Change, add, or remove content from your site's homepage."; - /* Description of a Quick Start Tour */ "Change, add, or remove your site's pages." = "Change, add, or remove your site's pages."; @@ -1446,6 +1460,9 @@ /* Subtitle for No results full page screen displayed from post list when there is no connection */ "Check your network connection and try again. Or draft a post." = "Check your network connection and try again. Or draft a post."; +/* Title of a Quick Start Tour */ +"Check your notifications" = "Check your notifications"; + /* Title of a Quick Start Tour */ "Check your site stats" = "Check your site stats"; @@ -1455,10 +1472,14 @@ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "Checking purchases…"; +/* Title of button that asks the users if they'd like to focus on checking their sites stats */ +"Checking stats" = "Checking stats"; + /* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ "Child of %@" = "Child of %@"; -/* Title for the button to progress with the selected site homepage design */ +/* Title for the button to progress with the selected site homepage design + Title for the button to progress with the selected site homepage design. */ "Choose" = "Choose"; /* Label for Publish date picker */ @@ -1735,6 +1756,9 @@ /* The action is completed */ "Completed" = "Completed"; +/* The Quick Start Tour title after the user finished the step. */ +"Completed: Check your notifications" = "Completed: Check your notifications"; + /* The Quick Start Tour title after the user finished the step. */ "Completed: Check your site stats" = "Completed: Check your site stats"; @@ -1748,20 +1772,17 @@ "Completed: Choose a unique site icon" = "Completed: Choose a unique site icon"; /* The Quick Start Tour title after the user finished the step. */ -"Completed: Continue with site setup" = "Completed: Continue with site setup"; +"Completed: Connect with other sites" = "Completed: Connect with other sites"; /* The Quick Start Tour title after the user finished the step. */ -"Completed: Create your site" = "Completed: Create your site"; +"Completed: Continue with site setup" = "Completed: Continue with site setup"; /* The Quick Start Tour title after the user finished the step. */ -"Completed: Edit your homepage" = "Completed: Edit your homepage"; +"Completed: Create your site" = "Completed: Create your site"; /* The Quick Start Tour title after the user finished the step. */ "Completed: Explore plans" = "Completed: Explore plans"; -/* The Quick Start Tour title after the user finished the step. */ -"Completed: Follow other sites" = "Completed: Follow other sites"; - /* The Quick Start Tour title after the user finished the step. */ "Completed: Publish a post" = "Completed: Publish a post"; @@ -1804,6 +1825,9 @@ /* Title of domain name purchase success screen */ "Congratulations on your purchase!" = "Congratulations on your purchase!"; +/* Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text. */ +"Congratulations! Your site passed *1000 all-time* views!" = "Congratulations! Your site passed *1000 all-time* views!"; + /* Verb. Tapping connects an account to Publicize. Verb. Text label. Allows the user to connect to a third-party sharing service like Facebook or Twitter. */ "Connect" = "Connect"; @@ -1820,6 +1844,9 @@ /* A detailed message to users about growing the audience for their site through reader discover. */ "Connect with other bloggers by following, liking and commenting on their posts." = "Connect with other bloggers by following, liking and commenting on their posts."; +/* Title of a Quick Start Tour */ +"Connect with other sites" = "Connect with other sites"; + /* No comment provided by engineer. */ "Connect your favorite social media services to automatically share new posts with friends." = "Connect your favorite social media services to automatically share new posts with friends."; @@ -2117,7 +2144,8 @@ "Create Post" = "Create Post"; /* Button to progress to the next step - Site creation. Step 1. Screen title */ + Site creation. Step 1. Screen title + Title for the button to progress with creating the site with the selected design. */ "Create Site" = "Create Site"; /* Stories intro continue button title */ @@ -2226,8 +2254,7 @@ /* Customize Insights title */ "Customize your insights" = "Customize your insights"; -/* Name of the Quick Start list that guides users through a few tasks to customize their new website. - Title of the Quick Start Checklist that guides users through a few tasks to customize their new website. */ +/* Name of the Quick Start list that guides users through a few tasks to customize their new website. */ "Customize Your Site" = "Customize Your Site"; /* Notification Settings for your own blogs */ @@ -2352,7 +2379,7 @@ Title of section that contains plugins' description */ "Description" = "Description"; -/* Shortened version of the main title to be used in back navigation */ +/* Shortened version of the main title to be used in back navigation. */ "Design" = "Design"; /* Title for the desktop web preview */ @@ -2409,9 +2436,15 @@ /* Explanatory text for the user. The `%@` is a placeholder for the name of a third-party sharing service. */ "Disconnecting this account means published posts will no longer be automatically shared to %@" = "Disconnecting this account means published posts will no longer be automatically shared to %@"; +/* The menu item to select during a guided tour. */ +"Discover" = "Discover"; + /* Reader select interests title label text */ "Discover and follow blogs you love" = "Discover and follow blogs you love"; +/* Description of a Quick Start Tour */ +"Discover and follow sites that inspire you." = "Discover and follow sites that inspire you."; + /* Title for button that will open up the follow topics screen. */ "Discover blogs to follow" = "Discover blogs to follow"; @@ -2738,9 +2771,6 @@ /* No comment provided by engineer. */ "Edit video" = "Edit video"; -/* Title of a Quick Start Tour */ -"Edit your homepage" = "Edit your homepage"; - /* No comment provided by engineer. */ "Editing reusable blocks is not yet supported on WordPress for Android" = "Editing reusable blocks is not yet supported on WordPress for Android"; @@ -2843,9 +2873,6 @@ /* Describes a switch component that toggles in-app notifications for a followed post. */ "Enable in-app notifications" = "Enable in-app notifications"; -/* Hint for the action button that enables notification for new comments */ -"Enable in-app notifications?" = "Enable in-app notifications?"; - /* Title for button that will open up the social media Sharing screen. */ "Enable post sharing" = "Enable post sharing"; @@ -2853,7 +2880,10 @@ "Enable Publicize" = "Enable Publicize"; /* Title of a row displayed on the debug screen used in debug builds of the app */ -"Enable Quick Start for Site" = "Enable Quick Start for Site"; +"Enable Quick Start for Existing Site" = "Enable Quick Start for Existing Site"; + +/* Title of a row displayed on the debug screen used in debug builds of the app */ +"Enable Quick Start for New Site" = "Enable Quick Start for New Site"; /* Message prompting user to enable site notifications. */ "Enable site notifications?" = "Enable site notifications?"; @@ -3231,9 +3261,6 @@ /* Title for the find out more button in the What's New page. */ "Find out more" = "Find out more"; -/* Description of a Quick Start Tour */ -"Find sites that speak to you, and follow them to get updates when they publish." = "Find sites that speak to you, and follow them to get updates when they publish."; - /* The hint button's title text to help users find their site address. */ "Find your site address" = "Find your site address"; @@ -3275,10 +3302,7 @@ "Follow Conversation" = "Follow Conversation"; /* Verb. Button title. Follow the comments on a post. */ -"Follow conversation by email" = "Follow conversation by email"; - -/* Title of a Quick Start Tour */ -"Follow other sites" = "Follow other sites"; +"Follow conversation" = "Follow conversation"; /* Verb. An option to follow a site. */ "Follow site" = "Follow site"; @@ -3430,6 +3454,9 @@ /* Displayed in the Notifications Tab as a message, when the Follow Filter shows no notifications */ "Get noticed: comment on posts you've read." = "Get noticed: comment on posts you've read."; +/* Description of a Quick Start Tour */ +"Get real time updates from your pocket." = "Get real time updates from your pocket."; + /* View title for initial auth views. */ "Get Started" = "Get Started"; @@ -3442,6 +3469,9 @@ /* Appended to latest post summary text when the post does not have data. */ "Get the ball rolling and increase your post views by sharing your post." = "Get the ball rolling and increase your post views by sharing your post."; +/* Name of the Quick Start list that guides users through a few tasks to explore the WordPress app. */ +"Get to know the WordPress app" = "Get to know the WordPress app"; + /* Title of the card that starts the purchase of the first redirected domain in the Domains Dashboard. */ "Get your domain" = "Get your domain"; @@ -3466,6 +3496,9 @@ /* Cancel */ "Give Up" = "Give Up"; +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your %@ website a name" = "Give your %@ website a name"; + /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "Give your site a name that reflects its personality and topic. First impressions count!"; @@ -3473,9 +3506,6 @@ Title for Site Name screen in iPhone landscape. */ "Give your website a name" = "Give your website a name"; -/* Title of the Site Name screen. Takes the vertical name as a parameter. */ -"Give your%@website a name" = "Give your%@website a name"; - /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3514,10 +3544,12 @@ /* This is the text we display to the user after they've indicated they like the app */ "Great!\n We love to hear from happy users \n😁" = "Great!\n We love to hear from happy users \n😁"; -/* Name of the Quick Start list that guides users through a few tasks to customize their new website. - Title of the Quick Start Checklist that guides users through a few tasks to grow the audience of their new website. */ +/* Name of the Quick Start list that guides users through a few tasks to customize their new website. */ "Grow Your Audience" = "Grow Your Audience"; +/* This value is used to set the accessibility hint text for viewing the user's notifications. */ +"Guides you through the process of checking your notifications." = "Guides you through the process of checking your notifications."; + /* This value is used to set the accessibility hint text for choosing a theme for the user's site. */ "Guides you through the process of choosing a theme for your site." = "Guides you through the process of choosing a theme for your site."; @@ -3647,8 +3679,7 @@ Title for the dashboard screen. */ "Home" = "Home"; -/* The item to select during a guided tour. - Title for setting which shows the current page assigned as a site's homepage +/* Title for setting which shows the current page assigned as a site's homepage Title for the homepage section in site settings screen Title of the Homepage Badge */ "Homepage" = "Homepage"; @@ -3793,6 +3824,9 @@ /* The plugin is not active on the site and has enabled automatic updates */ "Inactive, Autoupdates on" = "Inactive, Autoupdates on"; +/* Title of the switch to turn on or off the blogging prompts feature. */ +"Include prompt" = "Include prompt"; + /* Describes a standard *.wordpress.com site domain */ "Included with Site" = "Included with Site"; @@ -3936,6 +3970,9 @@ /* Invite People Title */ "Invite People" = "Invite People"; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted people."; + /* Describes the IP address section in the comment detail screen. */ "IP address" = "IP address"; @@ -4051,6 +4088,12 @@ /* Description of a Quick Start Tour */ "Keep up to date on your site’s performance." = "Keep up to date on your site’s performance."; +/* Subtitle giving the user more context about why to enable notifications. */ +"Know when your favorite authors post new content." = "Know when your favorite authors post new content."; + +/* Subtitle giving the user more context about why to enable notifications. */ +"Know when your site is getting more traffic, new followers, or when it passes a new milestone!" = "Know when your site is getting more traffic, new followers, or when it passes a new milestone!"; + /* An option in a list. Automatically approve comments from known users. */ "Known user's comments" = "Known user's comments"; @@ -4099,6 +4142,9 @@ /* Writing, Date and Time Settings: Learn more about date and time settings footer text */ "Learn more about date and time formatting." = "Learn more about date and time formatting."; +/* Accessibility label for the blogging prompts info button on the Blogging Reminders Settings screen. */ +"Learn more about prompts" = "Learn more about prompts"; + /* Footer text for Invite People role field. */ "Learn more about roles" = "Learn more about roles"; @@ -5040,6 +5086,9 @@ /* Display value for Support email field if there is no user email address. */ "Not Set" = "Not Set"; +/* Button that allows users unsure of what selection they'd like */ +"Not sure, show me around" = "Not sure, show me around"; + /* Label for the note displayed in the Feature Introduction view. */ "Note:" = "Note:"; @@ -5072,9 +5121,13 @@ /* Title for the time picker button in Blogging Reminders. */ "Notification time" = "Notification time"; +/* Description of the blogging prompts feature on the Blogging Reminders Settings screen. */ +"Notification will include a word or short phrase for inspiration" = "Notification will include a word or short phrase for inspiration"; + /* Notifications 3D Touch Shortcut Notifications tab bar item accessibility label Notifications View Controller title + The item to select during a guided tour. Title of the 'Notifications' tab - used for spotlight indexing on iOS. */ "Notifications" = "Notifications"; @@ -5767,9 +5820,9 @@ /* Displays the Post Preview Interface Section title for related posts section preview - Title for button to preview a selected homepage design + Title for button to preview a selected homepage design. Title for button to preview a selected layout - Title for screen to preview a selected homepage design + Title for screen to preview a selected homepage design. Title for screen to preview a static content. */ "Preview" = "Preview"; @@ -5792,7 +5845,7 @@ "Preview Unavailable" = "Preview Unavailable"; /* Description of a Quick Start Tour */ -"Preview your new site to see what your visitors will see." = "Preview your new site to see what your visitors will see."; +"Preview your site to see what your visitors will see." = "Preview your site to see what your visitors will see."; /* Accessibility label for the button which shows the previous month in the monthly calendar view */ "Previous month" = "Previous month"; @@ -5859,7 +5912,8 @@ /* Menu item label for linking a project page. */ "Projects" = "Projects"; -/* Title label for the Prompts card in My Sites tab. */ +/* Title label for blogging prompts in the create new bottom action sheet. + Title label for the Prompts card in My Sites tab. */ "Prompts" = "Prompts"; /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. @@ -5979,6 +6033,9 @@ /* Title of the screen that allows the user to change the Reader CSS URL for debug builds */ "Reader CSS URL" = "Reader CSS URL"; +/* Title of button that asks the users if they'd like to focus on checking their sites stats */ +"Reading posts from other sites" = "Reading posts from other sites"; + /* Real Estate site intent topic */ "Real Estate" = "Real Estate"; @@ -6448,7 +6505,6 @@ "Scrollable block menu opened. Select a block." = "Scrollable block menu opened. Select a block."; /* Placeholder text for the search bar - The menu item to select during a guided tour. Title of the Reader's search feature */ "Search" = "Search"; @@ -6538,13 +6594,7 @@ "Select %@ to discover new themes" = "Select %@ to discover new themes"; /* A step in a guided tour for quick start. %@ will be the name of the item to select. */ -"Select %@ to edit your Homepage." = "Select %@ to edit your Homepage."; - -/* A step in a guided tour for quick start. %@ will be the name of the item to select. */ -"Select %@ to look for sites with similar interests" = "Select %@ to look for sites with similar interests"; - -/* A step in a guided tour for quick start. %@ will be the name of the item to select. */ -"Select %@ to preview" = "Select %@ to preview"; +"Select %@ to find other sites." = "Select %@ to find other sites."; /* A step in a guided tour for quick start. %@ will be the name of the item to select. */ "Select %@ to see how your site is performing." = "Select %@ to see how your site is performing."; @@ -6564,6 +6614,9 @@ /* A step in a guided tour for quick start. %@ will be the name of the item to select. */ "Select %@ to upload a new one." = "Select %@ to upload a new one."; +/* A step in a guided tour for quick start. %@ will be the site url. */ +"Select %@ to view your site" = "Select %@ to view your site"; + /* No comment provided by engineer. */ "Select a color" = "Select a color"; @@ -6597,6 +6650,9 @@ /* Register Domain - Address information field placeholder for State */ "Select State" = "Select State"; +/* A step in a guided tour for quick start. %@ will be the name of the item to select. */ +"Select the %@ tab to get updates on the go." = "Select the %@ tab to get updates on the go."; + /* A step in a guided tour for quick start. %@ will be the name of the item to select. */ "Select the %@ to add your social media accounts" = "Select the %@ to add your social media accounts"; @@ -6735,6 +6791,7 @@ /* Link to plugin's Settings Section title + The menu item to select during a guided tour. Title for screen that allows configuration of your blog/site settings. Title for the Jetpack Security Settings Screen */ "Settings" = "Settings"; @@ -6968,7 +7025,8 @@ /* Title of the navigation bar, shown when the large title is hidden. */ "Site Topic" = "Site Topic"; -/* The accessibility label for the followed sites search field */ +/* The accessibility label for the followed sites search field + The item to select during a guided tour. */ "Site URL" = "Site URL"; /* Sites Filter Tab Title @@ -6984,18 +7042,13 @@ /* Image size option title. */ "Size" = "Size"; -/* Button label when skipping all quick start items +/* Button that allows the user to skip the prompt and be brought to the app Button title that appears when you swipe to left the row. It indicates the possibility to skip a specific tour. Continue without making a selection + Continue without making a selection. Title for the Skip button in the Site Name Screen. */ "Skip" = "Skip"; -/* Label for button that will allow the user to skip all items in the Quick Start checklist */ -"Skip All" = "Skip All"; - -/* Title shown in alert to confirm skipping all quick start items */ -"Skip Quick Start" = "Skip Quick Start"; - /* Menu title to skip today's prompt. */ "Skip this prompt" = "Skip this prompt"; @@ -7167,12 +7220,39 @@ /* Displayed in the Stats widgets when there is no network */ "Stats will be updated next time you're online" = "Stats will be updated next time you're online"; +/* Title for Comments count in Latest Post Summary stats card. */ +"stats.insights.latestPostSummary.comments" = "Comments"; + +/* Title for Likes count in Latest Post Summary stats card. */ +"stats.insights.latestPostSummary.likes" = "Likes"; + +/* Publish date of a post displayed in Stats. Placeholder will be replaced with a localized relative time, e.g. 2 days ago */ +"stats.insights.latestPostSummary.publishDate" = "Published %@"; + +/* Title for Views count in Latest Post Summary stats card. */ +"stats.insights.latestPostSummary.views" = "Views"; + +/* Insights 'Most Popular Time' header. Fire emoji should remain part of the string. */ +"stats.insights.mostPopularCard.title" = "🔥 Most Popular Time"; + +/* Label showing the percentage of views to a user's site which fall on a particular day. */ +"stats.insights.mostPopularCard.viewPercentage" = "%d%% of views"; + /* The status of the post. Should be the same as in core WP. */ "Status" = "Status"; /* Title of the first alert preparing users to grant permission for us to send them push notifications. */ "Stay in the loop" = "Stay in the loop"; +/* Subtitle giving the user more context about why to enable notifications. */ +"Stay in touch with like and comment notifications." = "Stay in touch with like and comment notifications."; + +/* Subtitle giving the user more context about why to enable notifications. */ +"Stay in touch with your audience with like and comment notifications." = "Stay in touch with your audience with like and comment notifications."; + +/* Title of button that asks the users if they'd like to focus on checking their sites stats */ +"Staying up to date with notifications" = "Staying up to date with notifications"; + /* This is the cell title. */ "Stick post to the front page" = "Stick post to the front page"; @@ -7406,6 +7486,9 @@ /* Accessibility hint for button used to view the user's site */ "Tap to view your site" = "Tap to view your site"; +/* A hint about the completed guided tour. */ +"Task complete." = "Task complete."; + /* Label for the Taxonomy area (categories, keywords, ...) in post settings. */ "Taxonomy" = "Taxonomy"; @@ -7535,9 +7618,6 @@ /* Message displayed in popup when user tries to copy a post with conflicts */ "The post you are trying to copy has two versions that are in conflict or you recently made changes but didn\'t save them.\nEdit the post first to resolve any conflict or proceed with copying the version from this app." = "The post you are trying to copy has two versions that are in conflict or you recently made changes but didn\'t save them.\nEdit the post first to resolve any conflict or proceed with copying the version from this app."; -/* Description shown in alert to confirm skipping all quick start items */ -"The quick start tour will guide you through building a basic site. Are you sure you want to skip? " = "The quick start tour will guide you through building a basic site. Are you sure you want to skip? "; - /* A failure reason for when the request couldn't be serialized. */ "The serialization of the request failed." = "The serialization of the request failed."; @@ -8057,6 +8137,9 @@ Customize Insights button title */ "Try it now" = "Try it now"; +/* A step in a guided tour for quick start. %@ will be the name of the item to select. */ +"Try selecting %@ to add topics you like." = "Try selecting %@ to add topics you like."; + /* The title of a notice telling users that the classic editor is deprecated and will be removed in a future version of the app. */ "Try the new Block Editor" = "Try the new Block Editor"; @@ -8277,6 +8360,7 @@ Button title. Reverts a comment moderation action. Button title. Reverts the previous notification operation Revert an operation + Revert enabling notification after successfully subcribing to the comments for the post. The title of an 'undo' button. Tapping the button moves a trashed page out of the trash folder. The title of an 'undo' button. Tapping the button moves a trashed post out of the trash folder. Undo action */ @@ -8290,10 +8374,10 @@ "Unfollow %@" = "Unfollow %@"; /* Title for a button that unsubscribes the user from the post. */ -"Unfollow conversation" = "Unfollow conversation"; +"Unfollow Conversation" = "Unfollow Conversation"; /* Verb. Button title. The user is following the comments on a post. */ -"Unfollow conversation by email" = "Unfollow conversation by email"; +"Unfollow conversation" = "Unfollow conversation"; /* Verb. An option to unfollow a site. */ "Unfollow site" = "Unfollow site"; @@ -8487,6 +8571,9 @@ /* Use the current image */ "Use" = "Use"; +/* A step in a guided tour for quick start. %@ will be the name of the item to select. */ +"Use %@ to find sites and tags." = "Use %@ to find sites and tags."; + /* Option to enable the block editor for new posts */ "Use block editor" = "Use block editor"; @@ -8496,9 +8583,6 @@ /* Title of a row displayed on the debug screen used to configure the sandbox store use in the App. */ "Use Sandbox Store" = "Use Sandbox Store"; -/* Footer text for Invite Links section of the Invite People screen. */ -"invite_people_invite_link_footer" = "Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted people."; - /* No comment provided by engineer. */ "Use this site" = "Use this site"; @@ -8615,8 +8699,7 @@ /* Button label for viewing a post */ "View Post" = "View Post"; -/* Action title. Opens the user's site in an in-app browser - The menu item to select during a guided tour. */ +/* Action title. Opens the user's site in an in-app browser */ "View Site" = "View Site"; /* Description for view count. Singular. */ @@ -8657,6 +8740,9 @@ /* A call to action to visit the specified blog. The '%@' characters are a placholder for the blog name. */ "Visit %@ for more" = "Visit %@ for more"; +/* Text of a button that links to the VaultPress dashboard. */ +"Visit Dashboard" = "Visit Dashboard"; + /* Portion of a message for Jetpack users that have multisite WP installation, thus Restore is not available. This part is a link, colored with a different color. */ "visit our documentation page" = "visit our documentation page"; @@ -9278,6 +9364,9 @@ /* Writing & Poetry site intent topic */ "Writing & Poetry" = "Writing & Poetry"; +/* Title of button that asks the users if they'd like to focus on checking their sites stats */ +"Writing blog posts" = "Writing blog posts"; + /* No comment provided by engineer. */ "X-Axis Position" = "X-Axis Position"; @@ -9434,6 +9523,9 @@ /* Body of alert prompting users to verify their accounts while attempting to publish */ "You need to verify your account before you can publish a post.\nDon’t worry, your post is safe and will be saved as a draft." = "You need to verify your account before you can publish a post.\nDon’t worry, your post is safe and will be saved as a draft."; +/* Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text. */ +"You received *50 likes* on your comment" = "You received *50 likes* on your comment"; + /* Example Likes notification displayed in the prologue carousel of the app. Number of likes should marked with * characters and will be displayed as bold text. */ "You received *50 likes* on your site today" = "You received *50 likes* on your site today"; @@ -9459,6 +9551,10 @@ /* Blogging Reminders description confirming a user's choices. The placeholder will be replaced at runtime with a day of the week. The HTML markup is used to bold the word 'once'. */ "You'll get a reminder to blog once a week on %@ at %@." = "You'll get a reminder to blog once a week on %1$@ at %2$@."; +/* Message for the action with opt-out revert action. + The app successfully subscribed to the comments for the post */ +"You'll get notifications in the app" = "You'll get notifications in the app"; + /* Blogging Reminders description confirming a user's choices. The first placeholder will be populated with a count of the number of times a week they'll be reminded. The second will be a formatted list of days. For example: 'You'll get reminders to blog 2 times a week on Monday and Tuesday. */ "You'll get reminders to blog %@ times a week on %@." = "You'll get reminders to blog %1$@ times a week on %2$@."; @@ -9531,6 +9627,12 @@ /* Body text of alert helping users understand their site address */ "Your site address appears in the bar at the top of the screen when you visit your site in Safari." = "Your site address appears in the bar at the top of the screen when you visit your site in Safari."; +/* Description for label when the user has a site with VaultPress. */ +"Your site already is protected by VaultPress. You can find a link to your VaultPress dashboard below." = "Your site already is protected by VaultPress. You can find a link to your VaultPress dashboard below."; + +/* Example notification content displayed on the Enable Notifications prompt that is personalized based on a users selection. Words marked between * characters will be displayed as bold text. */ +"Your site appears to be getting *more traffic* than usual!" = "Your site appears to be getting *more traffic* than usual!"; + /* Header of the domains list section in the Domains Dashboard. */ "Your Site Domains" = "Your Site Domains"; @@ -9543,6 +9645,9 @@ /* Title of a message displayed when a site has finished rewinding */ "Your site has been succesfully restored" = "Your site has been succesfully restored"; +/* Title for label when the user has VaultPress enabled. */ +"Your site has VaultPress" = "Your site has VaultPress"; + /* The item to select during a guided tour. */ "Your Site Icon" = "Your Site Icon"; diff --git a/WordPress/Resources/es.lproj/Localizable.strings b/WordPress/Resources/es.lproj/Localizable.strings index da2a84987e1c..0a4dacc77795 100644 --- a/WordPress/Resources/es.lproj/Localizable.strings +++ b/WordPress/Resources/es.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-19 11:48:58+0000 */ +/* Translation-Revision-Date: 2022-04-23 07:16:06+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: es */ @@ -8387,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Usar botón de icono"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Usa este enlace para incorporar a los miembros de tu equipo sin tener que invitarlos uno por uno. Cualquiera que visite esta URL podrá registrarse en tu organización, incluso si ha recibido el enlace de alguien, así que, asegúrate de que lo compartes con personas de confianza."; - /* No comment provided by engineer. */ "Use this site" = "Usar este sitio"; @@ -9497,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Para añadir fotos o vídeos en tus entradas."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Utiliza este enlace para embarcar a los miembros de tu equipo sin tener que invitarlos uno a uno. Cualquiera que visite esta URL podrá registrarse en tu organización, aunque haya recibido el enlace de otra persona, así que asegúrate de que lo compartes con gente de confianza."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Guardar como borrador"; diff --git a/WordPress/Resources/fr.lproj/Localizable.strings b/WordPress/Resources/fr.lproj/Localizable.strings index 87a305e13090..63f18a30a5f7 100644 --- a/WordPress/Resources/fr.lproj/Localizable.strings +++ b/WordPress/Resources/fr.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-08 15:54:08+0000 */ +/* Translation-Revision-Date: 2022-04-25 14:20:00+0000 */ /* Plural-Forms: nplurals=2; plural=n > 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: fr */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d mentions J’aime"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d réponse"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d réponses"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "%1$d sur %2$d terminée"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "Un fichier contient un modèle de code malveillant"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "Un nom court et facile à retenir est la clé du succès.\nVous pourrez toujours le modifier ultérieurement."; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "Une nouvelle façon de publier du contenu attrayant sur votre site."; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "Ajouter un bloc avant"; +/* No comment provided by engineer. */ +"Add Blocks" = "Ajouter des blocs"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "Ajouter le contenu dans l’article"; @@ -621,6 +633,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "Avancé"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "Après %@"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -778,6 +793,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "Anonyme"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "Répondre à l’incitation"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "Icône de l’app"; @@ -1039,6 +1057,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "Beauté"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "Avant %@"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "Meilleur jour"; @@ -1294,6 +1315,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "Attention !"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "Produisez le film de votre vie."; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "Catégories"; @@ -1401,6 +1425,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "Vérification des achats…"; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "Enfant de %@"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "Choisir"; @@ -1440,6 +1467,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "Choisir une heure"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "Choisissez un thème dans la liste ci-dessous ou saisissez-le manuellement."; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "Choisir une favicône unique"; @@ -2450,6 +2480,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "Toucher deux fois et maintenir le bouton enfoncé pour modifier"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "Touchez deux fois et maintenez pour déplacer cet élément de menu vers le haut ou vers le bas. Déplacez cet élément horizontalement pour modifier la hiérarchie."; + /* No comment provided by engineer. */ "Double tap to add a block" = "Toucher deux fois pour ajouter un bloc"; @@ -3372,6 +3405,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "Donnez à votre site un nom qui reflète sa personnalité et le sujet qu’il aborde. La première impression compte !"; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "Donnez un nom à votre site Web"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "Donnez un nom à votre site Web %@"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3769,6 +3809,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "L’installation d’une première extension sur votre site peut prendre jusqu'à une minute. Pendant ce temps, vous ne pourrez effectuer aucun changement à votre site."; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "Vous souhaitez gagner en popularité ? Consultez nos meilleurs conseils "; + /* Interior Design site intent topic */ "Interior Design" = "Décoration d’intérieur"; @@ -4456,6 +4499,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "Heure la plus populaire"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "Déplacer %@"; + /* No comment provided by engineer. */ "Move Image Backward" = "Déplacer l’image vers l’arrière"; @@ -5714,6 +5760,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "Projets"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "Incitations"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "Public"; @@ -5957,6 +6006,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "Retirer le bloc"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "Supprimer du tableau de bord"; + /* Option to remove Insight from view. */ "Remove from insights" = "Retirer des thématiques"; @@ -6850,6 +6902,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "Passer le démarrage rapide"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "Ignorer cette incitation"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "Résultats de l’outil d’insertion de barre oblique"; @@ -8329,9 +8384,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Utiliser le bouton d’icône"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Utilisez ce lien pour ajouter les membres de votre équipe sans avoir à les inviter individuellement. Toute personne ayant accès à ce lien sera en mesure de rejoindre votre organisation, même si le lien a été envoyé par quelqu’un d’autre que vous. Faites attention à le partager uniquement à des personnes de confiance."; - /* No comment provided by engineer. */ "Use this site" = "Utiliser ce site"; @@ -8443,6 +8495,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "Voir plus"; +/* Menu title to show more prompts. */ +"View more prompts" = "Afficher plus d’incitations"; + /* Description for view count. Singular. */ "View to your site so far" = "vue sur votre site jusqu’à présent"; @@ -9436,6 +9491,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Pour ajouter des photos ou des vidéos à vos articles."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Utilisez ce lien pour ajouter les membres de votre équipe sans avoir à les inviter individuellement. Toute personne ayant accès à ce lien sera en mesure de rejoindre votre organisation, même si le lien a été envoyé par quelqu’un d’autre que vous. Veillez à le partager uniquement avec des personnes de confiance."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Enregistrer comme brouillon"; @@ -9607,3 +9665,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "• Utilisateurs et auteurs"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ Vous avez répondu"; + diff --git a/WordPress/Resources/he.lproj/Localizable.strings b/WordPress/Resources/he.lproj/Localizable.strings index 0a9d3c880674..dd17f48cef3b 100644 --- a/WordPress/Resources/he.lproj/Localizable.strings +++ b/WordPress/Resources/he.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-20 17:54:08+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:15:04+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: he_IL */ @@ -8387,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "הכפתור 'להשתמש בסמל'"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "ניתן להשתמש בקישור זה כדי להזמין את כל חברי הצוות שלך במקביל, במקום לשלוח הזמנות אישיות. לכל אדם שמבקר בכתובת ה-URL הזאת תהיה אפשרות להירשם לארגון שלך, גם אם הוא מקבל את הקישור מאדם אחר ולכן, חשוב לוודא שהקישור נשלח לאנשים מהימנים בלבד."; - /* No comment provided by engineer. */ "Use this site" = "שימוש באתר זה"; @@ -9497,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "להוסיף תמונות או סרטוני וידאו לפוסטים."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "ניתן להשתמש בקישור זה כדי להזמין את כל חברי הצוות שלך במקביל, במקום לשלוח הזמנות אישיות. לכל אדם שמבקר בכתובת ה-URL הזאת תהיה אפשרות להירשם לארגון שלך, גם אם הוא מקבל את הקישור מאדם אחר ולכן, חשוב לוודא שהקישור נשלח לאנשים מהימנים בלבד."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "לשמור כטיוטה"; diff --git a/WordPress/Resources/id.lproj/Localizable.strings b/WordPress/Resources/id.lproj/Localizable.strings index 610d427e6a45..b95a3c89218a 100644 --- a/WordPress/Resources/id.lproj/Localizable.strings +++ b/WordPress/Resources/id.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-19 14:58:38+0000 */ +/* Translation-Revision-Date: 2022-04-22 12:27:46+0000 */ /* Plural-Forms: nplurals=2; plural=n > 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: id */ @@ -8387,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Gunakan tombol ikon"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Gunakan tautan ini untuk mendaftarkan anggota tim Anda tanpa harus mengundang mereka satu per satu. Siapa pun yang mengunjungi URL berikut akan dapat mendaftar ke organisasi Anda meskipun mereka menerima tautan dari orang lain, jadi pastikan Anda membagikannya dengan orang tepercaya."; - /* No comment provided by engineer. */ "Use this site" = "Gunakan situs ini"; @@ -9497,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Untuk menambahkan foto atau video ke artikel Anda."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Gunakan tautan ini untuk mendaftarkan anggota tim Anda tanpa harus mengundang mereka satu per satu. Siapa pun yang mengunjungi URL berikut akan dapat mendaftar ke organisasi Anda, meski pun mereka menerima tautan dari orang lain, jadi pastikan Anda membagikannya dengan orang tepercaya."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Simpan sebagai Konsep"; diff --git a/WordPress/Resources/it.lproj/Localizable.strings b/WordPress/Resources/it.lproj/Localizable.strings index 5d07d6e48aff..26783e8ae87d 100644 --- a/WordPress/Resources/it.lproj/Localizable.strings +++ b/WordPress/Resources/it.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-08 09:54:09+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:20:14+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: it */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d Mi piace"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d risposta"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d risposte"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "%1$d di %2$d completati"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "Un file contiene un modello di codice dannoso"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "Un buon nome è breve e indimenticabile.\nPuoi modificarlo in seguito."; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "Un nuovo modo di creare e pubblicare contenuti coinvolgenti sul tuo sito."; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "Aggiungi blocco prima"; +/* No comment provided by engineer. */ +"Add Blocks" = "Aggiungi blocchi"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "Aggiungi contenuti all'articolo"; @@ -621,6 +633,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "Avanzate"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "Dopo di %@"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -778,6 +793,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "Anonimo"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "Rispondi alla richiesta"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "Icona app"; @@ -1039,6 +1057,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "Bellezza"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "Prima di %@"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "Giorno migliore"; @@ -1294,6 +1315,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "Stai attento!"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "Trasmetti il film della tua vita."; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "Categorie"; @@ -1401,6 +1425,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "Ricerca di elementi acqistati in corso ..."; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "Secondario di %@"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "Scegli"; @@ -1440,6 +1467,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "Scegli un'ora"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "Scegli un argomento dall'elenco sottostante o digitane uno tuo."; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "Scegli un'icona del sito univoca"; @@ -2450,6 +2480,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "Tocca due volte e tieni premuto per modificare"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "Tocca due volte e tieni premuto per spostare questo elemento del menu in alto o in basso. Sposta in orizzontale per modificare la gerarchia."; + /* No comment provided by engineer. */ "Double tap to add a block" = "Tocca due volte per aggiungere un blocco"; @@ -2582,6 +2615,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Duplicate block" = "Duplica il blocco"; +/* Placeholder text for the search field int the Site Intent screen. */ +"E.g. Fashion, Poetry, Politics" = "Ad esempio Moda, poesia, politica"; + /* No comment provided by engineer. */ "Each block has its own settings. To find them, tap on a block. Its settings will appear on the toolbar at the bottom of the screen." = "Ogni blocco ha le proprie impostazioni. Per trovarle tocca il blocco. Verranno visualizzate le impostazioni nella barra degli strumenti nella parte inferiore dello schermo."; @@ -3372,6 +3408,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "Dai al tuo sito un nome che rifletta la tua personalità e l'argomento. La prima impressione conta."; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "Dai al tuo sito web un nome"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "Dai al tuo%@sito web un nome"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3769,6 +3812,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "L'installazione del primo plugin sul tuo sito può richiedere fino a 1 minuto. In questo periodo di tempo non potrai apportare modifiche al sito."; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "Interessato a creare il tuo pubblico? Dai un'occhiata ai nostri migliori suggerimenti"; + /* Interior Design site intent topic */ "Interior Design" = "Design d'interni"; @@ -4456,6 +4502,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "Orari più popolari"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "Sposta %@"; + /* No comment provided by engineer. */ "Move Image Backward" = "Sposta indietro l'immagine"; @@ -5714,6 +5763,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "Progetti"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "Richieste"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "Pubblico"; @@ -5957,6 +6009,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "Rimuovi il blocco"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "Rimuovi dalla bacheca"; + /* Option to remove Insight from view. */ "Remove from insights" = "Rimuovi dalla panoramica"; @@ -6850,6 +6905,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "Salta il tour iniziale"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "Salta questa richiesta"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "Risultati dello strumento per l'inserimento della barra"; @@ -8329,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Usa pulsante icona"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Usa questo link per accettare i membri del team senza doverli invitare uno per uno. Chiunque visiti questo URL potrà iscriversi alla tua organizzazione, anche se ha ricevuto un link da qualcun altro, quindi assicurati di condividerlo con le persone fidate."; - /* No comment provided by engineer. */ "Use this site" = "Utilizza questo sito"; @@ -8443,6 +8498,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "Visualizza altro"; +/* Menu title to show more prompts. */ +"View more prompts" = "Visualizza più richieste"; + /* Description for view count. Singular. */ "View to your site so far" = "Visualizzazione del tuo sito finora"; @@ -9436,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Per aggiungere foto o video ai tuoi articoli."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Usa questo link per accettare i membri del team senza doverli invitare uno per uno. Chiunque visiti questo URL potrà iscriversi alla tua organizzazione, anche se ha ricevuto un link da qualcun altro, quindi assicurati di condividerlo con le persone fidate."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Salva come bozza"; @@ -9607,3 +9668,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "• Utenti e autori"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ Risposta"; + diff --git a/WordPress/Resources/ja.lproj/Localizable.strings b/WordPress/Resources/ja.lproj/Localizable.strings index bb70b9acd055..4281374a6d5d 100644 --- a/WordPress/Resources/ja.lproj/Localizable.strings +++ b/WordPress/Resources/ja.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-08 09:54:09+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:16:59+0000 */ /* Plural-Forms: nplurals=1; plural=0; */ /* Generator: GlotPress/3.0.0 */ /* Language: ja_JP */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d個の「いいね」"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d件の回答"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d件の回答"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "%1$d\/%2$d が完了"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "ファイルには、悪意のあるコードが含まれています"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "良い名前は短く、簡単に覚えられるものです。\nテーマは後で変更できます。"; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "心をつかむコンテンツを作り、サイトで公開する新しい方法。"; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "前にブロックを追加"; +/* No comment provided by engineer. */ +"Add Blocks" = "ブロックを追加"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "コンテンツを投稿に追加"; @@ -621,6 +633,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "上級者モード"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "%@の後"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -778,6 +793,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "匿名"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "回答のプロンプト"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "アプリアイコン"; @@ -1039,6 +1057,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "美容"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "%@の前"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "最高記録日"; @@ -1294,6 +1315,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "ご注意ください。"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "あなたの人生の映画をキャスティングしましょう。"; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "カテゴリー"; @@ -1401,6 +1425,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "購入を確認中…"; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "%@の子"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "選択"; @@ -1440,6 +1467,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "時間を選択"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "以下のリストからテーマを選択するか、自分で入力します。"; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "独自のサイトアイコンを選択する"; @@ -2450,6 +2480,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "ダブルタップと長押しで編集"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "このメニュー項目を上下に移動するにはダブルタップして長押ししてください。 水平方向に移動して階層を変更します。"; + /* No comment provided by engineer. */ "Double tap to add a block" = "ダブルタップしてブロックを追加"; @@ -2582,6 +2615,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Duplicate block" = "ブロックを複製"; +/* Placeholder text for the search field int the Site Intent screen. */ +"E.g. Fashion, Poetry, Politics" = "例: ファッション、詩、政治"; + /* No comment provided by engineer. */ "Each block has its own settings. To find them, tap on a block. Its settings will appear on the toolbar at the bottom of the screen." = "各ブロックには独自の設定があります。 確認するには、ブロックをタップします。 画面下部にあるツールバーに設定が表示されます。"; @@ -3372,6 +3408,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "サイトにその特徴とトピックがわかるような名前を付けてください。 第一印象が大事です。"; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "サイトに名前を付けてください"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "%@ サイトに名前を付けてください"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3769,6 +3812,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "サイトに最初のプラグインをインストールするには最長で1分かかる場合があります。その間、サイトへの変更は行うことができなくなります。"; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "読者を増やしたいとお考えですか ? トップのヒントをご覧ください。"; + /* Interior Design site intent topic */ "Interior Design" = "インテリアデザイン"; @@ -4456,6 +4502,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "最も人気のある時間"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "%@を移動する"; + /* No comment provided by engineer. */ "Move Image Backward" = "画像を後ろに移動"; @@ -5714,6 +5763,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "プロジェクト"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "プロンプト"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "公開"; @@ -5957,6 +6009,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "ブロックを削除"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "ダッシュボードから削除"; + /* Option to remove Insight from view. */ "Remove from insights" = "統計概要から削除"; @@ -6850,6 +6905,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "クイックスタートをスキップ"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "このプロンプトをスキップ"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "スラッシュインサーターの結果"; @@ -8329,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "アイコンボタンを使用"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "このリンクを使用すると、チームメンバーを1人ずつではなく一括で招待できます。 この URL にアクセスすると、だれでも組織に登録されます。リンクをだれから受け取ったかは関係ないため、信頼できる人と共有するようにしてください。"; - /* No comment provided by engineer. */ "Use this site" = "このサイトを使用"; @@ -8443,6 +8498,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "さらに表示"; +/* Menu title to show more prompts. */ +"View more prompts" = "プロンプトをさらに表示"; + /* Description for view count. Singular. */ "View to your site so far" = "件のこれまでのサイトの閲覧数"; @@ -9436,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "投稿に写真または動画を追加する。"; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "このリンクを使用すると、チームメンバーを1人ずつではなく一括で招待できます。 この URL にアクセスすると、だれでも組織に登録されます。リンクをだれから受け取ったかは関係ないため、信頼できる人と共有するようにしてください。"; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "下書きとして保存"; @@ -9607,3 +9668,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "•ユーザーと投稿者"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓回答済み"; + diff --git a/WordPress/Resources/ko.lproj/Localizable.strings b/WordPress/Resources/ko.lproj/Localizable.strings index cd6ac0d379e1..4769eb624a68 100644 --- a/WordPress/Resources/ko.lproj/Localizable.strings +++ b/WordPress/Resources/ko.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-08 13:54:09+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:44:22+0000 */ /* Plural-Forms: nplurals=1; plural=0; */ /* Generator: GlotPress/3.0.0 */ /* Language: ko_KR */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "좋아요 %1$d개 "; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d개 답변"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d개 답변"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "%1$d\/%2$d 완료됨"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "파일에 악성 코드 패턴이 있음"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "좋은 이름은 짧고 인상적입니다.\n나중에 변경할 수 있습니다."; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "사이트에서 매력적인 콘텐츠를 만들고 공개하는 새로운 방법입니다."; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "다음 블록 이전에 추가하기"; +/* No comment provided by engineer. */ +"Add Blocks" = "블록 추가"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "글에 콘텐츠 추가"; @@ -618,6 +630,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "고급"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "%@ 뒤"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "에어메일"; @@ -772,6 +787,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "익명"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "답변 프롬프트"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "앱 아이콘"; @@ -799,6 +817,9 @@ translators: Block name. %s: The localized block name */ Verb. Approves a 2fa authentication challenge, and logs in a user. */ "Approve" = "승인"; +/* Approves a Comment */ +"Approve Comment" = "댓글 승인"; + /* Button title for Approved comment state. Title of approved Comments filter. */ "Approved" = "승인"; @@ -1030,6 +1051,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "미용"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "%@ 앞"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "안녕히 계세요."; @@ -1285,6 +1309,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "조심하세요!"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "자신의 인생을 영화로 만들어 보세요."; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "카테고리"; @@ -1389,6 +1416,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "구매 확인 중…"; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "%@의 하위"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "선택하기"; @@ -1428,6 +1458,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "시간을 선택하세요."; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "아래 목록에서 테마를 선택하거나 원하는 테마를 입력하세요."; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "고유한 사이트 아이콘 선택"; @@ -2438,6 +2471,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "편집하려면 두 번 탭하고 길게 누르세요."; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "이 메뉴 항목을 위 또는 아래로 이동하려면 두 번 누르고 유지합니다. 계층구조를 변경하려면 가로 방향으로 이동합니다."; + /* No comment provided by engineer. */ "Double tap to add a block" = "블록을 추가하려면 두 번 탭하세요."; @@ -3360,6 +3396,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "개성과 주제를 반영하는 사이트 제목을 주십시오. 첫 인상이 많은 부분을 차지합니다!"; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "웹사이트 이름 지정"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "%@ 웹사이트 이름 지정"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "지메일"; @@ -3757,6 +3800,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "첫 번째 플러그인을 사이트에 설치하는 데에는 최대 1분이 소요될 수 있습니다. 이 시간 동안은 사이트를 변경할 수 없습니다."; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "잠재 고객을 확보하는 데 관심이 있으신가요? 최고의 팁 확인"; + /* Interior Design site intent topic */ "Interior Design" = "인테리어 디자인"; @@ -4444,6 +4490,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "가장 인기 있는 시간"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "%@ 이동"; + /* No comment provided by engineer. */ "Move Image Backward" = "이미지를 뒤로 이동"; @@ -5699,6 +5748,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "프로젝트"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "프롬프트"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "공개"; @@ -5942,6 +5994,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "블록 제거하기"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "알림판에서 제거"; + /* Option to remove Insight from view. */ "Remove from insights" = "인사이트에서 제거"; @@ -6835,6 +6890,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "퀵 스타트 건너뛰기"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "이 프롬프트 건너뛰기"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "슬래시 삽입기 결과"; @@ -8087,6 +8145,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Unapproves a comment */ "Unapprove" = "비승인"; +/* Unapproves a Comment */ +"Unapprove Comment" = "댓글 미승인"; + /* VoiceOver accessibility hint, informing the user the button can be used to unapprove a comment */ "Unapproves the Comment." = "댓글을 승인하지 않습니다."; @@ -8311,9 +8372,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "아이콘 버튼 사용"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "이 링크를 활용하면 일일이 한 명씩 초대하지 않아도 여러 팀원이 팀에 참여할 수 있게 됩니다. 이 URL을 방문하는 사람은 누구나 조직에 가입할 수 있습니다. 다른 사람을 통해서 이 링크를 전달받은 사람도 가입할 수 있기 때문에 신뢰할 수 있는 사람에게만 공유하세요."; - /* No comment provided by engineer. */ "Use this site" = "이 사이트 사용"; @@ -8425,6 +8483,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "더 보기"; +/* Menu title to show more prompts. */ +"View more prompts" = "더 많은 프롬프트 보기"; + /* Description for view count. Singular. */ "View to your site so far" = "지금까지 사이트 조회수"; @@ -9418,6 +9479,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "글에 사진이나 비디오를 추가"; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "이 링크를 활용하면 일일이 한 명씩 초대하지 않아도 여러 팀원이 팀에 참여할 수 있게 됩니다. 이 URL을 방문하는 사람은 누구나 조직에 가입할 수 있습니다. 다른 사람을 통해서 이 링크를 전달받은 사람도 가입할 수 있기 때문에 신뢰할 수 있는 사람에게만 공유하세요."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "임시글로 저장"; @@ -9589,3 +9653,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "• 사용자 및 글쓴이"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ 답변됨"; + diff --git a/WordPress/Resources/nl.lproj/Localizable.strings b/WordPress/Resources/nl.lproj/Localizable.strings index c77c9bef9448..1be81acbf0ee 100644 --- a/WordPress/Resources/nl.lproj/Localizable.strings +++ b/WordPress/Resources/nl.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-03-25 13:54:07+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:04:18+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: nl */ @@ -325,13 +325,13 @@ translators: Block name. %s: The localized block name */ "Once<\/strong> a week" = "Een keer<\/strong> per week"; /* Short title telling the user they will receive a blogging reminder once per week. The word for 'once' should be surrounded by HTML tags. */ -"Once<\/strong> a week at %@" = "Een<\/strong> keer per week"; +"Once<\/strong> a week at %@" = "Een<\/strong> keer per week om %@"; /* Short title telling the user they will receive a blogging reminder two times a week. The word for 'twice' should be surrounded by HTML tags. */ "Twice<\/strong> a week" = "Twee keer<\/strong> per week"; /* Short title telling the user they will receive a blogging reminder two times a week. The word for 'twice' should be surrounded by HTML tags. */ -"Twice<\/strong> a week at %@" = "Twee<\/strong> keer per week"; +"Twice<\/strong> a week at %@" = "Twee<\/strong> keer per week om %@"; /* Label displaying the user's username preceeded by an '@' symbol. %1$@ is a placeholder for the username. */ "@%1$@" = "@%1$@"; @@ -1033,6 +1033,9 @@ translators: Block name. %s: The localized block name */ /* Message shown encouraging the user to leave a comment on a post in the reader. */ "Be the first to leave a comment." = "Laat als eerste een reactie achter."; +/* Beauty site intent topic */ +"Beauty" = "Schoonheid"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "Beste dag"; @@ -1119,6 +1122,9 @@ translators: Block name. %s: The localized block name */ Discoverability title for bold formatting keyboard shortcut. */ "Bold" = "Vet"; +/* Books site intent topic */ +"Books" = "Boeken"; + /* No comment provided by engineer. */ "Border Radius" = "Radius rand"; @@ -1428,6 +1434,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "Kies een tijd"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "Kies een onderwerp van de lijst hieronder of typ je eigen"; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "Kies een unieke site pictogram"; @@ -2658,6 +2667,9 @@ translators: Block name. %s: The localized block name */ /* Screen reader hint for button to edit a menu item */ "Edits this menu item" = "Bewerkt dit menu-item"; +/* Education site intent topic */ +"Education" = "Onderwijs"; + /* Accessibility label for the Email text field. Account Settings Email label Email address text field placeholder @@ -3035,6 +3047,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Failed to upload files.\nPlease tap for options." = "Uploaden van bestanden mislukt.\nTik voor opties."; +/* Fashion site intent topic */ +"Fashion" = "Mode"; + /* Option to select the Fastmail app when logging in with magic links */ "Fastmail" = "Fastmail"; @@ -3092,12 +3107,18 @@ translators: Block name. %s: The localized block name */ /* Label for the file type (.JPG, .PNG, etc) for a media asset (image / video) */ "File type" = "Bestandstype"; +/* Film & Television site intent topic */ +"Film & Television" = "Film & televisie"; + /* Title of the filter button in the Reader */ "Filter" = "Filteren"; /* Title of a screen that shows activity types so the user can filter using them (eg.: posts, images, users) */ "Filter by activity type" = "Filter op type activiteit"; +/* Finance site intent topic */ +"Finance" = "Financiën"; + /* Title for the find out more button in the What's New page. */ "Find out more" = "Meer te weten komen"; @@ -3209,6 +3230,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Font Size" = "Lettertype grootte"; +/* Food site intent topic */ +"Food" = "Eten"; + /* An example tag used in the login prologue screens. */ "Football" = "Voetbal"; @@ -3266,6 +3290,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Gallery style" = "Galerij stijl"; +/* Gaming site intent topic */ +"Gaming" = "Games"; + /* An example tag used in the login prologue screens. */ "Gardening" = "Tuinieren"; @@ -3327,6 +3354,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "Geef je site een naam die zijn personaliteit en onderwerp reflecteerd. De eerste indruk telt!"; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "Geef je site een naam"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "Geef je%@site een naam"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3349,6 +3383,10 @@ translators: Block name. %s: The localized block name */ /* Message shown on screen after the Google sign up process failed. */ "Google sign up failed." = "Aanmelden met Google mislukt."; +/* Button title on the blogging prompt's feature introduction view to dismiss the view. + Title for the continue button in the dashboard's custom What's New page. */ +"Got it" = "Ik snap het"; + /* Okay button title shown in alert announcing new Create Button feature. */ "Got it!" = "Begrepen!"; @@ -3441,6 +3479,9 @@ translators: Block name. %s: The localized block name */ /* H6 Aztec Style */ "Heading 6" = "Heading 6"; +/* Health site intent topic */ +"Health" = "Gezondheid"; + /* Help button */ "Help" = "Help"; @@ -4392,6 +4433,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "Populairste tijd"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "Verplaats %@"; + /* No comment provided by engineer. */ "Move Image Backward" = "Verplaats afbeelding naar achteren"; @@ -4482,6 +4526,9 @@ translators: Block name. %s: The localized block name */ /* Example post title used in the login prologue screens. */ "My Top Ten Cafes" = "Mijn toptien cafés"; +/* Title for disclaimer in the dashboard's custom What's New page. */ +"NEW!" = "NIEUW!"; + /* Accessibility label for the Email text field. Header for a comment author's name, shown when editing a comment. Name text field placeholder @@ -4564,6 +4611,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Sort Order */ "Newest first" = "Nieuwste eerst"; +/* News site intent topic */ +"News" = "Nieuws"; + /* Next action on comment moderation snackbar. Next action on share extension editor screen. Next screen button title @@ -5163,6 +5213,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Message informing the user that their pages parent has been set successfully */ "Parent page successfully updated." = "Hoofdpagina met succes geüpdatet."; +/* Parenting site intent topic */ +"Parenting" = "Ouderschap"; + /* Accessibility label for the password text field in the self-hosted login page. Label for entering password in password field Label for the password field. Should be the same as WP core. @@ -5213,12 +5266,18 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Delete Site confirmation action title */ "Permanently Delete Site" = "Verwijder site permanent"; +/* Personal site intent topic */ +"Personal" = "Persoonlijk"; + /* Section title for the personalize table section in the blog details screen. */ "Personalize" = "Personaliseer"; /* Accessibility label for selecting an image or video from the device's photo library on formatting toolbar. */ "Photo Library" = "Fotobibliotheek"; +/* Photography site intent topic */ +"Photography" = "Fotografie"; + /* Tab bar title for the Photos tab in Media Picker */ "Photos" = "Foto's"; @@ -5632,6 +5691,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "Projecten"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "Prompts"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "Openbaar"; @@ -5749,6 +5811,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Title of the screen that allows the user to change the Reader CSS URL for debug builds */ "Reader CSS URL" = "Reader CSS URL"; +/* Real Estate site intent topic */ +"Real Estate" = "Onroerend goed"; + /* Text for the 'Reblog' button. */ "Reblog" = "Herblog"; @@ -5869,6 +5934,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "Verwijder blok"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "Verwijder van dashboard"; + /* Option to remove Insight from view. */ "Remove from insights" = "Verwijderen uit inzichten"; @@ -6756,6 +6824,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "Snelstart overslaan"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "Sla deze prompt over"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "Slash inserter resultaten"; @@ -6879,6 +6950,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Title for the Speed up your site Settings Screen */ "Speed up your site" = "Versnel je site"; +/* Sports site intent topic */ +"Sports" = "Sport"; + /* Standard post format label */ "Standard" = "Standaard"; @@ -7157,6 +7231,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Label for the Taxonomy area (categories, keywords, ...) in post settings. */ "Taxonomy" = "Taxonomie"; +/* Technology site intent topic */ +"Technology" = "Technologie"; + /* My Profile 'About me' hint text */ "Tell us a bit about you." = "Vertel ons iets over jezelf."; @@ -8214,9 +8291,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Gebruik pictogram knop"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Gebruik deze link om je teamleden aan boord te krijgen zonder ze een voor een uit te nodigen. Iedereen die deze URL bezoekt, kan zich aanmelden bij je organisatie, zelfs als ze de link van iemand anders hebben ontvangen, dus zorg ervoor dat je deze deelt met vertrouwde mensen."; - /* No comment provided by engineer. */ "Use this site" = "Gebruik deze site"; @@ -8328,6 +8402,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "Meer weergeven"; +/* Menu title to show more prompts. */ +"View more prompts" = "Bekijk meer prompts"; + /* Description for view count. Singular. */ "View to your site so far" = "Bekijk je site tot zover"; @@ -9291,6 +9368,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Text for related post cell preview */ "in \"Upgrade\"" = "in \"Upgrade\""; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Gebruik deze link om je teamleden aan boord te krijgen zonder ze een voor een uit te nodigen. Iedereen die deze URL bezoekt, kan zich aanmelden bij je organisatie, zelfs als ze de link van iemand anders hebben ontvangen, dus zorg ervoor dat je deze deelt met vertrouwde mensen."; + /* Later today */ "later today" = "later vandaag"; @@ -9435,3 +9515,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "• Gebruikers en auteurs"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ Beantwoord"; + diff --git a/WordPress/Resources/pl.lproj/Localizable.strings b/WordPress/Resources/pl.lproj/Localizable.strings index cf1de2b74652..3c96b263a084 100644 --- a/WordPress/Resources/pl.lproj/Localizable.strings +++ b/WordPress/Resources/pl.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-04 06:09:00+0000 */ +/* Translation-Revision-Date: 2022-04-22 06:43:25+0000 */ /* Plural-Forms: nplurals=3; plural=(n == 1) ? 0 : ((n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) ? 1 : 2); */ /* Generator: GlotPress/3.0.0 */ /* Language: pl */ @@ -344,7 +344,7 @@ "OK" = "OK"; /* Disabled */ -"Off" = "Wyłączone"; +"Off" = "Wyłączono"; /* An informal exclaimation that means `something went wrong`. Title for the view when there's an error loading a comment. diff --git a/WordPress/Resources/pt-BR.lproj/Localizable.strings b/WordPress/Resources/pt-BR.lproj/Localizable.strings index 2ba86483898b..2251d7463336 100644 --- a/WordPress/Resources/pt-BR.lproj/Localizable.strings +++ b/WordPress/Resources/pt-BR.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-12 18:22:19+0000 */ +/* Translation-Revision-Date: 2022-04-28 18:04:17+0000 */ /* Plural-Forms: nplurals=2; plural=n > 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: pt_BR */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d curtidas"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d resposta"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d respostas"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "%1$d de %2$d concluídas"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "Um arquivo contém um padrão de código malicioso"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "Um bom nome é curto e fácil de lembrar.\nVocê pode mudar isso depois."; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "Uma nova maneira de criar e publicar conteúdos atraentes em seu site."; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "Adicionar bloco antes"; +/* No comment provided by engineer. */ +"Add Blocks" = "Adicionar blocos"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "Adicionar conteúdo ao post"; @@ -621,6 +633,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "Avançado"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "Após %s"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -778,6 +793,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "Anônimo"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "Responder sugestão"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "Ícone do aplicativo"; @@ -1039,6 +1057,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "Beleza"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "Antes de %@"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "Melhor dia"; @@ -1294,6 +1315,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "Cuidado!"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "Faça o filme da sua vida."; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "Categorias"; @@ -1401,6 +1425,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "Verificando compras..."; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "Descendente de %@"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "Escolher"; @@ -1440,6 +1467,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "Escolha um horário"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "Escolha um assunto na lista abaixo ou digite o seu próprio"; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "Escolher um ícone de site exclusivo"; @@ -2450,6 +2480,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "Toque duas vezes e segure para editar"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "Toque duas vezes e segure para mover este item de menu para cima ou para baixo. Mova horizontalmente para mudar a hierarquia."; + /* No comment provided by engineer. */ "Double tap to add a block" = "Toque duas vezes para adicionar um bloco"; @@ -2582,6 +2615,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Duplicate block" = "Duplicar bloco"; +/* Placeholder text for the search field int the Site Intent screen. */ +"E.g. Fashion, Poetry, Politics" = "Ex.: moda, poesia, política"; + /* No comment provided by engineer. */ "Each block has its own settings. To find them, tap on a block. Its settings will appear on the toolbar at the bottom of the screen." = "Cada bloco possui suas próprias configurações. Para encontrá-las, toque em um bloco. As configurações dele aparecerão na barra de ferramentas na parte inferior da tela."; @@ -3372,6 +3408,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "Dê um nome para seu site que reflita sua personalidade e tópicos que serão publicados. A primeira impressão conta."; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "Dê um nome ao seu site"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "Dê um nome ao site %@"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3769,6 +3812,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "Instalar o primeiro plugin em seu site pode demorar alguns minutos. Durante esse tempo, não será possível fazer outras alterações no seu site."; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "Quer aumentar seu público? Veja nossas dicas"; + /* Interior Design site intent topic */ "Interior Design" = "Design de interiores"; @@ -4456,6 +4502,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "Horário mais popular"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "Mover %@"; + /* No comment provided by engineer. */ "Move Image Backward" = "Mover imagem para trás"; @@ -5714,6 +5763,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "Projetos"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "Sugestões"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "Público"; @@ -5957,6 +6009,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "Remover bloco"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "Remover do painel"; + /* Option to remove Insight from view. */ "Remove from insights" = "Remover do resumo"; @@ -6850,6 +6905,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "Pular o início rápido"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "Ignorar esta sugestão"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "Resultados do adicionador com barra"; @@ -8329,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Usar ícone de botão"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Use este link para integrar os membros da sua equipe sem ter que convidá-los um por um. Qualquer pessoa que visitar este URL poderá se inscrever em sua organização, mesmo que tenha recebido o link de outra pessoa, então certifique-se de compartilhá-lo com pessoas de confiança."; - /* No comment provided by engineer. */ "Use this site" = "Usar este site"; @@ -8443,6 +8498,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "Ver mais"; +/* Menu title to show more prompts. */ +"View more prompts" = "Ver mais sugestões"; + /* Description for view count. Singular. */ "View to your site so far" = "Visualização em seu site até o momento"; @@ -9436,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Para adicionar fotos ou vídeos aos seus posts."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Use este link para integrar os membros da sua equipe sem ter que convidá-los um por um. Qualquer pessoa que visitar este URL poderá se inscrever em sua organização, mesmo que tenha recebido o link de outra pessoa, então certifique-se de compartilhá-lo com pessoas de confiança."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Salvar como rascunho"; @@ -9607,3 +9668,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "• Usuários e autores"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ Respondida"; + diff --git a/WordPress/Resources/release_notes.txt b/WordPress/Resources/release_notes.txt index 16fdae8901ab..a6adff6aebfd 100644 --- a/WordPress/Resources/release_notes.txt +++ b/WordPress/Resources/release_notes.txt @@ -1,11 +1,13 @@ -We made a small but mighty change to the block editor: the “Add Block” button is more visible when you first open the editor with no blocks selected. We also removed one of three error notifications when a media or audio block fails to upload—it felt like overkill. +* [**] Self hosted sites are not restricted by video length during media uploads [https://github.com/wordpress-mobile/WordPress-iOS/pull/18414] +* [*] [internal] My Site Dashboard: Made some changes to the code architecture of the dashboard. The majority of the changes are related to the posts cards. It should have no visible changes but could cause regressions. Please test it by creating/trashing drafts and scheduled posts and testing that they appear correctly on the dashboard. [#18405] +* [*] Quick Start: Updated the Stats tour. The tour can now be accessed from either the dashboard or the menu tab. [#18413] +* [*] Quick Start: Updated the Reader tour. The tour now highlights the Discover tab and guides users to follow topics via the Settings screen. [#18450] +* [*] [internal] Quick Start: Deleted the Edit your homepage tour. [#18469] +* [*] [internal] Quick Start: Refactored some code related to the tasks displayed in the Quick Start Card and the Quick Start modal. It should have no visible changes but could cause regressions. [#18395] +* [**] Follow Conversation flow now enables in-app notifications by default. They were updated to be opt-out rather than opt-in. [#18449] +* [*] Block Editor: Latest Posts block: Add featured image settings [https://github.com/WordPress/gutenberg/pull/39257] +* [*] Block Editor: Prevent incorrect notices displaying when switching between HTML-Visual mode quickly [https://github.com/WordPress/gutenberg/pull/40415] +* [*] Block Editor: Embed block: Fix inline preview cut-off when editing URL [https://github.com/WordPress/gutenberg/pull/35326] +* [*] Block Editor: Prevent gaps shown around floating toolbar when using external keyboard [https://github.com/WordPress/gutenberg/pull/40266] +* [**] We'll now ask users logging in which area of the app they'd like to focus on to build towards a more personalized experience. [#18385] -You’ll hear some accessibility tweaks in the VoiceOver experience when you’re rearranging menu items. Instructions and notices are clearer, and the menu hierarchy makes more sense out loud. - -We added a new screen to the site creation process where you can enter your site’s intent. We tested this screen with a small group of users, and we think you’ll like it, too. - -Web previews won’t cut off bottom-of-the-screen notifications when your browser toolbar is visible. - -What’s in a name? Well, if your site has one, you’ll see it in the My Site navigation title. - -When you swipe left on a comment in your Notifications, you won’t see the “Trash” option anymore. Instead you’ll see “Unapprove Comment” and “Approve Comment.” We approve. diff --git a/WordPress/Resources/ro.lproj/Localizable.strings b/WordPress/Resources/ro.lproj/Localizable.strings index 861e8bd2926b..8d31a02d03f0 100644 --- a/WordPress/Resources/ro.lproj/Localizable.strings +++ b/WordPress/Resources/ro.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-19 05:54:28+0000 */ +/* Translation-Revision-Date: 2022-04-22 13:49:01+0000 */ /* Plural-Forms: nplurals=3; plural=(n == 1) ? 0 : ((n == 0 || n % 100 >= 2 && n % 100 <= 19) ? 1 : 2); */ /* Generator: GlotPress/3.0.0 */ /* Language: ro */ @@ -50,7 +50,7 @@ /* Singular button title to Like a comment. %1$d is a placeholder for the number of Likes. Singular format string for view title displaying the number of post likes. %1$d is the number of likes. */ -"%1$d Like" = "O apreciere"; +"%1$d Like" = "%1$d apreciere"; /* Plural button title to Like a comment. %1$d is a placeholder for the number of Likes. Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ @@ -2682,9 +2682,6 @@ translators: Block name. %s: The localized block name */ /* Title for the edit sharing buttons section */ "Edit sharing buttons" = "Editare butoane de partajare"; -/* Title for the edit sharing buttons section */ -"Edit sharing buttons" = "Editare butoane de partajare"; - /* Button title displayed in popup indicating that the user edits the post first */ "Edit the post first" = "Mai întâi, editează articolul"; @@ -4383,7 +4380,7 @@ translators: Block name. %s: The localized block name */ "Media" = "Media"; /* Label for size of media cache in the app. */ -"Media Cache Size" = " Dimensiune cache media"; +"Media Cache Size" = "Dimensiune cache media"; /* Title for alert when access to media capture is not granted */ "Media Capture" = "Captură media"; @@ -7758,7 +7755,7 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ "Thumbnail" = "Miniatură"; /* Message shown if a thumbnail preview of a media item unavailable. */ -"Thumbnail unavailable." = "Miniatură indisponibilă"; +"Thumbnail unavailable." = "Miniatură indisponibilă."; /* No comment provided by engineer. */ "Tiled gallery settings" = "Setări galerii placate"; @@ -8390,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Folosește butonul icon"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Folosește această legătură pentru a mării numărul de membri din echipa ta fără a fi nevoie să-i inviți individual. Oricine vizitează acest URL va putea să se înscrie în organizația ta, chiar dacă a primit o invitație de la altcineva, deci asigură-te că partajezi legătura cu persoane de încredere."; - /* No comment provided by engineer. */ "Use this site" = "Folosește acest site"; @@ -9415,7 +9409,7 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ "_%1$d bloggers_ like this." = "_%1$d blogeri_ apreciază asta."; /* Describes that the current user and one other user like a post. %1$d is the number of likes, excluding the like by current user. The underscores denote underline and is not displayed. */ -"_You and %1$d blogger_ like this." = "_Tu și un alt bloger_ ați apreciat asta."; +"_You and %1$d blogger_ like this." = "_Tu și %1$d alt bloger_ ați apreciat asta."; /* Plural format string for displaying the number of post likes, including the like from the current user. %1$d is the number of likes, excluding the like by current user. The underscores denote underline and is not displayed. */ "_You and %1$d bloggers_ like this." = "_Tu și alți %1$d blogeri_ ați apreciat asta."; @@ -9500,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Să adaugi poze sau videouri în articolele tale."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Folosește această legătură pentru a mării numărul de membri din echipa ta fără a fi nevoie să-i inviți individual. Oricine vizitează acest URL va putea să se înscrie în organizația ta, chiar dacă a primit o invitație de la altcineva, deci asigură-te că partajezi legătura cu persoane de încredere."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Salvează ca ciornă"; diff --git a/WordPress/Resources/ru.lproj/Localizable.strings b/WordPress/Resources/ru.lproj/Localizable.strings index 59ec378374a1..3096db2add65 100644 --- a/WordPress/Resources/ru.lproj/Localizable.strings +++ b/WordPress/Resources/ru.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-20 15:45:22+0000 */ +/* Translation-Revision-Date: 2022-04-28 14:56:45+0000 */ /* Plural-Forms: nplurals=3; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : ((n % 10 >= 2 && n % 10 <= 4 && (n % 100 < 12 || n % 100 > 14)) ? 1 : 2); */ /* Generator: GlotPress/3.0.0 */ /* Language: ru */ @@ -8387,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Использовать кнопку со значком"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Используйте эту ссылку, чтобы подключить членов вашей команды, не приглашая их по одному. Любой, кто посетит этот URL-адрес, сможет зарегистрироваться в вашей организации, даже если он получил ссылку от кого-то другого, поэтому убедитесь, что вы делитесь ею с доверенными людьми."; - /* No comment provided by engineer. */ "Use this site" = "Использовать этот сайт"; @@ -9497,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Для размещения фотографий и видео в ваших записях."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Используйте эту ссылку, чтобы подключить членов вашей команды, не приглашая их по одному. Любой, кто посетит этот URL-адрес, сможет зарегистрироваться в вашей организации, даже если он получил ссылку от кого-то другого, поэтому убедитесь, что вы делитесь ей с доверенными людьми."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Сохранить как черновик"; diff --git a/WordPress/Resources/sq.lproj/Localizable.strings b/WordPress/Resources/sq.lproj/Localizable.strings index 99a03443dd80..dff51e4103fe 100644 --- a/WordPress/Resources/sq.lproj/Localizable.strings +++ b/WordPress/Resources/sq.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-08 12:47:02+0000 */ +/* Translation-Revision-Date: 2022-04-27 10:59:06+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: sq_AL */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d Pëlqime"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d përgjigje"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d përgjigje"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "%1$d nga %2$d të plotësuara"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "Një kartelë përmban rregullsi kodi dashakeq"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "Një emër i mirë do të ishte i shkurtër dhe që mbahet mend.\nMund ta ndryshoni më vonë."; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "Një rrugë e re për të krijuar dhe botuar lëndë tërheqëse në sajtin tuaj."; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "Shtoni Bllok Para"; +/* No comment provided by engineer. */ +"Add Blocks" = "Shtoni Blloqe"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "Shtoje Lëndën te Postimi"; @@ -621,6 +633,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "Të mëtejshme"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "Pas %@"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -805,6 +820,9 @@ translators: Block name. %s: The localized block name */ Verb. Approves a 2fa authentication challenge, and logs in a user. */ "Approve" = "Miratoje"; +/* Approves a Comment */ +"Approve Comment" = "Miratojeni Komentin"; + /* Button title for Approved comment state. Title of approved Comments filter. */ "Approved" = "U shmiratua"; @@ -1036,6 +1054,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "Bukuri"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "Para %@"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "Dita Më e Mirë"; @@ -1398,6 +1419,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "Po kontrollohen blerjet…"; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "Pjellë e %@"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "Zgjidhni"; @@ -1437,6 +1461,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "Zgjidhni një kohë"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "Zgjidhni një temë nga lista më poshtë, ose shtypni tuajën."; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "Zgjidhni një ikonë sajti unike"; @@ -2444,6 +2471,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "Për përpunim, prekeni dyfish dhe mbajeni të prekur"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "Prekeni dy herë dhe mbajeni të prekur, që ta lëvizni këtë element menuje sipër a poshtë. Që t’i ndryshoni hierarkinë, lëvizeni horizontalisht."; + /* No comment provided by engineer. */ "Double tap to add a block" = "Që të shtoni një bllok, prekeni dy herë"; @@ -2576,6 +2606,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Duplicate block" = "Përsëdyte bllokun"; +/* Placeholder text for the search field int the Site Intent screen. */ +"E.g. Fashion, Poetry, Politics" = "P.sh., Modë, Poezi, Politikë"; + /* No comment provided by engineer. */ "Each block has its own settings. To find them, tap on a block. Its settings will appear on the toolbar at the bottom of the screen." = "Çdo bllok ka rregullimet e veta. Për t’i gjetur, klikoni mbi një bllok. Rregullimet e tij do të shfaqen te paneli në fund të ekranit."; @@ -3363,6 +3396,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "Jepini sajtit tuaj një emër që pasqyron personalitetin dhe subjektin e tij. Përshtypja e parë ka vlerë!"; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "Jepini sajtit tuaj një emër"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "Jepini your%@website një emër"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3760,6 +3800,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "Instalimi i shtojcës së parë në sajtin tuaj mund të hajë deri në 1 minutë. Gjatë kësaj kohe, s’do të jeni në gjendje të bëni ndryshime në sajtin tuaj."; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "Ju intereson të ndërtoni publikun tuaj? Shihni ndihmëzat tona kryesuese?"; + /* Interior Design site intent topic */ "Interior Design" = "Dizajn Mjedisesh të Brendshëm"; @@ -4444,6 +4487,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "Koha Më Popullore"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "Lëvizeni %@"; + /* No comment provided by engineer. */ "Move Image Backward" = "Shpjere Figurën Prapa"; @@ -5942,6 +5988,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "Hiqe bllokun"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "Hiqe nga pulti"; + /* Option to remove Insight from view. */ "Remove from insights" = "Hiqe nga Prirjet"; @@ -8081,6 +8130,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Unapproves a comment */ "Unapprove" = "Shmiratoje"; +/* Unapproves a Comment */ +"Unapprove Comment" = "Shmiratojeni Komentin"; + /* VoiceOver accessibility hint, informing the user the button can be used to unapprove a comment */ "Unapproves the Comment." = "Heq miratimin e Komentit."; @@ -8305,9 +8357,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Përdor buton ikone"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Përdoreni këtë lidhje për hapat e mirëseardhjes për anëtarët e ekipit tuaj, pa u dashur t’i ftoni tek e tek. Gjithkush që viziton këtë URL, do të jetë në gjendje të regjistrohet në entin tuaj, madje edhe nëse lidhjen e marrin nga dikush tjetër, ndaj sigurohuni se ua jepni personave të besuar."; - /* No comment provided by engineer. */ "Use this site" = "Përdor këtë sajt"; @@ -9409,6 +9458,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Që të shtohen foto ose video te postimet tuaja."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Përdoreni këtë lidhje për mirëseardhjen e anëtarëve të ekipit tuaj, pa pasur nevojë t’i ftoni ata tek për tek. Cilido që viziton këtë URL, do të jetë në gjendje të regjistrohet në entin tuaj, madje edhe nëse lidhjen e morën nga dikush tjetër, ndaj kujdesuni t’ua jepni personave të besuar."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Ruaje si Skicë"; @@ -9580,3 +9632,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "• Përdorues & Autorë"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ Me Përgjigje"; + diff --git a/WordPress/Resources/sv.lproj/Localizable.strings b/WordPress/Resources/sv.lproj/Localizable.strings index e1df01f1c952..ade098667e77 100644 --- a/WordPress/Resources/sv.lproj/Localizable.strings +++ b/WordPress/Resources/sv.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-18 23:18:45+0000 */ +/* Translation-Revision-Date: 2022-04-23 13:27:35+0000 */ /* Plural-Forms: nplurals=2; plural=n != 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: sv_SE */ @@ -1315,6 +1315,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "Var försiktig!"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "Cast the movie of your life."; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "Kategorier"; @@ -1422,6 +1425,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "Kontrollerar inköp..."; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "Child of %@"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "Välj"; @@ -3806,6 +3812,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "Det kan ta upp till en minut att installera ditt första tillägg på webbplatsen. Under denna tid kan du inte göra några ändringar på din webbplats."; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "Interested in building your audience? Check out our top tips"; + /* Interior Design site intent topic */ "Interior Design" = "Inredningsdesign"; @@ -8378,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Använd ikonknapp"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Använd denna länk för att lägga till gruppmedlemmar utan att behöva bjuda in dem en i taget. Vem som helst som besöker denna URL kommer att kunna registrera sig i er organisation, även om de fått länken från någon annan. Se därför till att bara ge länken till personer du litar på."; - /* No comment provided by engineer. */ "Use this site" = "Använd den här webbplatsen"; @@ -9488,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "För att lägga till bilder eller videoklipp i dina inlägg."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Använd denna länk för att låta dina teammedlemmar gå med utan att behöva bjuda in dem en och en. Vem som helst som besöker denna URL kan registrera sig till din organisation, även om de har fått länken från någon annan, så se till att du delar den med betrodda personer."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Spara som utkast"; diff --git a/WordPress/Resources/tr.lproj/Localizable.strings b/WordPress/Resources/tr.lproj/Localizable.strings index fef0f311ce64..f792890a39f4 100644 --- a/WordPress/Resources/tr.lproj/Localizable.strings +++ b/WordPress/Resources/tr.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-11 11:54:09+0000 */ +/* Translation-Revision-Date: 2022-04-25 13:42:07+0000 */ /* Plural-Forms: nplurals=2; plural=n > 1; */ /* Generator: GlotPress/3.0.0 */ /* Language: tr */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d Beğenilenler"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d yanıt"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d yanıt"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "%1$d\/%2$d tamamlandı"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "Bir dosya kötü amaçlı bir kod modeli içeriyor"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "İyi ad, kısa ve akılda kalıcı olan addır.\nBunu daha sonra değiştirebilirsiniz."; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "Sitenizde ilgi çekici içerik oluşturmanın ve yayınlamanın yeni bir yolu."; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "Blok öncesine ekle"; +/* No comment provided by engineer. */ +"Add Blocks" = "Blok Ekle"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "Yazıya içerik ekle"; @@ -621,6 +633,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "Gelişmiş"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "%@ öğesinden sonra"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -778,6 +793,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "Anonim"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "Yanıt İstemi"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "Uygulama simgesi"; @@ -1039,6 +1057,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "Güzellik"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "%@ öğesinden önce"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "En iyi gün"; @@ -1294,6 +1315,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "Dikkatli olun!"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "Hayatınızın filmini oynayın."; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "Kategoriler"; @@ -1401,6 +1425,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "Satın alımlar kontrol ediliyor…"; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "%@ öğesinin alt öğesi"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "Seç"; @@ -1440,6 +1467,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "Saat seçin"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "Aşağıdaki listeden bir konu seçin veya kendi konunuzu yazın."; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "Benzersiz bir site simgesi seçin"; @@ -2450,6 +2480,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "Düzenlemek için çift dokunup basılı tutun"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "Bu menü öğesini yukarı veya aşağı taşımak için iki kez dokunup basılı tutun Hiyerarşiyi değiştirmek için yatay olarak hareket ettirin."; + /* No comment provided by engineer. */ "Double tap to add a block" = "Blok eklemek için çift dokunun"; @@ -2582,6 +2615,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Duplicate block" = "Bloğu çoğalt"; +/* Placeholder text for the search field int the Site Intent screen. */ +"E.g. Fashion, Poetry, Politics" = "Ör. Moda, Şiir, Politika"; + /* No comment provided by engineer. */ "Each block has its own settings. To find them, tap on a block. Its settings will appear on the toolbar at the bottom of the screen." = "Her blokun kendi ayarları vardır. Onları bulmak için bir bloka dokunun. Ayarları, ekranın altındaki araç çubuğunda görünür."; @@ -3372,6 +3408,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "Sitenize kişiliğini ve konuyu yansıtan bir ad verin. İlk izlenim önemlidir."; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "Web sitenize bir ad verin"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "web sitenize%@bir ad verin"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3769,6 +3812,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "Sitenize ilk eklentinin yüklenmesi 1 dakika kadar sürebilir. Bu sırada sitenizde değişiklik yapamayacaksınız."; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "Kitlenizi oluşturmak mı istiyorsunuz? En iyi ipuçlarımıza göz atın"; + /* Interior Design site intent topic */ "Interior Design" = "İç Tasarım"; @@ -4456,6 +4502,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "En Popüler Zaman"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "Taşı: %@"; + /* No comment provided by engineer. */ "Move Image Backward" = "Görseli Geri Taşı"; @@ -5714,6 +5763,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "Projeler"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "İstemler"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "Herkese açık"; @@ -5957,6 +6009,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "Bloğu kaldır"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "Panodan kaldır"; + /* Option to remove Insight from view. */ "Remove from insights" = "Yönelimlerden çıkar"; @@ -6850,6 +6905,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "Hızlı başlangıcı atla"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "Bu bilgiyi atla"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "Eğik çizgi yerleştirici sonuçları"; @@ -8329,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "Simge düğmesini kullan"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "Ekip üyelerinizi tek tek davet etmenize gerek kalmadan, bu bağlantıyla hepsini getirebilirsiniz. Ekibinizin üyelerini tek tek davet etmek zorunda kalmadan dahil etmek için bu bağlantıyı kullanın. Bu bağlantıya tıklayan herkes, başkasından bile almış olsa, kurumunuza dahil olabilir. O nedenle, sadece güvendiğiniz kişilerle paylaşmaya dikkat edin."; - /* No comment provided by engineer. */ "Use this site" = "Bu siteyi kullan"; @@ -8443,6 +8498,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "Daha fazlasını görüntüle"; +/* Menu title to show more prompts. */ +"View more prompts" = "Daha fazla bilgi görüntüle"; + /* Description for view count. Singular. */ "View to your site so far" = "Şimdiye kadar sitenizdeki görüntüleme"; @@ -9436,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "Yazılarınızda fotoğraf veya video eklemek için."; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "Ekibinizin üyelerini tek tek davet etmek zorunda kalmadan dahil etmek için bu bağlantıyı kullanın. Bu bağlantıya tıklayan herkes, başkasından bile almış olsa, kurumunuza dahil olabilir. O nedenle, sadece güvendiğiniz kişilerle paylaşmaya dikkat edin."; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "Taslak olarak kaydet"; @@ -9607,3 +9668,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "• Kullanıcılar ve yazarlar"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ Yanıtlandı"; + diff --git a/WordPress/Resources/zh-Hans.lproj/Localizable.strings b/WordPress/Resources/zh-Hans.lproj/Localizable.strings index 51d232c7cad2..10148000c6e5 100644 --- a/WordPress/Resources/zh-Hans.lproj/Localizable.strings +++ b/WordPress/Resources/zh-Hans.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-08 09:54:09+0000 */ +/* Translation-Revision-Date: 2022-04-23 13:58:49+0000 */ /* Plural-Forms: nplurals=1; plural=0; */ /* Generator: GlotPress/3.0.0 */ /* Language: zh_CN */ @@ -56,6 +56,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d 人喜欢"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d 条回复"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d 条回复"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "已完成 %1$d 个(共 %2$d 个)"; @@ -345,6 +351,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "一个包含恶意代码模式的文件"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "好的名称应简短易记。\n您之后可以对此进行更改。"; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "在您的站点上创建、发布吸引人内容的新方法。"; @@ -481,6 +490,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "在之前添加区块"; +/* No comment provided by engineer. */ +"Add Blocks" = "添加区块"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "在文章中添加内容"; @@ -621,6 +633,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "高级"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "在 %@ 之后"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -778,6 +793,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "匿名"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "回复提示"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "App 图标"; @@ -1039,6 +1057,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "美容"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "在 %@ 之前"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "最佳日期"; @@ -1294,6 +1315,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "小心!"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "将您的生活拍成电影。"; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "分类目录"; @@ -1401,6 +1425,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "正在检查购买内容…"; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "%@ 的子项"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "选择"; @@ -1440,6 +1467,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "选择时间"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "请从以下列表中选择主题或输入自己的主题。"; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "选择唯一站点图标"; @@ -2450,6 +2480,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "轻点两次并按住以进行编辑"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "双击并按住可向上或向下移动此菜单项。 水平移动可更改层级。"; + /* No comment provided by engineer. */ "Double tap to add a block" = "轻点两次以添加区块"; @@ -2582,6 +2615,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Duplicate block" = "复制区块"; +/* Placeholder text for the search field int the Site Intent screen. */ +"E.g. Fashion, Poetry, Politics" = "例如: 时尚、诗歌、政治"; + /* No comment provided by engineer. */ "Each block has its own settings. To find them, tap on a block. Its settings will appear on the toolbar at the bottom of the screen." = "每个区块都有各自的设置。要找到这些设置,请点击一个区块。区块的设置将出现在屏幕底部的工具栏上。"; @@ -3372,6 +3408,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "为您的站点提供一个反映其个性和主题的名称。 第一印象很重要!"; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "为您的网站命名"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "为您的 %@website 命名"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3769,6 +3812,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "在站点上安装第一个插件最多需要 1 分钟。在此期间,您将无法更改自己的站点。"; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "想建立受众群体? 查看我们的实用提示"; + /* Interior Design site intent topic */ "Interior Design" = "室内设计"; @@ -4456,6 +4502,9 @@ translators: Block name. %s: The localized block name */ /* Insights 'Most Popular Time' header */ "Most Popular Time" = "人气最高的时间"; +/* Screen reader text for button that will move the menu item. Argument is menu item's name. */ +"Move %@" = "移动 %@"; + /* No comment provided by engineer. */ "Move Image Backward" = "向后移动图片"; @@ -5714,6 +5763,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "项目"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "提示"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "公开"; @@ -5957,6 +6009,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "移除区块"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "从仪表盘中移除"; + /* Option to remove Insight from view. */ "Remove from insights" = "从数据分析中删除"; @@ -6850,6 +6905,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "跳过“快速启动”"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "跳过此提示"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "斜杠插入器结果"; @@ -7768,7 +7826,7 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ "To use stats on your site, you'll need to install the Jetpack plugin." = "要在您的网站上使用“统计”功能,您需要安装Jetpack插件。"; /* Message explaining that Jetpack needs to be installed for a particular site. Reads like 'To use this app for example.com you'll need to have... */ -"To use this app for %@ you'll need to have the Jetpack plugin installed and activated." = "要将此应用用于 %@,您需要安装并启用 Jetpack 插件。"; +"To use this app for %@ you'll need to have the Jetpack plugin installed and activated." = "要将此应用用于 %@,您需要安装并启用 Jetpack 插件。"; /* Comments Today Section Header Insights 'Today' header @@ -8329,9 +8387,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "使用图标按钮"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "使用此链接来邀请成员加入您的团队,而不必逐一邀请。任何访问此链接的人都能轻松加入到您的组织,即使他们是从别处收到的链接,因此请确保您与可信的人分享此链接。"; - /* No comment provided by engineer. */ "Use this site" = "使用此站点"; @@ -8443,6 +8498,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "查看更多信息"; +/* Menu title to show more prompts. */ +"View more prompts" = "查看更多提示"; + /* Description for view count. Singular. */ "View to your site so far" = "到目前为止您站点的浏览次数"; @@ -9436,6 +9494,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "在您的文章内添加照片或视频。"; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "使用此链接请团队成员加入,而不必逐个邀请团队成员。 使用此 URL 的任何人都可以注册您的组织(即使他们收到了其他人的链接),因此请确保与值得信任的人共享。"; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "保存为草稿"; @@ -9607,3 +9668,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "•用户与作者"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ 已回复"; + diff --git a/WordPress/Resources/zh-Hant.lproj/Localizable.strings b/WordPress/Resources/zh-Hant.lproj/Localizable.strings index e5500cac27d9..8eef1d3cdf90 100644 --- a/WordPress/Resources/zh-Hant.lproj/Localizable.strings +++ b/WordPress/Resources/zh-Hant.lproj/Localizable.strings @@ -1,4 +1,4 @@ -/* Translation-Revision-Date: 2022-04-07 09:54:09+0000 */ +/* Translation-Revision-Date: 2022-04-25 16:21:15+0000 */ /* Plural-Forms: nplurals=1; plural=0; */ /* Generator: GlotPress/3.0.0 */ /* Language: zh_TW */ @@ -53,6 +53,12 @@ Plural format string for view title displaying the number of post likes. %1$d is the number of likes. */ "%1$d Likes" = "%1$d 按讚數"; +/* Singular format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answer" = "%1$d 個答案"; + +/* Plural format string for displaying the number of users that answered the blogging prompt. */ +"%1$d answers" = "%1$d 個答案"; + /* Format string for displaying number of completed quickstart tutorials. %1$d is number completed, %2$d is total number of tutorials available. */ "%1$d of %2$d completed" = "已完成 %2$d 個,共 %1$d 個"; @@ -342,6 +348,9 @@ translators: Block name. %s: The localized block name */ /* Title for a threat */ "A file contains a malicious code pattern" = "檔案包含惡意程式碼模式"; +/* Subtitle of the Site Name screen. */ +"A good name is short and memorable.\nYou can change it later." = "好名稱必須簡短易記。\n日後你可隨時變更。"; + /* Story Intro welcome title */ "A new way to create and publish engaging content on your site." = "使用全新方式在網站上建立及發佈吸睛內容。"; @@ -478,6 +487,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Add Block Before" = "在之前新增區塊"; +/* No comment provided by engineer. */ +"Add Blocks" = "新增區塊"; + /* Alert option to add document contents into a blog post. */ "Add Contents to Post" = "將內容新增至文章"; @@ -615,6 +627,9 @@ translators: Block name. %s: The localized block name */ /* Title for the advanced section in site settings screen */ "Advanced" = "進階"; +/* Screen reader text expressing the menu item is after another menu item. Argument is a name for another menu item. */ +"After %@" = "%@之後"; + /* Option to select the Airmail app when logging in with magic links */ "Airmail" = "Airmail"; @@ -772,6 +787,9 @@ translators: Block name. %s: The localized block name */ /* the comment has an anonymous author. */ "Anonymous" = "匿名"; +/* Title for a call-to-action button on the prompts card. */ +"Answer Prompt" = "回答提示"; + /* Navigates to picker screen to change the app's icon Title of screen to change the app's icon */ "App Icon" = "應用程式圖示"; @@ -1033,6 +1051,9 @@ translators: Block name. %s: The localized block name */ /* Beauty site intent topic */ "Beauty" = "美妝"; +/* Screen reader text expressing the menu item is before another menu item. Argument is a name for another menu item. */ +"Before %@" = "%@之前"; + /* 'Best Day' label for Most Popular stat. */ "Best Day" = "造訪尖峰日"; @@ -1284,6 +1305,9 @@ translators: Block name. %s: The localized block name */ Title for the warning shown to the user when he refuses to re-login when the authToken is missing. */ "Careful!" = "請小心!"; +/* Example prompt for the Prompts card in Feature Introduction. */ +"Cast the movie of your life." = "投放你的人生電影。"; + /* Label for Categories Label for the categories field. Should be the same as WP core. */ "Categories" = "分類"; @@ -1391,6 +1415,9 @@ translators: Block name. %s: The localized block name */ /* Overlay message displayed while checking if site has premium purchases */ "Checking purchases…" = "正在確認購買項目…"; +/* Screen reader text expressing the menu item is a child of another menu item. Argument is a name for another menu item. */ +"Child of %@" = "%@的子項"; + /* Title for the button to progress with the selected site homepage design */ "Choose" = "選擇"; @@ -1430,6 +1457,9 @@ translators: Block name. %s: The localized block name */ /* Label for Publish time picker */ "Choose a time" = "選擇時間"; +/* Select the site's intent. Subtitle */ +"Choose a topic from the list below or type your own." = "請從下方清單選擇一個主題,或輸入你自己的主題。"; + /* Title of a Quick Start Tour */ "Choose a unique site icon" = "選擇專屬網站圖示"; @@ -2424,6 +2454,9 @@ translators: Block name. %s: The localized block name */ /* No comment provided by engineer. */ "Double tap and hold to edit" = "點兩下並按住不放即可編輯"; +/* Screen reader hint for button that will move the menu item */ +"Double tap and hold to move this menu item up or down. Move horizontally to change hierarchy." = "點兩下並按住,即可上下移動此選單項目 水平移動即可變更階層。"; + /* No comment provided by engineer. */ "Double tap to add a block" = "按兩下以新增區塊"; @@ -3340,6 +3373,13 @@ translators: Block name. %s: The localized block name */ /* Description of a Quick Start Tour */ "Give your site a name that reflects its personality and topic. First impressions count!" = "為網站取一個能反映出自我風格和主題的名稱。 第一印象很重要!"; +/* Default title of the Site Name screen. + Title for Site Name screen in iPhone landscape. */ +"Give your website a name" = "為你的網站取個名字"; + +/* Title of the Site Name screen. Takes the vertical name as a parameter. */ +"Give your%@website a name" = "為你的%@網站取個名字"; + /* Option to select the Gmail app when logging in with magic links */ "Gmail" = "Gmail"; @@ -3737,6 +3777,9 @@ translators: Block name. %s: The localized block name */ /* Message displayed in an alert when user tries to install a first plugin on their site. */ "Installing the first plugin on your site can take up to 1 minute. During this time you won’t be able to make changes to your site." = "在你的網站上安裝第一個外掛程式,可能需要 1 分鐘的時間。在此期間,你無法對你的網站進行任何變更。"; +/* Title for a button that opens up the 'Getting More Views and Traffic' support page when tapped. */ +"Interested in building your audience? Check out our top tips" = "有興趣培養你的讀者群嗎? 查看我們的頂尖秘訣。"; + /* Interior Design site intent topic */ "Interior Design" = "室內設計"; @@ -5682,6 +5725,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* Menu item label for linking a project page. */ "Projects" = "專案"; +/* Title label for the Prompts card in My Sites tab. */ +"Prompts" = "提示"; + /* Privacy setting for posts set to 'Public' (default). Should be the same as in core WP. Text for privacy settings: Public */ "Public" = "公開"; @@ -5925,6 +5971,9 @@ translators: %s: Select control button label e.g. \"Button width\" */ /* No comment provided by engineer. */ "Remove block" = "移除區塊"; +/* Destructive menu title to remove the prompt card from the dashboard. */ +"Remove from dashboard" = "從儀表板移除"; + /* Option to remove Insight from view. */ "Remove from insights" = "從洞察報告中移除"; @@ -6815,6 +6864,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Title shown in alert to confirm skipping all quick start items */ "Skip Quick Start" = "略過快速入門"; +/* Menu title to skip today's prompt. */ +"Skip this prompt" = "略過此提示"; + /* translators: Slash inserter autocomplete results */ "Slash inserter results" = "斜線插入工具結果"; @@ -8291,9 +8343,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* No comment provided by engineer. */ "Use icon button" = "使用圖示按鈕"; -/* Footer text for Invite Links section of the Invite People screen. */ -"Use this link to onboard your team members without having to invite them one by one. Anybody visiting this URL will be able to sign up to your organization, even if they received the link from somebody else, so make sure that you share it with trusted peo" = "你可以使用此連結一次加入所有團隊成員,無須逐一邀請。 凡是造訪這個 URL 的人,不論以何種方式取得連結,都可以註冊加入貴機構,因此分享網址前,請確認對方值得信任。"; - /* No comment provided by engineer. */ "Use this site" = "使用此網站"; @@ -8405,6 +8454,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ Label for viewing more stats. */ "View more" = "檢視更多"; +/* Menu title to show more prompts. */ +"View more prompts" = "檢視更多提示"; + /* Description for view count. Singular. */ "View to your site so far" = "你的網站目前為止的瀏覽次數"; @@ -9385,6 +9437,9 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Sentence to justify why the app asks permission from the user to access their Media Library. */ "infoplist.NSPhotoLibraryUsageDescription" = "在你的文章中新增相片或影片。"; +/* Footer text for Invite Links section of the Invite People screen. */ +"invite_people_invite_link_footer" = "用這個連結直接加入成員,就不需要一個一個邀請。 造訪此 URL 的人都可以註冊你的組織,即使他們是從其他人那裡收到連結,因此請務必與值得信任的人分享。"; + /* Name of the "Save as Draft" action as it should appear in the iOS Share Sheet when sharing content from other apps to WordPress */ "ios-sharesheet.CFBundleDisplayName" = "儲存為草稿"; @@ -9556,3 +9611,6 @@ translators: %s: Select control option value e.g: \"Auto, 25%\". */ /* Item 2 of delete screen section listing things that will be deleted. */ "• Users & Authors" = "•使用者和作者"; +/* Title label that indicates the prompt has been answered. */ +"✓ Answered" = "✓ 已回答"; + diff --git a/WordPress/UITestsFoundation/Screens/Login/LoginEpilogueScreen.swift b/WordPress/UITestsFoundation/Screens/Login/LoginEpilogueScreen.swift index 5347687cd9ef..d3ac253d44da 100644 --- a/WordPress/UITestsFoundation/Screens/Login/LoginEpilogueScreen.swift +++ b/WordPress/UITestsFoundation/Screens/Login/LoginEpilogueScreen.swift @@ -22,6 +22,7 @@ public class LoginEpilogueScreen: ScreenObject { firstSite.tap() try dismissQuickStartPromptIfNeeded() + try dismissOnboardingQuestionsPromptIfNeeded() return try MySiteScreen() } @@ -32,6 +33,7 @@ public class LoginEpilogueScreen: ScreenObject { firstSite.tap() try dismissQuickStartPromptIfNeeded() + try dismissOnboardingQuestionsPromptIfNeeded() return try MySitesScreen() } @@ -66,4 +68,13 @@ public class LoginEpilogueScreen: ScreenObject { _ = try QuickStartPromptScreen().selectNoThanks() } } + + private func dismissOnboardingQuestionsPromptIfNeeded() throws { + try XCTContext.runActivity(named: "Dismiss onboarding questions prompt if needed.") { _ in + guard OnboardingQuestionsPromptScreen.isLoaded() else { return } + + Logger.log(message: "Dismissing onboarding questions prompt...", event: .i) + _ = try OnboardingQuestionsPromptScreen().selectSkip() + } + } } diff --git a/WordPress/UITestsFoundation/Screens/Login/LoginUsernamePasswordScreen.swift b/WordPress/UITestsFoundation/Screens/Login/LoginUsernamePasswordScreen.swift index 8cee7b929034..76155c39e87d 100644 --- a/WordPress/UITestsFoundation/Screens/Login/LoginUsernamePasswordScreen.swift +++ b/WordPress/UITestsFoundation/Screens/Login/LoginUsernamePasswordScreen.swift @@ -58,6 +58,7 @@ public class LoginUsernamePasswordScreen: ScreenObject { public func proceedWithSelfHostedSiteAddedFromSitesList(username: String, password: String) throws -> MySitesScreen { fill(username: username, password: password) try dismissQuickStartPromptIfNeeded() + try dismissOnboardingQuestionsPromptIfNeeded() return try MySitesScreen() } @@ -65,6 +66,7 @@ public class LoginUsernamePasswordScreen: ScreenObject { public func proceedWithSelfHosted(username: String, password: String) throws -> MySiteScreen { fill(username: username, password: password) try dismissQuickStartPromptIfNeeded() + try dismissOnboardingQuestionsPromptIfNeeded() return try MySiteScreen() } @@ -96,4 +98,14 @@ public class LoginUsernamePasswordScreen: ScreenObject { } } } + + private func dismissOnboardingQuestionsPromptIfNeeded() throws { + try XCTContext.runActivity(named: "Dismiss onboarding questions prompt if needed.") { (activity) in + if OnboardingQuestionsPromptScreen.isLoaded() { + Logger.log(message: "Dismissing onboarding questions prompt...", event: .i) + _ = try OnboardingQuestionsPromptScreen().selectSkip() + return + } + } + } } diff --git a/WordPress/UITestsFoundation/Screens/Login/OnboardingQuestionsPromptScreen.swift b/WordPress/UITestsFoundation/Screens/Login/OnboardingQuestionsPromptScreen.swift new file mode 100644 index 000000000000..2040762b4965 --- /dev/null +++ b/WordPress/UITestsFoundation/Screens/Login/OnboardingQuestionsPromptScreen.swift @@ -0,0 +1,28 @@ +import ScreenObject +import XCTest + +public class OnboardingQuestionsPromptScreen: ScreenObject { + private let skipButtonGetter: (XCUIApplication) -> XCUIElement = { + $0.buttons["Skip"] + } + + var skipButton: XCUIElement { skipButtonGetter(app) } + + public init(app: XCUIApplication = XCUIApplication()) throws { + try super.init( + expectedElementGetters: [skipButtonGetter], + app: app, + waitTimeout: 7 + ) + } + + public func selectSkip() throws -> MySiteScreen { + skipButton.tap() + + return try MySiteScreen() + } + + static func isLoaded() -> Bool { + (try? OnboardingQuestionsPromptScreen().isLoaded) ?? false + } +} diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index 85fbceb327c6..875af7b8e1b1 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -72,6 +72,7 @@ 0807CB721CE670A800CDBDAC /* WPContentSearchHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0807CB711CE670A800CDBDAC /* WPContentSearchHelper.swift */; }; 080C44A91CE14A9F00B3A02F /* MenuDetailsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 080C449E1CE14A9F00B3A02F /* MenuDetailsViewController.m */; }; 0815CF461E96F22600069916 /* MediaImportService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0815CF451E96F22600069916 /* MediaImportService.swift */; }; + 081E4B4C281C019A0085E89C /* TooltipAnchor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 081E4B4B281C019A0085E89C /* TooltipAnchor.swift */; }; 08216FAA1CDBF95100304BA7 /* MenuItemEditing.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 08216FA71CDBF95100304BA7 /* MenuItemEditing.storyboard */; }; 08216FAB1CDBF95100304BA7 /* MenuItemEditingViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 08216FA91CDBF95100304BA7 /* MenuItemEditingViewController.m */; }; 08216FC81CDBF96000304BA7 /* MenuItemAbstractPostsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 08216FAD1CDBF96000304BA7 /* MenuItemAbstractPostsViewController.m */; }; @@ -116,6 +117,7 @@ 08B832421EC130D60079808D /* test-gif.gif in Resources */ = {isa = PBXBuildFile; fileRef = 08B832411EC130D60079808D /* test-gif.gif */; }; 08C388661ED7705E0057BE49 /* MediaAssetExporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08C388651ED7705E0057BE49 /* MediaAssetExporter.swift */; }; 08C3886A1ED78EE70057BE49 /* Media+WPMediaAsset.m in Sources */ = {isa = PBXBuildFile; fileRef = 08C388691ED78EE70057BE49 /* Media+WPMediaAsset.m */; }; + 08C42C31281807880034720B /* ReaderSubscribeCommentsActionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 08C42C30281807880034720B /* ReaderSubscribeCommentsActionTests.swift */; }; 08CC677E1C49B65A00153AD7 /* MenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 08CC67791C49B65A00153AD7 /* MenuItem.m */; }; 08CC677F1C49B65A00153AD7 /* Menu.m in Sources */ = {isa = PBXBuildFile; fileRef = 08CC677A1C49B65A00153AD7 /* Menu.m */; }; 08CC67801C49B65A00153AD7 /* MenuLocation.m in Sources */ = {isa = PBXBuildFile; fileRef = 08CC677D1C49B65A00153AD7 /* MenuLocation.m */; }; @@ -149,6 +151,7 @@ 098B8578275FF975004D299F /* AppLocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F2656A025AF4DFA0073A832 /* AppLocalizedString.swift */; }; 098B8579275FFB21004D299F /* AppLocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F2656A025AF4DFA0073A832 /* AppLocalizedString.swift */; }; 099D768327D14B8E00F77EDE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 099D768127D14B8E00F77EDE /* InfoPlist.strings */; }; + 09DBEA55281336E10019724E /* AppLocalizedString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F2656A025AF4DFA0073A832 /* AppLocalizedString.swift */; }; 1702BBDC1CEDEA6B00766A33 /* BadgeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1702BBDB1CEDEA6B00766A33 /* BadgeLabel.swift */; }; 1702BBE01CF3034E00766A33 /* DomainsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1702BBDF1CF3034E00766A33 /* DomainsService.swift */; }; 1703D04C20ECD93800D292E9 /* Routes+Post.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1703D04B20ECD93800D292E9 /* Routes+Post.swift */; }; @@ -308,6 +311,8 @@ 1770BD0E267A368100D5F8C0 /* BloggingRemindersPushPromptViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1770BD0C267A368100D5F8C0 /* BloggingRemindersPushPromptViewController.swift */; }; 177E7DAD1DD0D1E600890467 /* UINavigationController+SplitViewFullscreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 177E7DAC1DD0D1E600890467 /* UINavigationController+SplitViewFullscreen.swift */; }; 1782BE841E70063100A91E7D /* MediaItemViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1782BE831E70063100A91E7D /* MediaItemViewController.swift */; }; + 17870A702816F2A000D1C627 /* StatsLatestPostSummaryInsightsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17870A6F2816F2A000D1C627 /* StatsLatestPostSummaryInsightsCell.swift */; }; + 17870A712816F2A000D1C627 /* StatsLatestPostSummaryInsightsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17870A6F2816F2A000D1C627 /* StatsLatestPostSummaryInsightsCell.swift */; }; 1788106F260E488B00A98BD8 /* UnifiedPrologueNotificationsContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1788106E260E488B00A98BD8 /* UnifiedPrologueNotificationsContentView.swift */; }; 178810B52611D25600A98BD8 /* Text+BoldSubString.swift in Sources */ = {isa = PBXBuildFile; fileRef = 178810B42611D25600A98BD8 /* Text+BoldSubString.swift */; }; 178810D92612037900A98BD8 /* UnifiedPrologueReaderContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 178810D82612037800A98BD8 /* UnifiedPrologueReaderContentView.swift */; }; @@ -1353,16 +1358,16 @@ 80EF672327F160720063B138 /* DashboardCustomAnnouncementCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF672127F160720063B138 /* DashboardCustomAnnouncementCell.swift */; }; 80EF672527F3D63B0063B138 /* DashboardStatsStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF672427F3D63B0063B138 /* DashboardStatsStackView.swift */; }; 80EF672627F3D63B0063B138 /* DashboardStatsStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF672427F3D63B0063B138 /* DashboardStatsStackView.swift */; }; - 80EF928D280E83110064A971 /* QuickStartToursCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF928C280E83110064A971 /* QuickStartToursCollection.swift */; }; - 80EF928E280E83110064A971 /* QuickStartToursCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF928C280E83110064A971 /* QuickStartToursCollection.swift */; }; - 80EF929028105CFA0064A971 /* QuickStartFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF928F28105CFA0064A971 /* QuickStartFactory.swift */; }; - 80EF929128105CFA0064A971 /* QuickStartFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF928F28105CFA0064A971 /* QuickStartFactory.swift */; }; - 80EF92932810FA5A0064A971 /* QuickStartFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF92922810FA5A0064A971 /* QuickStartFactoryTests.swift */; }; 80EF9284280CFEB60064A971 /* DashboardPostsSyncManagerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF9283280CFEB60064A971 /* DashboardPostsSyncManagerTests.swift */; }; 80EF9286280D272E0064A971 /* DashboardPostsSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF9285280D272E0064A971 /* DashboardPostsSyncManager.swift */; }; 80EF9287280D272E0064A971 /* DashboardPostsSyncManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF9285280D272E0064A971 /* DashboardPostsSyncManager.swift */; }; 80EF928A280D28140064A971 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF9289280D28140064A971 /* Atomic.swift */; }; 80EF928B280D28140064A971 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF9289280D28140064A971 /* Atomic.swift */; }; + 80EF928D280E83110064A971 /* QuickStartToursCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF928C280E83110064A971 /* QuickStartToursCollection.swift */; }; + 80EF928E280E83110064A971 /* QuickStartToursCollection.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF928C280E83110064A971 /* QuickStartToursCollection.swift */; }; + 80EF929028105CFA0064A971 /* QuickStartFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF928F28105CFA0064A971 /* QuickStartFactory.swift */; }; + 80EF929128105CFA0064A971 /* QuickStartFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF928F28105CFA0064A971 /* QuickStartFactory.swift */; }; + 80EF92932810FA5A0064A971 /* QuickStartFactoryTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 80EF92922810FA5A0064A971 /* QuickStartFactoryTests.swift */; }; 820ADD701F3A1F88002D7F93 /* ThemeBrowserSectionHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 820ADD6F1F3A1F88002D7F93 /* ThemeBrowserSectionHeaderView.xib */; }; 820ADD721F3A226E002D7F93 /* ThemeBrowserSectionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 820ADD711F3A226E002D7F93 /* ThemeBrowserSectionHeaderView.swift */; }; 821738091FE04A9E00BEC94C /* DateAndTimeFormatSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 821738081FE04A9E00BEC94C /* DateAndTimeFormatSettingsViewController.swift */; }; @@ -1393,6 +1398,12 @@ 834CE7341256D0DE0046A4A3 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 834CE7331256D0DE0046A4A3 /* CFNetwork.framework */; }; 8350E49611D2C71E00A7B073 /* Media.m in Sources */ = {isa = PBXBuildFile; fileRef = 8350E49511D2C71E00A7B073 /* Media.m */; }; 8355D7D911D260AA00A61362 /* CoreData.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8355D7D811D260AA00A61362 /* CoreData.framework */; }; + 836498C828172C5900A2C170 /* WPStyleGuide+BloggingPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836498C728172C5900A2C170 /* WPStyleGuide+BloggingPrompts.swift */; }; + 836498C928172C5900A2C170 /* WPStyleGuide+BloggingPrompts.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836498C728172C5900A2C170 /* WPStyleGuide+BloggingPrompts.swift */; }; + 836498CB2817301800A2C170 /* BloggingPromptsHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 836498CA2817301800A2C170 /* BloggingPromptsHeaderView.xib */; }; + 836498CC2817301800A2C170 /* BloggingPromptsHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 836498CA2817301800A2C170 /* BloggingPromptsHeaderView.xib */; }; + 836498CE281735CC00A2C170 /* BloggingPromptsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836498CD281735CC00A2C170 /* BloggingPromptsHeaderView.swift */; }; + 836498CF281735CC00A2C170 /* BloggingPromptsHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 836498CD281735CC00A2C170 /* BloggingPromptsHeaderView.swift */; }; 8370D10A11FA499A009D650F /* WPTableViewActivityCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 8370D10911FA499A009D650F /* WPTableViewActivityCell.m */; }; 839B150B2795DEE0009F5E77 /* UIView+Margins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839B150A2795DEE0009F5E77 /* UIView+Margins.swift */; }; 839B150C2795DEE0009F5E77 /* UIView+Margins.swift in Sources */ = {isa = PBXBuildFile; fileRef = 839B150A2795DEE0009F5E77 /* UIView+Margins.swift */; }; @@ -2195,6 +2206,8 @@ C7124E4F2638528F00929318 /* JetpackPrologueViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7124E4D2638528F00929318 /* JetpackPrologueViewController.swift */; }; C7124E922638905B00929318 /* StarFieldView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7124E912638905B00929318 /* StarFieldView.swift */; }; C7192ECF25E8432D00C3020D /* ReaderTopicsCardCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = C7192ECE25E8432D00C3020D /* ReaderTopicsCardCell.xib */; }; + C71AF533281064DE00F9E99E /* OnboardingQuestionsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71AF532281064DE00F9E99E /* OnboardingQuestionsCoordinator.swift */; }; + C71AF534281064DE00F9E99E /* OnboardingQuestionsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71AF532281064DE00F9E99E /* OnboardingQuestionsCoordinator.swift */; }; C71BC73F25A652410023D789 /* JetpackScanStatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C71BC73E25A652410023D789 /* JetpackScanStatusViewModel.swift */; }; C72A4F68264088E4009CA633 /* JetpackNotFoundErrorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C72A4F67264088E4009CA633 /* JetpackNotFoundErrorViewModel.swift */; }; C72A4F7B26408943009CA633 /* JetpackNotWPErrorViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C72A4F7A26408943009CA633 /* JetpackNotWPErrorViewModel.swift */; }; @@ -2211,6 +2224,14 @@ C76F48DC25BA202600BFEC87 /* JetpackScanHistoryViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76F48DB25BA202600BFEC87 /* JetpackScanHistoryViewController.swift */; }; C76F48EE25BA20EF00BFEC87 /* JetpackScanHistoryCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C76F48ED25BA20EF00BFEC87 /* JetpackScanHistoryCoordinator.swift */; }; C76F490025BA23B000BFEC87 /* JetpackScanHistoryViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C76F48FF25BA23B000BFEC87 /* JetpackScanHistoryViewController.xib */; }; + C77FC90928009C7000726F00 /* OnboardingQuestionsPromptViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77FC90728009C7000726F00 /* OnboardingQuestionsPromptViewController.swift */; }; + C77FC90A28009C7000726F00 /* OnboardingQuestionsPromptViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77FC90728009C7000726F00 /* OnboardingQuestionsPromptViewController.swift */; }; + C77FC90B28009C7000726F00 /* OnboardingQuestionsPromptViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C77FC90828009C7000726F00 /* OnboardingQuestionsPromptViewController.xib */; }; + C77FC90C28009C7000726F00 /* OnboardingQuestionsPromptViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C77FC90828009C7000726F00 /* OnboardingQuestionsPromptViewController.xib */; }; + C77FC90F2800CAC100726F00 /* OnboardingEnableNotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77FC90D2800CAC100726F00 /* OnboardingEnableNotificationsViewController.swift */; }; + C77FC9102800CAC100726F00 /* OnboardingEnableNotificationsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C77FC90D2800CAC100726F00 /* OnboardingEnableNotificationsViewController.swift */; }; + C77FC9112800CAC100726F00 /* OnboardingEnableNotificationsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C77FC90E2800CAC100726F00 /* OnboardingEnableNotificationsViewController.xib */; }; + C77FC9122800CAC100726F00 /* OnboardingEnableNotificationsViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = C77FC90E2800CAC100726F00 /* OnboardingEnableNotificationsViewController.xib */; }; C78543D225B889CC006CEAFB /* JetpackScanThreatViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C78543D125B889CC006CEAFB /* JetpackScanThreatViewModel.swift */; }; C789952525816F96001B7B43 /* JetpackScanCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = C789952425816F96001B7B43 /* JetpackScanCoordinator.swift */; }; C79C307C26EA915100E88514 /* ReferrerDetailsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 931215E3267F5003008C3B69 /* ReferrerDetailsTableViewController.swift */; }; @@ -2221,6 +2242,9 @@ C79C308126EA975900E88514 /* ReferrerDetailsHeaderCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 931215E9267F59CB008C3B69 /* ReferrerDetailsHeaderCell.swift */; }; C79C308226EA99D500E88514 /* ReferrerDetailsSpamActionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 931215F3267FE177008C3B69 /* ReferrerDetailsSpamActionCell.swift */; }; C79C308326EA9A2300E88514 /* ReferrerDetailsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 931215ED267F6799008C3B69 /* ReferrerDetailsCell.swift */; }; + C7B7CC702812FDCE007B9807 /* MySiteViewController+OnboardingPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B7CC6F2812FDCE007B9807 /* MySiteViewController+OnboardingPrompt.swift */; }; + C7B7CC712812FDCE007B9807 /* MySiteViewController+OnboardingPrompt.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B7CC6F2812FDCE007B9807 /* MySiteViewController+OnboardingPrompt.swift */; }; + C7B7CC7328134347007B9807 /* OnboardingQuestionsPromptScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7B7CC7228134347007B9807 /* OnboardingQuestionsPromptScreen.swift */; }; C7D30C652638B07A00A1695B /* JetpackPrologueStyleGuide.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7D30C642638B07A00A1695B /* JetpackPrologueStyleGuide.swift */; }; C7E5F2522799BD54009BC263 /* cool-blue-icon-app-76x76.png in Resources */ = {isa = PBXBuildFile; fileRef = C7E5F24D2799BD52009BC263 /* cool-blue-icon-app-76x76.png */; }; C7E5F2532799BD54009BC263 /* cool-blue-icon-app-60x60@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = C7E5F24E2799BD52009BC263 /* cool-blue-icon-app-60x60@3x.png */; }; @@ -4535,6 +4559,7 @@ FE23EB4C26E7C91F005A1698 /* richCommentStyle.css in Resources */ = {isa = PBXBuildFile; fileRef = FE23EB4826E7C91F005A1698 /* richCommentStyle.css */; }; FE25C235271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */; }; FE25C236271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */; }; + FE2E3729281C839C00A1E82A /* BloggingPromptsServiceTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE2E3728281C839C00A1E82A /* BloggingPromptsServiceTests.swift */; }; FE32EFFF275914390040BE67 /* MenuSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32EFFE275914390040BE67 /* MenuSheetViewController.swift */; }; FE32F000275914390040BE67 /* MenuSheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32EFFE275914390040BE67 /* MenuSheetViewController.swift */; }; FE32F002275F602E0040BE67 /* CommentContentRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE32F001275F602E0040BE67 /* CommentContentRenderer.swift */; }; @@ -4566,6 +4591,8 @@ FEA088032696E81F00193358 /* ListTableHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = FEA088022696E81F00193358 /* ListTableHeaderView.xib */; }; FEA088052696F7AA00193358 /* WPStyleGuide+List.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEA088042696F7AA00193358 /* WPStyleGuide+List.swift */; }; FEA5CE7F2701DC8000B41F2A /* AppImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 433840C622C2BA5B00CB13F8 /* AppImages.xcassets */; }; + FEA6517B281C491C002EA086 /* BloggingPromptsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEA6517A281C491C002EA086 /* BloggingPromptsService.swift */; }; + FEA6517C281C491C002EA086 /* BloggingPromptsService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEA6517A281C491C002EA086 /* BloggingPromptsService.swift */; }; FEA7948D26DD136700CEC520 /* CommentHeaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEA7948C26DD136700CEC520 /* CommentHeaderTableViewCell.swift */; }; FEA7948E26DD136700CEC520 /* CommentHeaderTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEA7948C26DD136700CEC520 /* CommentHeaderTableViewCell.swift */; }; FEA7949026DF7F3700CEC520 /* WPStyleGuide+CommentDetail.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEA7948F26DF7F3700CEC520 /* WPStyleGuide+CommentDetail.swift */; }; @@ -4809,6 +4836,7 @@ 080C449D1CE14A9F00B3A02F /* MenuDetailsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuDetailsViewController.h; sourceTree = ""; }; 080C449E1CE14A9F00B3A02F /* MenuDetailsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuDetailsViewController.m; sourceTree = ""; }; 0815CF451E96F22600069916 /* MediaImportService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaImportService.swift; sourceTree = ""; }; + 081E4B4B281C019A0085E89C /* TooltipAnchor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipAnchor.swift; sourceTree = ""; }; 08216FA71CDBF95100304BA7 /* MenuItemEditing.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = MenuItemEditing.storyboard; sourceTree = ""; }; 08216FA81CDBF95100304BA7 /* MenuItemEditingViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuItemEditingViewController.h; sourceTree = ""; }; 08216FA91CDBF95100304BA7 /* MenuItemEditingViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuItemEditingViewController.m; sourceTree = ""; }; @@ -4882,6 +4910,7 @@ 08C388651ED7705E0057BE49 /* MediaAssetExporter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaAssetExporter.swift; sourceTree = ""; }; 08C388681ED78EE70057BE49 /* Media+WPMediaAsset.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "Media+WPMediaAsset.h"; sourceTree = ""; }; 08C388691ED78EE70057BE49 /* Media+WPMediaAsset.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "Media+WPMediaAsset.m"; sourceTree = ""; }; + 08C42C30281807880034720B /* ReaderSubscribeCommentsActionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderSubscribeCommentsActionTests.swift; sourceTree = ""; }; 08CC67771C49B52E00153AD7 /* WordPress 45.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 45.xcdatamodel"; sourceTree = ""; }; 08CC67781C49B65A00153AD7 /* MenuItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MenuItem.h; sourceTree = ""; }; 08CC67791C49B65A00153AD7 /* MenuItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MenuItem.m; sourceTree = ""; }; @@ -5105,6 +5134,8 @@ 1770BD0C267A368100D5F8C0 /* BloggingRemindersPushPromptViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingRemindersPushPromptViewController.swift; sourceTree = ""; }; 177E7DAC1DD0D1E600890467 /* UINavigationController+SplitViewFullscreen.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UINavigationController+SplitViewFullscreen.swift"; sourceTree = ""; }; 1782BE831E70063100A91E7D /* MediaItemViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaItemViewController.swift; sourceTree = ""; }; + 17870A6F2816F2A000D1C627 /* StatsLatestPostSummaryInsightsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StatsLatestPostSummaryInsightsCell.swift; sourceTree = ""; }; + 17870A72281847D500D1C627 /* WordPress 139.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 139.xcdatamodel"; sourceTree = ""; }; 1788106E260E488B00A98BD8 /* UnifiedPrologueNotificationsContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnifiedPrologueNotificationsContentView.swift; sourceTree = ""; }; 178810B42611D25600A98BD8 /* Text+BoldSubString.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Text+BoldSubString.swift"; sourceTree = ""; }; 178810D82612037800A98BD8 /* UnifiedPrologueReaderContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UnifiedPrologueReaderContentView.swift; sourceTree = ""; }; @@ -6089,12 +6120,12 @@ 80EF671E27F135EB0063B138 /* WhatIsNewViewAppearance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WhatIsNewViewAppearance.swift; sourceTree = ""; }; 80EF672127F160720063B138 /* DashboardCustomAnnouncementCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardCustomAnnouncementCell.swift; sourceTree = ""; }; 80EF672427F3D63B0063B138 /* DashboardStatsStackView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardStatsStackView.swift; sourceTree = ""; }; - 80EF928C280E83110064A971 /* QuickStartToursCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickStartToursCollection.swift; sourceTree = ""; }; - 80EF928F28105CFA0064A971 /* QuickStartFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickStartFactory.swift; sourceTree = ""; }; - 80EF92922810FA5A0064A971 /* QuickStartFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickStartFactoryTests.swift; sourceTree = ""; }; 80EF9283280CFEB60064A971 /* DashboardPostsSyncManagerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardPostsSyncManagerTests.swift; sourceTree = ""; }; 80EF9285280D272E0064A971 /* DashboardPostsSyncManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DashboardPostsSyncManager.swift; sourceTree = ""; }; 80EF9289280D28140064A971 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; + 80EF928C280E83110064A971 /* QuickStartToursCollection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickStartToursCollection.swift; sourceTree = ""; }; + 80EF928F28105CFA0064A971 /* QuickStartFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickStartFactory.swift; sourceTree = ""; }; + 80EF92922810FA5A0064A971 /* QuickStartFactoryTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QuickStartFactoryTests.swift; sourceTree = ""; }; 820ADD6C1F3A0DA0002D7F93 /* WordPress 64.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "WordPress 64.xcdatamodel"; sourceTree = ""; }; 820ADD6F1F3A1F88002D7F93 /* ThemeBrowserSectionHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ThemeBrowserSectionHeaderView.xib; sourceTree = ""; }; 820ADD711F3A226E002D7F93 /* ThemeBrowserSectionHeaderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeBrowserSectionHeaderView.swift; sourceTree = ""; }; @@ -6141,6 +6172,9 @@ 8355D67D11D13EAD00A61362 /* MobileCoreServices.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; }; 8355D7D811D260AA00A61362 /* CoreData.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = System/Library/Frameworks/CoreData.framework; sourceTree = SDKROOT; }; 835E2402126E66E50085940B /* AssetsLibrary.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; }; + 836498C728172C5900A2C170 /* WPStyleGuide+BloggingPrompts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WPStyleGuide+BloggingPrompts.swift"; sourceTree = ""; }; + 836498CA2817301800A2C170 /* BloggingPromptsHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = BloggingPromptsHeaderView.xib; sourceTree = ""; }; + 836498CD281735CC00A2C170 /* BloggingPromptsHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsHeaderView.swift; sourceTree = ""; }; 8370D10811FA499A009D650F /* WPTableViewActivityCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WPTableViewActivityCell.h; sourceTree = ""; }; 8370D10911FA499A009D650F /* WPTableViewActivityCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WPTableViewActivityCell.m; sourceTree = ""; }; 839B150A2795DEE0009F5E77 /* UIView+Margins.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Margins.swift"; sourceTree = ""; }; @@ -6945,6 +6979,7 @@ C7124E4D2638528F00929318 /* JetpackPrologueViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JetpackPrologueViewController.swift; sourceTree = ""; }; C7124E912638905B00929318 /* StarFieldView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarFieldView.swift; sourceTree = ""; }; C7192ECE25E8432D00C3020D /* ReaderTopicsCardCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ReaderTopicsCardCell.xib; sourceTree = ""; }; + C71AF532281064DE00F9E99E /* OnboardingQuestionsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingQuestionsCoordinator.swift; sourceTree = ""; }; C71BC73E25A652410023D789 /* JetpackScanStatusViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackScanStatusViewModel.swift; sourceTree = ""; }; C72A4F67264088E4009CA633 /* JetpackNotFoundErrorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackNotFoundErrorViewModel.swift; sourceTree = ""; }; C72A4F7A26408943009CA633 /* JetpackNotWPErrorViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackNotWPErrorViewModel.swift; sourceTree = ""; }; @@ -6958,8 +6993,14 @@ C76F48DB25BA202600BFEC87 /* JetpackScanHistoryViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackScanHistoryViewController.swift; sourceTree = ""; }; C76F48ED25BA20EF00BFEC87 /* JetpackScanHistoryCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackScanHistoryCoordinator.swift; sourceTree = ""; }; C76F48FF25BA23B000BFEC87 /* JetpackScanHistoryViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = JetpackScanHistoryViewController.xib; sourceTree = ""; }; + C77FC90728009C7000726F00 /* OnboardingQuestionsPromptViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingQuestionsPromptViewController.swift; sourceTree = ""; }; + C77FC90828009C7000726F00 /* OnboardingQuestionsPromptViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = OnboardingQuestionsPromptViewController.xib; sourceTree = ""; }; + C77FC90D2800CAC100726F00 /* OnboardingEnableNotificationsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingEnableNotificationsViewController.swift; sourceTree = ""; }; + C77FC90E2800CAC100726F00 /* OnboardingEnableNotificationsViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = OnboardingEnableNotificationsViewController.xib; sourceTree = ""; }; C78543D125B889CC006CEAFB /* JetpackScanThreatViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackScanThreatViewModel.swift; sourceTree = ""; }; C789952425816F96001B7B43 /* JetpackScanCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackScanCoordinator.swift; sourceTree = ""; }; + C7B7CC6F2812FDCE007B9807 /* MySiteViewController+OnboardingPrompt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MySiteViewController+OnboardingPrompt.swift"; sourceTree = ""; }; + C7B7CC7228134347007B9807 /* OnboardingQuestionsPromptScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingQuestionsPromptScreen.swift; sourceTree = ""; }; C7D30C642638B07A00A1695B /* JetpackPrologueStyleGuide.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JetpackPrologueStyleGuide.swift; sourceTree = ""; }; C7E5F24D2799BD52009BC263 /* cool-blue-icon-app-76x76.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cool-blue-icon-app-76x76.png"; sourceTree = ""; }; C7E5F24E2799BD52009BC263 /* cool-blue-icon-app-60x60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "cool-blue-icon-app-60x60@3x.png"; sourceTree = ""; }; @@ -7784,6 +7825,7 @@ FE23EB4726E7C91F005A1698 /* richCommentTemplate.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; name = richCommentTemplate.html; path = Resources/HTML/richCommentTemplate.html; sourceTree = ""; }; FE23EB4826E7C91F005A1698 /* richCommentStyle.css */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.css; name = richCommentStyle.css; path = Resources/HTML/richCommentStyle.css; sourceTree = ""; }; FE25C234271F23000084E1DB /* ReaderCommentsNotificationSheetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReaderCommentsNotificationSheetViewController.swift; sourceTree = ""; }; + FE2E3728281C839C00A1E82A /* BloggingPromptsServiceTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsServiceTests.swift; sourceTree = ""; }; FE32EFFE275914390040BE67 /* MenuSheetViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuSheetViewController.swift; sourceTree = ""; }; FE32F001275F602E0040BE67 /* CommentContentRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentContentRenderer.swift; sourceTree = ""; }; FE32F005275F62620040BE67 /* WebCommentContentRenderer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebCommentContentRenderer.swift; sourceTree = ""; }; @@ -7803,6 +7845,7 @@ FEA088002696E7F600193358 /* ListTableHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListTableHeaderView.swift; sourceTree = ""; }; FEA088022696E81F00193358 /* ListTableHeaderView.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = ListTableHeaderView.xib; sourceTree = ""; }; FEA088042696F7AA00193358 /* WPStyleGuide+List.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WPStyleGuide+List.swift"; sourceTree = ""; }; + FEA6517A281C491C002EA086 /* BloggingPromptsService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BloggingPromptsService.swift; sourceTree = ""; }; FEA7948C26DD136700CEC520 /* CommentHeaderTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommentHeaderTableViewCell.swift; sourceTree = ""; }; FEA7948F26DF7F3700CEC520 /* WPStyleGuide+CommentDetail.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WPStyleGuide+CommentDetail.swift"; sourceTree = ""; }; FEAC916D28001FC4005026E7 /* AvatarTrainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarTrainView.swift; sourceTree = ""; }; @@ -8185,6 +8228,14 @@ path = Classes; sourceTree = ""; }; + 081E4B4A281BFB520085E89C /* Feature Highlight */ = { + isa = PBXGroup; + children = ( + 081E4B4B281C019A0085E89C /* TooltipAnchor.swift */, + ); + path = "Feature Highlight"; + sourceTree = ""; + }; 086C4D0C1E81F7920011D960 /* Media */ = { isa = PBXGroup; children = ( @@ -8357,6 +8408,7 @@ FAA9084B27BD60710093FFA8 /* MySiteViewController+QuickStart.swift */, F56A33322538C0ED00E2AEF3 /* MySiteViewController+FAB.swift */, FA4F383527D766020068AAF5 /* MySiteSettings.swift */, + C7B7CC6F2812FDCE007B9807 /* MySiteViewController+OnboardingPrompt.swift */, ); path = "My Site"; sourceTree = ""; @@ -11332,6 +11384,7 @@ C533CF320E6D3AB3000C3DE8 /* Comments */, F1C740BD26B18DEA005D0809 /* Developer */, 173BCE711CEB365400AE8817 /* Domains */, + 081E4B4A281BFB520085E89C /* Feature Highlight */, 98AA9F1F27EA888C00B3A98C /* Feature Introduction */, 7E3E9B6E2177C9C300FD5797 /* Gutenberg */, E1F391ED1FF25DEC00DB32A3 /* Jetpack */, @@ -11885,6 +11938,7 @@ F1ADCAF6241FEF0C00F150D2 /* AtomicAuthenticationService.swift */, F12FA5D82428FA8F0054DA21 /* AuthenticationService.swift */, 46F584812624DCC80010A723 /* BlockEditorSettingsService.swift */, + FEA6517A281C491C002EA086 /* BloggingPromptsService.swift */, 822D60B81F4CCC7A0016C46D /* BlogJetpackSettingsService.swift */, 93C1148318EDF6E100DAC95C /* BlogService.h */, 93C1148418EDF6E100DAC95C /* BlogService.m */, @@ -12150,6 +12204,7 @@ 98563DDC21BF30C40006F5E9 /* TabbedTotalsCell.xib */, 176CE91527FB44C100F1E32B /* StatsBaseCell.swift */, 17ABD3512811A48900B1E9CB /* StatsMostPopularTimeInsightsCell.swift */, + 17870A6F2816F2A000D1C627 /* StatsLatestPostSummaryInsightsCell.swift */, ); path = Insights; sourceTree = ""; @@ -12682,6 +12737,7 @@ AC34397B0E11443300E5D79B /* Blog */ = { isa = PBXGroup; children = ( + C77FC90628009C3C00726F00 /* Onboarding Questions Prompt */, 3F170D2A2654615900F6F670 /* Blogging Reminders */, FA73D7E72798766300DF24B3 /* Site Picker */, 1716AEFA25F2926C00CF49EC /* My Site */, @@ -13243,6 +13299,7 @@ 575802122357C41200E4C63C /* MediaCoordinatorTests.swift */, 46B30B772582C7DD00A25E66 /* SiteAddressServiceTests.swift */, 17FC0031264D728E00FCBD37 /* SharingServiceTests.swift */, + FE2E3728281C839C00A1E82A /* BloggingPromptsServiceTests.swift */, ); name = Services; sourceTree = ""; @@ -13464,6 +13521,7 @@ isa = PBXGroup; children = ( BE1071FB1BC75E7400906AFF /* WPStyleGuide+Blog.swift */, + 836498C728172C5900A2C170 /* WPStyleGuide+BloggingPrompts.swift */, ); name = Style; sourceTree = ""; @@ -13543,6 +13601,7 @@ CCE911BD221D85E4007E1D4E /* LoginUsernamePasswordScreen.swift */, BE6DD32B1FD6782A00E55192 /* LoginEpilogueScreen.swift */, FA612DDE274E9F730002B03A /* QuickStartPromptScreen.swift */, + C7B7CC7228134347007B9807 /* OnboardingQuestionsPromptScreen.swift */, ); path = Login; sourceTree = ""; @@ -13669,6 +13728,18 @@ path = System; sourceTree = ""; }; + C77FC90628009C3C00726F00 /* Onboarding Questions Prompt */ = { + isa = PBXGroup; + children = ( + C77FC90728009C7000726F00 /* OnboardingQuestionsPromptViewController.swift */, + C77FC90828009C7000726F00 /* OnboardingQuestionsPromptViewController.xib */, + C77FC90D2800CAC100726F00 /* OnboardingEnableNotificationsViewController.swift */, + C77FC90E2800CAC100726F00 /* OnboardingEnableNotificationsViewController.xib */, + C71AF532281064DE00F9E99E /* OnboardingQuestionsCoordinator.swift */, + ); + path = "Onboarding Questions Prompt"; + sourceTree = ""; + }; C7E5F2422799BB1E009BC263 /* cool-blue */ = { isa = PBXGroup; children = ( @@ -14511,6 +14582,7 @@ 8BD8201C24BF9E5200FF25FD /* ReaderWelcomeBannerTests.swift */, 3F1B66A123A2F52A0075F09E /* ReaderPostActions */, 3F5094592454EC7A00C4470B /* Tabbed Reader */, + 08C42C30281807880034720B /* ReaderSubscribeCommentsActionTests.swift */, ); name = Reader; sourceTree = ""; @@ -14816,6 +14888,8 @@ children = ( F5E032E32408D537003AF350 /* ActionSheetViewController.swift */, F5E032E52408D537003AF350 /* BottomSheetPresentationController.swift */, + 836498CD281735CC00A2C170 /* BloggingPromptsHeaderView.swift */, + 836498CA2817301800A2C170 /* BloggingPromptsHeaderView.xib */, ); path = "Action Sheet"; sourceTree = ""; @@ -15310,6 +15384,7 @@ buildConfigurationList = 3F526C612538CF2C0069706C /* Build configuration list for PBXNativeTarget "WordPressStatsWidgets" */; buildPhases = ( 0AA1A8899C01FEF3599F6FCF /* [CP] Check Pods Manifest.lock */, + 09DBEA51281333610019724E /* [Lint] Check AppLocalizedString usage */, 3F526C482538CF2A0069706C /* Sources */, 3F526C492538CF2A0069706C /* Frameworks */, 3F526C4A2538CF2A0069706C /* Resources */, @@ -15350,6 +15425,7 @@ isa = PBXNativeTarget; buildConfigurationList = 733F36152126197800988727 /* Build configuration list for PBXNativeTarget "WordPressNotificationContentExtension" */; buildPhases = ( + 09DBEA52281333700019724E /* [Lint] Check AppLocalizedString usage */, 733F35FF2126197800988727 /* Sources */, 733F36002126197800988727 /* Frameworks */, 733F36012126197800988727 /* Resources */, @@ -15368,6 +15444,7 @@ buildConfigurationList = 7358E6C4210BD318002323EB /* Build configuration list for PBXNativeTarget "WordPressNotificationServiceExtension" */; buildPhases = ( BAE780768320204E29A6FE5B /* [CP] Check Pods Manifest.lock */, + 09DBEA53281333770019724E /* [Lint] Check AppLocalizedString usage */, 7358E6B4210BD318002323EB /* Sources */, 7358E6B5210BD318002323EB /* Frameworks */, 7358E6B6210BD318002323EB /* Resources */, @@ -15387,6 +15464,7 @@ buildConfigurationList = 74576681202B558C00F42E40 /* Build configuration list for PBXNativeTarget "WordPressDraftActionExtension" */; buildPhases = ( 74CC431A202B5C73000DAE1A /* [CP] Check Pods Manifest.lock */, + 09DBEA4D281333060019724E /* [Lint] Check AppLocalizedString usage */, 7457666E202B558C00F42E40 /* Sources */, 7457666F202B558C00F42E40 /* Frameworks */, 74576670202B558C00F42E40 /* Resources */, @@ -15425,6 +15503,7 @@ buildConfigurationList = 932225B71C7CE50400443B02 /* Build configuration list for PBXNativeTarget "WordPressShareExtension" */; buildPhases = ( 4F4D5C2BB6478A3E90ADC3C5 /* [CP] Check Pods Manifest.lock */, + 09DBEA4C281329ED0019724E /* [Lint] Check AppLocalizedString usage */, 932225A31C7CE50300443B02 /* Sources */, 932225A41C7CE50300443B02 /* Frameworks */, 932225A51C7CE50300443B02 /* Resources */, @@ -15444,6 +15523,7 @@ buildConfigurationList = 93E5284D19A7741A003A1A9C /* Build configuration list for PBXNativeTarget "WordPressTodayWidget" */; buildPhases = ( 4CB8AA817C9BD74F3416B27C /* [CP] Check Pods Manifest.lock */, + 09DBEA4E2813334B0019724E /* [Lint] Check AppLocalizedString usage */, 93E5283619A7741A003A1A9C /* Sources */, 93E5283719A7741A003A1A9C /* Frameworks */, 93E5283819A7741A003A1A9C /* Resources */, @@ -15463,6 +15543,7 @@ buildConfigurationList = 98A3C2FF239997DB0048D38D /* Build configuration list for PBXNativeTarget "WordPressThisWeekWidget" */; buildPhases = ( 591AAEE0843D274DDFF16F69 /* [CP] Check Pods Manifest.lock */, + 09DBEA50281333590019724E /* [Lint] Check AppLocalizedString usage */, 98A3C2EB239997DA0048D38D /* Sources */, 98A3C2EC239997DA0048D38D /* Frameworks */, 98A3C2ED239997DA0048D38D /* Resources */, @@ -15482,6 +15563,7 @@ buildConfigurationList = 98D31B9E2396ED7F009CFF43 /* Build configuration list for PBXNativeTarget "WordPressAllTimeWidget" */; buildPhases = ( FF1C536C9FA7489B5AAA0FC2 /* [CP] Check Pods Manifest.lock */, + 09DBEA4F281333530019724E /* [Lint] Check AppLocalizedString usage */, 98D31B8A2396ED7E009CFF43 /* Sources */, 98D31B8B2396ED7E009CFF43 /* Frameworks */, 98D31B8C2396ED7E009CFF43 /* Resources */, @@ -15520,6 +15602,7 @@ buildConfigurationList = F1F163DC25658B4D003DC13B /* Build configuration list for PBXNativeTarget "WordPressIntents" */; buildPhases = ( CE51D1C75430FDDD21B27F64 /* [CP] Check Pods Manifest.lock */, + 09DBEA542813337F0019724E /* [Lint] Check AppLocalizedString usage */, F1F163BA25658B4D003DC13B /* Sources */, F1F163BB25658B4D003DC13B /* Frameworks */, F1F163BC25658B4D003DC13B /* Resources */, @@ -15911,6 +15994,7 @@ C7E5F2532799BD54009BC263 /* cool-blue-icon-app-60x60@3x.png in Resources */, 1761F17E26209AEE000815EF /* open-source-icon-app-76x76.png in Resources */, 17222DAE261DDDF90047B163 /* spectrum-classic-icon-app-76x76.png in Resources */, + C77FC9112800CAC100726F00 /* OnboardingEnableNotificationsViewController.xib in Resources */, 17222D9F261DDDF90047B163 /* pink-classic-icon-app-76x76@2x.png in Resources */, 439F4F38219B636500F8D0C7 /* Revisions.storyboard in Resources */, 4019B27120885AB900A0C7EB /* ActivityDetailViewController.storyboard in Resources */, @@ -16017,6 +16101,7 @@ 1761F17326209AEE000815EF /* open-source-dark-icon-app-60x60@2x.png in Resources */, 1761F18B26209AEE000815EF /* hot-pink-icon-app-83.5x83.5@2x.png in Resources */, C7E5F25A2799C2B0009BC263 /* blue-icon-app-76x76.png in Resources */, + C77FC90B28009C7000726F00 /* OnboardingQuestionsPromptViewController.xib in Resources */, 17222DA6261DDDF90047B163 /* spectrum-icon-app-76x76.png in Resources */, E149771A1C0DCB6F0057CD60 /* MediaSizeSliderCell.xib in Resources */, 17222D98261DDDF90047B163 /* pink-icon-app-83.5x83.5@2x.png in Resources */, @@ -16049,6 +16134,7 @@ 9808655A203D075E00D58786 /* EpilogueUserInfoCell.xib in Resources */, C7E5F2552799BD54009BC263 /* cool-blue-icon-app-83.5x83.5@2x.png in Resources */, 17222D92261DDDF90047B163 /* blue-classic-icon-app-83.5x83.5@2x.png in Resources */, + 836498CB2817301800A2C170 /* BloggingPromptsHeaderView.xib in Resources */, 17222D90261DDDF90047B163 /* blue-classic-icon-app-60x60@2x.png in Resources */, E6D2E1611B8AA4410000ED14 /* ReaderTagStreamHeader.xib in Resources */, 577C2AB62294401800AD1F03 /* PostCompactCell.xib in Resources */, @@ -16360,6 +16446,7 @@ FABB1FC12602FC2C00C8785C /* defaultPostTemplate.html in Resources */, FABB1FC32602FC2C00C8785C /* defaultPostTemplate_old.html in Resources */, FABB1FC42602FC2C00C8785C /* ReaderInterestsCollectionViewCell.xib in Resources */, + 836498CC2817301800A2C170 /* BloggingPromptsHeaderView.xib in Resources */, FABB1FC52602FC2C00C8785C /* StatsGhostTopHeaderCell.xib in Resources */, 9856A38A261FC206008D6354 /* UserProfileUserInfoCell.xib in Resources */, FABB1FC72602FC2C00C8785C /* RegisterDomainDetailsFooterView.xib in Resources */, @@ -16438,6 +16525,7 @@ FABB202A2602FC2C00C8785C /* PostSignUpInterstitialViewController.xib in Resources */, FABB202B2602FC2C00C8785C /* CollapsableHeaderViewController.xib in Resources */, FABB202C2602FC2C00C8785C /* ReaderRelatedPostsSectionHeaderView.xib in Resources */, + C77FC90C28009C7000726F00 /* OnboardingQuestionsPromptViewController.xib in Resources */, FABB202D2602FC2C00C8785C /* PostingActivityMonth.xib in Resources */, FABB202E2602FC2C00C8785C /* Menus.storyboard in Resources */, FABB202F2602FC2C00C8785C /* CountriesMapView.xib in Resources */, @@ -16457,6 +16545,7 @@ FABB20422602FC2C00C8785C /* Reader.storyboard in Resources */, FABB20442602FC2C00C8785C /* RestoreWarningView.xib in Resources */, FABB20452602FC2C00C8785C /* JetpackLoginViewController.xib in Resources */, + C77FC9122800CAC100726F00 /* OnboardingEnableNotificationsViewController.xib in Resources */, FABB20472602FC2C00C8785C /* StatsNoDataRow.xib in Resources */, FABB20482602FC2C00C8785C /* JetpackScanThreatCell.xib in Resources */, FABB20492602FC2C00C8785C /* JetpackScanStatusCell.xib in Resources */, @@ -16595,6 +16684,186 @@ shellScript = "$SRCROOT/../Scripts/BuildPhases/GenerateCredentials.sh\n"; showEnvVarsInLog = 0; }; + 09DBEA4C281329ED0019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; + 09DBEA4D281333060019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; + 09DBEA4E2813334B0019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; + 09DBEA4F281333530019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; + 09DBEA50281333590019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; + 09DBEA51281333610019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; + 09DBEA52281333700019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; + 09DBEA53281333770019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; + 09DBEA542813337F0019724E /* [Lint] Check AppLocalizedString usage */ = { + isa = PBXShellScriptBuildPhase; + alwaysOutOfDate = 1; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + ); + inputPaths = ( + ); + name = "[Lint] Check AppLocalizedString usage"; + outputFileListPaths = ( + ); + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = "/bin/bash -eu"; + shellScript = "\"$SRCROOT/../Scripts/BuildPhases/runRubyScript\" \"LintAppLocalizedStringsUsage.rb\" \"${TARGET_NAME}\"\n"; + showEnvVarsInLog = 0; + }; 0AA1A8899C01FEF3599F6FCF /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -17839,6 +18108,7 @@ D853723C21952DC90076F461 /* SiteSegmentsStep.swift in Sources */, 32E1BFDA24A66F2A007A08F0 /* ReaderInterestsCollectionViewFlowLayout.swift in Sources */, FEC3B81726C2915A00A395C7 /* SingleButtonTableViewCell.swift in Sources */, + 836498C828172C5900A2C170 /* WPStyleGuide+BloggingPrompts.swift in Sources */, FF70A3221FD5840500BC270D /* PHAsset+Metadata.swift in Sources */, 5DA5BF4418E32DCF005F11F9 /* Theme.m in Sources */, D8A3A5B1206A49A100992576 /* StockPhotosMediaGroup.swift in Sources */, @@ -17982,6 +18252,7 @@ FAA4013427B52455009E1137 /* QuickActionButton.swift in Sources */, 32A218D8251109DB00D1AE6C /* ReaderReportPostAction.swift in Sources */, FA681F8A25CA946B00DAA544 /* BaseRestoreStatusFailedViewController.swift in Sources */, + 081E4B4C281C019A0085E89C /* TooltipAnchor.swift in Sources */, 3F851415260D0A3300A4B938 /* UnifiedPrologueEditorContentView.swift in Sources */, 179A70F02729834B006DAC0A /* Binding+OnChange.swift in Sources */, D8D7DF5A20AD18A400B40A2D /* ImgUploadProcessor.swift in Sources */, @@ -18440,6 +18711,7 @@ 821738091FE04A9E00BEC94C /* DateAndTimeFormatSettingsViewController.swift in Sources */, 5D6C4B081B603E03005E3C43 /* WPContentSyncHelper.swift in Sources */, 73C8F06021BEED9100DDDF7E /* SiteAssemblyStep.swift in Sources */, + 17870A702816F2A000D1C627 /* StatsLatestPostSummaryInsightsCell.swift in Sources */, 82C420761FE44BD900CFB15B /* SiteSettingsViewController+Swift.swift in Sources */, 8BBC778B27B5531700DBA087 /* BlogDashboardPersistence.swift in Sources */, F5E29038243FAB0300C19CA5 /* FilterTableData.swift in Sources */, @@ -18849,6 +19121,7 @@ FF619DD51C75246900903B65 /* CLPlacemark+Formatting.swift in Sources */, 98467A3F221CD48500DF51AE /* SiteStatsDetailTableViewController.swift in Sources */, E11450DF1C4E47E600A6BD0F /* MessageAnimator.swift in Sources */, + C77FC90F2800CAC100726F00 /* OnboardingEnableNotificationsViewController.swift in Sources */, FA4F65A72594337300EAA9F5 /* JetpackRestoreOptionsViewController.swift in Sources */, 7E14635720B3BEAB00B95F41 /* WPStyleGuide+Loader.swift in Sources */, 087EBFA81F02313E001F7ACE /* MediaThumbnailService.swift in Sources */, @@ -18876,8 +19149,10 @@ 3F3DD0AF26FCDA3100F5F121 /* PresentationButton.swift in Sources */, 988AC37522F10DD900BC1433 /* FileDownloadsStatsRecordValue+CoreDataProperties.swift in Sources */, E1A03EE217422DCF0085D192 /* BlogToAccount.m in Sources */, + C77FC90928009C7000726F00 /* OnboardingQuestionsPromptViewController.swift in Sources */, 8BE6F92C27EE27DB0008BDC7 /* BlogDashboardPostCardGhostCell.swift in Sources */, FA4F660525946B5F00EAA9F5 /* JetpackRestoreHeaderView.swift in Sources */, + FEA6517B281C491C002EA086 /* BloggingPromptsService.swift in Sources */, 436D55DF210F866900CEAA33 /* StoryboardLoadable.swift in Sources */, D8212CC320AA7F57008E8AE8 /* ReaderBlockSiteAction.swift in Sources */, 5D44EB381986D8BA008B7175 /* ReaderSiteService.m in Sources */, @@ -18933,6 +19208,7 @@ 17A28DCB2052FB5D00EA6D9E /* AuthorFilterViewController.swift in Sources */, 3F946C592684DD8E00B946F6 /* BloggingRemindersActions.swift in Sources */, 08D345521CD7F50900358E8C /* MenusSelectionItemView.m in Sources */, + C7B7CC702812FDCE007B9807 /* MySiteViewController+OnboardingPrompt.swift in Sources */, C81CCD6F243AF7D700A83E27 /* TenorReponseParser.swift in Sources */, 4020B2BD2007AC850002C963 /* WPStyleGuide+Gridicon.swift in Sources */, FF4258501BA092EE00580C68 /* RelatedPostsSettingsViewController.m in Sources */, @@ -18988,6 +19264,7 @@ C94C0B1B25DCFA0100F2F69B /* FilterableCategoriesViewController.swift in Sources */, 591AA5021CEF9BF20074934F /* Post+CoreDataProperties.swift in Sources */, E19B17AE1E5C6944007517C6 /* BasePost.swift in Sources */, + C71AF533281064DE00F9E99E /* OnboardingQuestionsCoordinator.swift in Sources */, 7E7947A9210BAC1D005BB851 /* NotificationContentRange.swift in Sources */, 8B6EA62323FDE50B004BA312 /* PostServiceUploadingList.swift in Sources */, E1EBC36F1C118EA500F638E0 /* ImmuTable.swift in Sources */, @@ -19015,6 +19292,7 @@ 8B05D29323AA572A0063B9AA /* GutenbergMediaEditorImage.swift in Sources */, B532D4EA199D4357006E4DF6 /* NoteBlockHeaderTableViewCell.swift in Sources */, 24ADA24C24F9A4CB001B5DAE /* RemoteFeatureFlagStore.swift in Sources */, + 836498CE281735CC00A2C170 /* BloggingPromptsHeaderView.swift in Sources */, 319D6E8519E44F7F0013871C /* SuggestionsTableViewCell.m in Sources */, 40A71C69220E1952002E3D25 /* LastPostStatsRecordValue+CoreDataClass.swift in Sources */, 98AA6D1126B8CE7200920C8B /* Comment+CoreDataClass.swift in Sources */, @@ -19111,6 +19389,7 @@ 3F2F854826FAEEEC000FCDA5 /* EditorPublishEpilogueScreen.swift in Sources */, 3F2F854326FAEA50000FCDA5 /* JetpackBackupScreen.swift in Sources */, 3F762E9526784B540088CD45 /* WireMock.swift in Sources */, + C7B7CC7328134347007B9807 /* OnboardingQuestionsPromptScreen.swift in Sources */, 3FE39A3F26F8384E006E2B3A /* StatsScreen.swift in Sources */, 3FE39A3126F836A5006E2B3A /* LoginSiteAddressScreen.swift in Sources */, 3F2F855126FAF227000FCDA5 /* WelcomeScreenLoginComponent.swift in Sources */, @@ -19187,6 +19466,7 @@ C737554027C80F1300C6E9A1 /* String+CondenseWhitespace.swift in Sources */, 7335AC6D21220F0F0012EF2D /* FormattableUserContent.swift in Sources */, 7335AC6221220E690012EF2D /* FormattableContentFactory.swift in Sources */, + 09DBEA55281336E10019724E /* AppLocalizedString.swift in Sources */, 433ADC1A223B2A7D00ED9DE1 /* TextBundleWrapper.m in Sources */, 7335AC6C21220F050012EF2D /* FormattableNoticonRange.swift in Sources */, 73F6DD42212BA54700CE447D /* RichNotificationContentFormatter.swift in Sources */, @@ -19515,6 +19795,7 @@ B0A6DEBF2626335F00B5B8EF /* AztecPostViewController+MenuTests.swift in Sources */, 4054F43E221357B600D261AB /* TopCommentedPostStatsRecordValueTests.swift in Sources */, 93B853231B4416A30064FE72 /* WPAnalyticsTrackerAutomatticTracksTests.m in Sources */, + FE2E3729281C839C00A1E82A /* BloggingPromptsServiceTests.swift in Sources */, D848CC0720FF2BE200A9038F /* NotificationContentRangeFactoryTests.swift in Sources */, 732A473F21878EB10015DA74 /* WPRichContentViewTests.swift in Sources */, 8BDA5A6D247C2F8400AB124C /* ReaderDetailViewControllerTests.swift in Sources */, @@ -19712,6 +19993,7 @@ 57D6C83E22945A10003DDC7E /* PostCompactCellTests.swift in Sources */, B030FE0A27EBF0BC000F6F5E /* SiteCreationIntentTracksEventTests.swift in Sources */, D81C2F5C20F872C2002AE1F1 /* ReplyToCommentActionTests.swift in Sources */, + 08C42C31281807880034720B /* ReaderSubscribeCommentsActionTests.swift in Sources */, D848CC1720FF38EA00A9038F /* FormattableCommentRangeTests.swift in Sources */, 246D0A0325E97D5D0028B83F /* Blog+ObjcTests.m in Sources */, 9A9D34FF2360A4E200BC95A3 /* StatsPeriodAsyncOperationTests.swift in Sources */, @@ -19858,6 +20140,7 @@ FABB21012602FC2C00C8785C /* ReaderCardDiscoverAttributionView.swift in Sources */, FABB21022602FC2C00C8785C /* Plugin.swift in Sources */, FABB21032602FC2C00C8785C /* JetpackActivityLogViewController.swift in Sources */, + 17870A712816F2A000D1C627 /* StatsLatestPostSummaryInsightsCell.swift in Sources */, FABB21042602FC2C00C8785C /* FormattableMediaContent.swift in Sources */, FABB21052602FC2C00C8785C /* CollabsableHeaderFilterCollectionViewCell.swift in Sources */, FABB21062602FC2C00C8785C /* SearchResultsStatsRecordValue+CoreDataClass.swift in Sources */, @@ -19880,6 +20163,7 @@ FABB21132602FC2C00C8785C /* AuthenticationService.swift in Sources */, FABB21142602FC2C00C8785C /* JetpackSiteRef.swift in Sources */, FABB21152602FC2C00C8785C /* WPStyleGuide+Reply.swift in Sources */, + 836498CF281735CC00A2C170 /* BloggingPromptsHeaderView.swift in Sources */, FABB21162602FC2C00C8785C /* WPBlogTableViewCell.m in Sources */, FABB21172602FC2C00C8785C /* JetpackBackupOptionsViewController.swift in Sources */, FABB21182602FC2C00C8785C /* TopViewedVideoStatsRecordValue+CoreDataProperties.swift in Sources */, @@ -20191,6 +20475,7 @@ FABB221E2602FC2C00C8785C /* PostEditorNavigationBarManager.swift in Sources */, FABB221F2602FC2C00C8785C /* Charts+LargeValueFormatter.swift in Sources */, FABB22202602FC2C00C8785C /* CustomHighlightButton.m in Sources */, + C77FC9102800CAC100726F00 /* OnboardingEnableNotificationsViewController.swift in Sources */, FABB22212602FC2C00C8785C /* UniversalLinkRouter.swift in Sources */, FABB22222602FC2C00C8785C /* LightNavigationController.swift in Sources */, FA20751527A86B73001A644D /* UIScrollView+Helpers.swift in Sources */, @@ -20216,6 +20501,7 @@ FABB22332602FC2C00C8785C /* ReaderTableCardCell.swift in Sources */, FABB22342602FC2C00C8785C /* ShareNoticeNavigationCoordinator.swift in Sources */, FABB22352602FC2C00C8785C /* CameraCaptureCoordinator.swift in Sources */, + C77FC90A28009C7000726F00 /* OnboardingQuestionsPromptViewController.swift in Sources */, FABB22362602FC2C00C8785C /* HomeWidgetCache.swift in Sources */, FABB22372602FC2C00C8785C /* JetpackRestoreStatusCoordinator.swift in Sources */, FABB22382602FC2C00C8785C /* EventLoggingDelegate.swift in Sources */, @@ -20390,6 +20676,7 @@ FABB22C52602FC2C00C8785C /* ActivityStore.swift in Sources */, FABB22C62602FC2C00C8785C /* NSAttributedString+WPRichText.swift in Sources */, FABB22C72602FC2C00C8785C /* StatsTotalRow.swift in Sources */, + 836498C928172C5900A2C170 /* WPStyleGuide+BloggingPrompts.swift in Sources */, C79C308226EA99D500E88514 /* ReferrerDetailsSpamActionCell.swift in Sources */, 80EF672327F160720063B138 /* DashboardCustomAnnouncementCell.swift in Sources */, FABB22C82602FC2C00C8785C /* SiteCreationAnalyticsHelper.swift in Sources */, @@ -20880,6 +21167,7 @@ FABB24732602FC2C00C8785C /* PostTagService.m in Sources */, FABB24742602FC2C00C8785C /* ReaderTabViewModel.swift in Sources */, FADFBD27265F580500039C41 /* MultilineButton.swift in Sources */, + C71AF534281064DE00F9E99E /* OnboardingQuestionsCoordinator.swift in Sources */, FABB24752602FC2C00C8785C /* ReaderSearchSuggestionService.swift in Sources */, FABB24762602FC2C00C8785C /* WPTabBarController+WhatIsNew.swift in Sources */, FABB24772602FC2C00C8785C /* CachedAnimatedImageView.swift in Sources */, @@ -21113,6 +21401,7 @@ FABB253A2602FC2C00C8785C /* WordPressAppDelegate.swift in Sources */, 098B8577275E9765004D299F /* AppLocalizedString.swift in Sources */, FABB253B2602FC2C00C8785C /* MediaService.m in Sources */, + FEA6517C281C491C002EA086 /* BloggingPromptsService.swift in Sources */, FABB253C2602FC2C00C8785C /* FormattableContentAction.swift in Sources */, 3F3DD0B326FD176800F5F121 /* PresentationCard.swift in Sources */, FABB253D2602FC2C00C8785C /* SiteVerticalsService.swift in Sources */, @@ -21216,6 +21505,7 @@ FABB25912602FC2C00C8785C /* FormattableActivity.swift in Sources */, FABB25922602FC2C00C8785C /* RevisionPreviewTextViewManager.swift in Sources */, FABB25932602FC2C00C8785C /* StatsChartLegendView.swift in Sources */, + C7B7CC712812FDCE007B9807 /* MySiteViewController+OnboardingPrompt.swift in Sources */, FABB25942602FC2C00C8785C /* FindOutMoreCell.swift in Sources */, FABB25952602FC2C00C8785C /* NSURL+Exporters.swift in Sources */, FABB25962602FC2C00C8785C /* FileDownloadsStatsRecordValue+CoreDataProperties.swift in Sources */, @@ -25754,6 +26044,7 @@ E125443B12BF5A7200D87A0A /* WordPress.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 17870A72281847D500D1C627 /* WordPress 139.xcdatamodel */, FE59DA9527D1FD0700624D26 /* WordPress 138.xcdatamodel */, FE97BC13274FCE7A00CF08F9 /* WordPress 137.xcdatamodel */, FEFC0F872730510F001F7F1D /* WordPress 136.xcdatamodel */, @@ -25893,7 +26184,7 @@ 8350E15911D28B4A00A7B073 /* WordPress.xcdatamodel */, E125443D12BF5A7200D87A0A /* WordPress 2.xcdatamodel */, ); - currentVersion = FE59DA9527D1FD0700624D26 /* WordPress 138.xcdatamodel */; + currentVersion = 17870A72281847D500D1C627 /* WordPress 139.xcdatamodel */; name = WordPress.xcdatamodeld; path = Classes/WordPress.xcdatamodeld; sourceTree = ""; diff --git a/WordPress/WordPressNotificationServiceExtension/Sources/NotificationService.swift b/WordPress/WordPressNotificationServiceExtension/Sources/NotificationService.swift index c4ecfda2dc3d..80b8d926680e 100644 --- a/WordPress/WordPressNotificationServiceExtension/Sources/NotificationService.swift +++ b/WordPress/WordPressNotificationServiceExtension/Sources/NotificationService.swift @@ -329,5 +329,5 @@ private extension NotificationService { return content } - static let viewMilestoneTitle = NSLocalizedString("You hit a milestone 🚀", comment: "Title for a view milestone push notification") + static let viewMilestoneTitle = AppLocalizedString("You hit a milestone 🚀", comment: "Title for a view milestone push notification") } diff --git a/WordPress/WordPressTest/AccountServiceTests.swift b/WordPress/WordPressTest/AccountServiceTests.swift index d37876344052..cafceee99e92 100644 --- a/WordPress/WordPressTest/AccountServiceTests.swift +++ b/WordPress/WordPressTest/AccountServiceTests.swift @@ -10,7 +10,6 @@ class AccountServiceTests: XCTestCase { super.setUp() contextManager = TestContextManager() - contextManager.requiresTestExpectation = false accountService = AccountService(managedObjectContext: contextManager.mainContext) } diff --git a/WordPress/WordPressTest/AtomicAuthenticationServiceTests.swift b/WordPress/WordPressTest/AtomicAuthenticationServiceTests.swift index 9b2410c9f405..e9ca0d2a3299 100644 --- a/WordPress/WordPressTest/AtomicAuthenticationServiceTests.swift +++ b/WordPress/WordPressTest/AtomicAuthenticationServiceTests.swift @@ -11,7 +11,6 @@ class AtomicAuthenticationServiceTests: XCTestCase { super.setUp() contextManager = TestContextManager() - contextManager.requiresTestExpectation = false let api = WordPressComRestApi(oAuthToken: "") let remote = AtomicAuthenticationServiceRemote(wordPressComRestApi: api) diff --git a/WordPress/WordPressTest/BlogJetpackTest.m b/WordPress/WordPressTest/BlogJetpackTest.m index a4684e6aa603..4fbdc9a7f735 100644 --- a/WordPress/WordPressTest/BlogJetpackTest.m +++ b/WordPress/WordPressTest/BlogJetpackTest.m @@ -75,19 +75,17 @@ - (void)testJetpackUsername { } - (void)testJetpackSetupDoesntReplaceDotcomAccount { - XCTestExpectation *saveExpectation = [self expectationWithDescription:@"Context save expectation"]; - self.testContextManager.testExpectation = saveExpectation; + XCTestExpectation *saveExpectation = [self expectationForNotification:NSManagedObjectContextDidSaveNotification object:self.testContextManager.mainContext handler:nil]; - AccountService *accountService = [[AccountService alloc] initWithManagedObjectContext:[ContextManager sharedInstance].mainContext]; + AccountService *accountService = [[AccountService alloc] initWithManagedObjectContext:self.testContextManager.mainContext]; WPAccount *wpComAccount = [accountService createOrUpdateAccountWithUsername:@"user" authToken:@"token"]; - [self waitForExpectationsWithTimeout:2.0 handler:nil]; + [self waitForExpectations:@[saveExpectation] timeout:2.0]; WPAccount * defaultAccount = [accountService defaultWordPressComAccount]; XCTAssertEqualObjects(wpComAccount, defaultAccount); - saveExpectation = [self expectationWithDescription:@"Context save expectation"]; - self.testContextManager.testExpectation = saveExpectation; + saveExpectation = [self expectationForNotification:NSManagedObjectContextDidSaveNotification object:self.testContextManager.mainContext handler:nil]; [accountService createOrUpdateAccountWithUsername:@"test1" authToken:@"token1"]; - [self waitForExpectationsWithTimeout:2.0 handler:nil]; + [self waitForExpectations:@[saveExpectation] timeout:2.0]; defaultAccount = [accountService defaultWordPressComAccount]; XCTAssertEqualObjects(wpComAccount, defaultAccount); } @@ -101,8 +99,7 @@ - (void)testWPCCShouldntDuplicateBlogs { statusCode:200 headers:@{@"Content-Type":@"application/json"}]; }]; - XCTestExpectation *saveExpectation = [self expectationWithDescription:@"Context save expectation"]; - self.testContextManager.testExpectation = saveExpectation; + XCTestExpectation *saveExpectation = [self expectationForNotification:NSManagedObjectContextDidSaveNotification object:self.testContextManager.mainContext handler:nil]; AccountService *accountService = [[AccountService alloc] initWithManagedObjectContext:self.testContextManager.mainContext]; BlogService *blogService = [[BlogService alloc] initWithManagedObjectContext:self.testContextManager.mainContext]; @@ -130,7 +127,7 @@ - (void)testWPCCShouldntDuplicateBlogs { }; // Wait on the merge to be completed - [self waitForExpectationsWithTimeout:2.0 handler:nil]; + [self waitForExpectations:@[saveExpectation] timeout:2.0]; // test.blog + wp.com + jetpack XCTAssertEqual(1, [accountService numberOfAccounts]); @@ -174,8 +171,7 @@ - (void)testSyncBlogsMigratesJetpackSSL statusCode:200 headers:@{@"Content-Type":@"application/json"}]; }]; - XCTestExpectation *saveExpectation = [self expectationWithDescription:@"Context save expectation"]; - self.testContextManager.testExpectation = saveExpectation; + XCTestExpectation *saveExpectation = [self expectationForNotification:NSManagedObjectContextDidSaveNotification object:self.testContextManager.mainContext handler:nil]; AccountService *accountService = [[AccountService alloc] initWithManagedObjectContext:self.testContextManager.mainContext]; BlogService *blogService = [[BlogService alloc] initWithManagedObjectContext:self.testContextManager.mainContext]; @@ -192,7 +188,7 @@ - (void)testSyncBlogsMigratesJetpackSSL jetpackBlog.url = @"https://jetpack.example.com/"; // Wait on the merge to be completed - [self waitForExpectationsWithTimeout:2.0 handler:nil]; + [self waitForExpectations:@[saveExpectation] timeout:2.0]; XCTAssertEqual(1, [accountService numberOfAccounts]); // test.blog + wp.com + jetpack (legacy) diff --git a/WordPress/WordPressTest/BloggingPromptsServiceTests.swift b/WordPress/WordPressTest/BloggingPromptsServiceTests.swift new file mode 100644 index 000000000000..d135064e1a11 --- /dev/null +++ b/WordPress/WordPressTest/BloggingPromptsServiceTests.swift @@ -0,0 +1,153 @@ +import XCTest + +@testable import WordPress + +final class BloggingPromptsServiceTests: XCTestCase { + private let siteID = 1 + private let timeout: TimeInterval = 2 + private var endpoint: String { + "sites/\(siteID)/blogging-prompts" + } + + private var context: NSManagedObjectContext! + private var remote: BloggingPromptsServiceRemoteMock! + private var service: BloggingPromptsService! + private var blog: Blog! + private var accountService: AccountService! + + override func setUp() { + super.setUp() + + context = TestContextManager().mainContext + remote = BloggingPromptsServiceRemoteMock() + blog = makeBlog() + accountService = makeAccountService() + service = BloggingPromptsService(context: context, remote: remote, blog: blog) + } + + override func tearDown() { + context.reset() + ContextManager.overrideSharedInstance(nil) + + context = nil + remote = nil + blog = nil + accountService = nil + service = nil + super.tearDown() + } + + // MARK: - Tests + + func test_fetchPrompts_givenSuccessfulResult_callsSuccessBlock() { + let expectation = expectation(description: "Fetch prompts should succeed") + + service.fetchPrompts { _ in + // TODO: Add mapping tests once CoreData model is added. + expectation.fulfill() + } failure: { _ in + XCTFail("This closure shouldn't be called.") + expectation.fulfill() + } + + wait(for: [expectation], timeout: timeout) + } + + func test_fetchPrompts_givenFailureResult_callsFailureBlock() { + let expectation = expectation(description: "Fetch prompts should fail") + remote.shouldReturnSuccess = false + + service.fetchPrompts { _ in + XCTFail("This closure shouldn't be called.") + expectation.fulfill() + } failure: { _ in + expectation.fulfill() + } + + wait(for: [expectation], timeout: timeout) + } + + func test_fetchPrompts_givenNoParameters_assignsDefaultValue() { + let expectedDifferenceInHours = 10 * 24 // 10 days ago. + let expectedNumber = 24 + remote.shouldReturnSuccess = false + + // call the fetch just to trigger default parameter assignment. the completion blocks can be ignored. + service.fetchPrompts(success: { _ in }, failure: { _ in }) + + XCTAssertNotNil(remote.passedDateParameter) + let passedDate = remote.passedDateParameter! + let differenceInHours = Calendar.autoupdatingCurrent.dateComponents([.hour], from: passedDate, to: Date()).hour! + XCTAssertEqual(differenceInHours, expectedDifferenceInHours) + + XCTAssertNotNil(remote.passedNumberParameter) + XCTAssertEqual(remote.passedNumberParameter!, expectedNumber) + } + + func test_fetchPrompts_givenValidParameters_passesThemToRemote() { + let expectedDate = BloggingPromptsServiceRemoteMock.dateFormatter.date(from: "2022-01-02")! + let expectedNumber = 10 + remote.shouldReturnSuccess = false + + // call the fetch just to trigger default parameter assignment. the completion blocks can be ignored. + service.fetchPrompts(from: expectedDate, number: expectedNumber, success: { _ in }, failure: { _ in }) + + XCTAssertNotNil(remote.passedDateParameter) + XCTAssertEqual(remote.passedDateParameter!, expectedDate) + + XCTAssertNotNil(remote.passedNumberParameter) + XCTAssertEqual(remote.passedNumberParameter!, expectedNumber) + } +} + + +// MARK: - Helpers + +private extension BloggingPromptsServiceTests { + func makeAccountService() -> AccountService { + let service = AccountService(managedObjectContext: context) + let account = service.createOrUpdateAccount(withUsername: "testuser", authToken: "authtoken") + account.userID = NSNumber(value: 1) + service.setDefaultWordPressComAccount(account) + + return service + } + + func makeBlog() -> Blog { + return BlogBuilder(context).isHostedAtWPcom().build() + } +} + +class BloggingPromptsServiceRemoteMock: BloggingPromptsServiceRemote { + var passedSiteID: NSNumber? = nil + var passedNumberParameter: Int? = nil + var passedDateParameter: Date? = nil + var shouldReturnSuccess: Bool = true + + override func fetchPrompts(for siteID: NSNumber, + number: Int? = nil, + fromDate: Date? = nil, + completion: @escaping (Result<[RemoteBloggingPrompt], Error>) -> Void) { + passedSiteID = siteID + passedNumberParameter = number + passedDateParameter = fromDate + + if shouldReturnSuccess { + completion(.success([])) + } else { + completion(.failure(Errors.failed)) + } + } + + enum Errors: Error { + case failed + } + + static var dateFormatter: DateFormatter = { + let formatter = DateFormatter() + formatter.locale = .init(identifier: "en_US_POSIX") + formatter.dateFormat = "yyyy-MM-dd" + + return formatter + }() +} diff --git a/WordPress/WordPressTest/ContextManagerMock.h b/WordPress/WordPressTest/ContextManagerMock.h index fff26a79621d..3fa9ea33d916 100644 --- a/WordPress/WordPressTest/ContextManagerMock.h +++ b/WordPress/WordPressTest/ContextManagerMock.h @@ -9,9 +9,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readwrite, strong) NSManagedObjectModel *managedObjectModel; @property (nonatomic, readwrite, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator; @property (nonatomic, readonly, strong) NSPersistentStoreCoordinator *standardPSC; -@property (nonatomic, readwrite, assign) BOOL requiresTestExpectation; @property (nonatomic, readonly, strong) NSURL *storeURL; -@property (nonatomic, nullable, readwrite, strong) XCTestExpectation *testExpectation; @end /** diff --git a/WordPress/WordPressTest/ContextManagerMock.m b/WordPress/WordPressTest/ContextManagerMock.m index 781146be15b3..86468bf88ec8 100644 --- a/WordPress/WordPressTest/ContextManagerMock.m +++ b/WordPress/WordPressTest/ContextManagerMock.m @@ -13,8 +13,6 @@ @implementation ContextManagerMock @synthesize persistentStoreCoordinator = _persistentStoreCoordinator; @synthesize mainContext = _mainContext; @synthesize managedObjectModel = _managedObjectModel; -@synthesize requiresTestExpectation = _requiresTestExpectation; -@synthesize testExpectation = _testExpectation; - (instancetype)init { @@ -23,7 +21,6 @@ - (instancetype)init // Override the shared ContextManager [ContextManager internalSharedInstance]; [ContextManager overrideSharedInstance:self]; - _requiresTestExpectation = YES; } return self; @@ -79,40 +76,13 @@ - (NSManagedObjectContext *)mainContext return _mainContext; } -- (void)saveContext:(NSManagedObjectContext *)context -{ - [self saveContext:context withCompletionBlock:^{ - if (self.testExpectation) { - [self.testExpectation fulfill]; - self.testExpectation = nil; - } else if (self.requiresTestExpectation) { - NSLog(@"No test expectation present for context save"); - } - }]; -} - - (void)saveContextAndWait:(NSManagedObjectContext *)context { [super saveContextAndWait:context]; - if (self.testExpectation) { - [self.testExpectation fulfill]; - self.testExpectation = nil; - } else if (self.requiresTestExpectation) { - NSLog(@"No test expectation present for context save"); - } -} - -- (void)saveContext:(NSManagedObjectContext *)context withCompletionBlock:(void (^)(void))completionBlock -{ - [super saveContext:context withCompletionBlock:^{ - if (self.testExpectation) { - [self.testExpectation fulfill]; - self.testExpectation = nil; - } else if (self.requiresTestExpectation) { - NSLog(@"No test expectation present for context save"); - } - completionBlock(); - }]; + // FIXME: Remove this method to use superclass one instead + // This log magically resolves a deadlock in + // `ZDashboardCardTests.testShouldNotShowQuickStartIfDefaultSectionIsSiteMenu` + NSLog(@"Context save completed"); } - (NSURL *)storeURL diff --git a/WordPress/WordPressTest/LastPostStatsRecordValueTests.swift b/WordPress/WordPressTest/LastPostStatsRecordValueTests.swift index 00651130b218..44a8d3d60791 100644 --- a/WordPress/WordPressTest/LastPostStatsRecordValueTests.swift +++ b/WordPress/WordPressTest/LastPostStatsRecordValueTests.swift @@ -101,7 +101,8 @@ class LastPostStatsRecordValueTests: StatsTestCase { likesCount: 1, commentsCount: 2, viewsCount: 3, - postID: 4) + postID: 4, + featuredImageURL: URL(string: "https://s.w.org/style/images/about/WordPress-logotype-wmark.png")!) let blog = defaultBlog @@ -123,7 +124,8 @@ class LastPostStatsRecordValueTests: StatsTestCase { XCTAssertEqual(castedResults.likesCount, 1) XCTAssertEqual(castedResults.commentsCount, 2) XCTAssertEqual(castedResults.viewsCount, 3) - XCTAssertEqual(castedResults.url, URL(string: "google.com") ) + XCTAssertEqual(castedResults.url, URL(string: "google.com")) + XCTAssertEqual(castedResults.featuredImageURL, URL(string: "https://s.w.org/style/images/about/WordPress-logotype-wmark.png")) } @discardableResult func createLastPostStatsRecordValue(parent: StatsRecord) -> LastPostStatsRecordValue { diff --git a/WordPress/WordPressTest/NotificationSyncMediatorTests.swift b/WordPress/WordPressTest/NotificationSyncMediatorTests.swift index 941d648ce65a..f267be4a0dbe 100644 --- a/WordPress/WordPressTest/NotificationSyncMediatorTests.swift +++ b/WordPress/WordPressTest/NotificationSyncMediatorTests.swift @@ -62,8 +62,7 @@ class NotificationSyncMediatorTests: XCTestCase { XCTAssert(manager.mainContext.countObjects(ofType: Notification.self) == 0) // CoreData Expectations - manager.testExpectation = expectation(description: "Context save expectation") - + let contextSaved = expectation(forNotification: .NSManagedObjectContextDidSave, object: manager.mainContext) // Mediator Expectations let expect = expectation(description: "Sync") @@ -74,7 +73,7 @@ class NotificationSyncMediatorTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: timeout, handler: nil) + wait(for: [contextSaved, expect], timeout: timeout) } @@ -129,7 +128,7 @@ class NotificationSyncMediatorTests: XCTestCase { XCTAssert(manager.mainContext.countObjects(ofType: Notification.self) == 0) // CoreData Expectations - manager.testExpectation = expectation(description: "Context save expectation") + let contextSaved = expectation(forNotification: .NSManagedObjectContextDidSave, object: manager.mainContext) // Mediator Expectations let expect = expectation(description: "Sync") @@ -141,7 +140,7 @@ class NotificationSyncMediatorTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: timeout, handler: nil) + wait(for: [contextSaved, expect], timeout: timeout) } @@ -161,7 +160,7 @@ class NotificationSyncMediatorTests: XCTestCase { XCTAssertFalse(note.read) // CoreData Expectations - manager.testExpectation = expectation(description: "Context save expectation") + let contextSaved = expectation(forNotification: .NSManagedObjectContextDidSave, object: manager.mainContext) // Mediator Expectations let expect = expectation(description: "Mark as Read") @@ -172,7 +171,7 @@ class NotificationSyncMediatorTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: timeout, handler: nil) + wait(for: [contextSaved, expect], timeout: timeout) } /// Verifies that Mark Notifications as Read effectively toggles a Notifications' read flag @@ -197,7 +196,7 @@ class NotificationSyncMediatorTests: XCTestCase { XCTAssertTrue(note2.read) // CoreData Expectations - manager.testExpectation = expectation(description: "Context save expectation") + let contextSaved = expectation(forNotification: .NSManagedObjectContextDidSave, object: manager.mainContext) // Mediator Expectations let expect = expectation(description: "Mark as Read") @@ -210,7 +209,7 @@ class NotificationSyncMediatorTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: timeout, handler: nil) + wait(for: [contextSaved, expect], timeout: timeout) } /// Verifies that Mark Notifications as Read modifies only the specified notifications' read status @@ -235,7 +234,7 @@ class NotificationSyncMediatorTests: XCTestCase { XCTAssertTrue(note2.read) // CoreData Expectations - manager.testExpectation = expectation(description: "Context save expectation") + let contextSaved = expectation(forNotification: .NSManagedObjectContextDidSave, object: manager.mainContext) // Mediator Expectations let expect = expectation(description: "Mark as Read") @@ -247,7 +246,7 @@ class NotificationSyncMediatorTests: XCTestCase { expect.fulfill() } - waitForExpectations(timeout: timeout, handler: nil) + wait(for: [contextSaved, expect], timeout: timeout) } diff --git a/WordPress/WordPressTest/QuickStartFactoryTests.swift b/WordPress/WordPressTest/QuickStartFactoryTests.swift index 00ce0271db0b..69996533c936 100644 --- a/WordPress/WordPressTest/QuickStartFactoryTests.swift +++ b/WordPress/WordPressTest/QuickStartFactoryTests.swift @@ -83,10 +83,11 @@ class QuickStartFactoryTests: XCTestCase { let tours = QuickStartFactory.allTours(for: blog) // Then - XCTAssertEqual(tours.count, 3) + XCTAssertEqual(tours.count, 4) XCTAssertTrue(tours[0] is QuickStartCheckStatsTour) - XCTAssertTrue(tours[1] is QuickStartViewTour) - XCTAssertTrue(tours[2] is QuickStartFollowTour) + XCTAssertTrue(tours[1] is QuickStartNotificationsTour) + XCTAssertTrue(tours[2] is QuickStartViewTour) + XCTAssertTrue(tours[3] is QuickStartFollowTour) } func testToursForNewSite() { @@ -98,17 +99,16 @@ class QuickStartFactoryTests: XCTestCase { let tours = QuickStartFactory.allTours(for: blog) // Then - XCTAssertEqual(tours.count, 10) + XCTAssertEqual(tours.count, 9) XCTAssertTrue(tours[0] is QuickStartCreateTour) XCTAssertTrue(tours[1] is QuickStartSiteTitleTour) XCTAssertTrue(tours[2] is QuickStartSiteIconTour) - XCTAssertTrue(tours[3] is QuickStartEditHomepageTour) - XCTAssertTrue(tours[4] is QuickStartReviewPagesTour) - XCTAssertTrue(tours[5] is QuickStartViewTour) - XCTAssertTrue(tours[6] is QuickStartShareTour) - XCTAssertTrue(tours[7] is QuickStartPublishTour) - XCTAssertTrue(tours[8] is QuickStartFollowTour) - XCTAssertTrue(tours[9] is QuickStartCheckStatsTour) + XCTAssertTrue(tours[3] is QuickStartReviewPagesTour) + XCTAssertTrue(tours[4] is QuickStartViewTour) + XCTAssertTrue(tours[5] is QuickStartShareTour) + XCTAssertTrue(tours[6] is QuickStartPublishTour) + XCTAssertTrue(tours[7] is QuickStartFollowTour) + XCTAssertTrue(tours[8] is QuickStartCheckStatsTour) } private func newTestBlog(id: Int) -> Blog { diff --git a/WordPress/WordPressTest/ReaderSubscribeCommentsActionTests.swift b/WordPress/WordPressTest/ReaderSubscribeCommentsActionTests.swift new file mode 100644 index 000000000000..2c5f623a1129 --- /dev/null +++ b/WordPress/WordPressTest/ReaderSubscribeCommentsActionTests.swift @@ -0,0 +1,128 @@ +import XCTest +@testable import WordPress + +final class ReaderSubscribeCommentsActionTests: XCTestCase { + let sut = ReaderSubscribeCommentsAction() + private var contextManager: TestContextManager! + private var context: NSManagedObjectContext! + + func testExecuteSuccessInvokesCompletion() { + contextManager = TestContextManager() + context = contextManager.mainContext + let readerPost = ReaderPost(context: self.context!) + + guard let service = MockFollowCommentsService(subscribeSuccess: true, notificationSuccess: true, post: readerPost) else { + XCTFail("MockFollowCommentsService instantiation failed.") + return + } + + let testExpectation = expectation(description: "Must be fulfilled on execute.") + + sut.execute( + with: readerPost, + context: context, + followCommentsService: service, sourceViewController: UIViewController()) { + XCTAssertEqual(service.toggleNotificationSettingsCallCount, 1) + XCTAssertEqual(service.toggleSubscribedCallCount, 1) + testExpectation.fulfill() + } + + waitForExpectations(timeout: 1, handler: nil) + } + + func testExecuteSubscribeFailureDoesNotInvokeToggleNotification() { + contextManager = TestContextManager() + context = contextManager.mainContext + let readerPost = ReaderPost(context: self.context!) + + guard let service = MockFollowCommentsService(subscribeSuccess: false, notificationSuccess: true, post: readerPost) else { + XCTFail("MockFollowCommentsService instantiation failed.") + return + } + + let testExpectation = expectation(description: "Must be fulfilled on execute.") + + sut.execute( + with: readerPost, + context: context, + followCommentsService: service, + sourceViewController: UIViewController(), + completion: nil) { error in + XCTAssertEqual(service.toggleSubscribedCallCount, 1) + XCTAssertEqual(service.toggleNotificationSettingsCallCount, 0) + testExpectation.fulfill() + } + + waitForExpectations(timeout: 1, handler: nil) + } + + func testExecuteNotificationFailureInvokesFailureHandler() { + contextManager = TestContextManager() + context = contextManager.mainContext + let readerPost = ReaderPost(context: self.context!) + + guard let service = MockFollowCommentsService(subscribeSuccess: true, notificationSuccess: false, post: readerPost) else { + XCTFail("MockFollowCommentsService instantiation failed.") + return + } + + let testExpectation = expectation(description: "Must be fulfilled on execute.") + + sut.execute( + with: readerPost, + context: context, + followCommentsService: service, + sourceViewController: UIViewController(), + completion: nil) { error in + XCTAssertEqual(service.toggleSubscribedCallCount, 1) + XCTAssertEqual(service.toggleNotificationSettingsCallCount, 1) + testExpectation.fulfill() + } + + waitForExpectations(timeout: 1, handler: nil) + } +} + +private class MockFollowCommentsService: FollowCommentsService { + var toggleNotificationSettingsCallCount = 0 + var toggleSubscribedCallCount = 0 + + private var subscribeSuccess: Bool = true + private var notificationSuccess: Bool = true + + init?(subscribeSuccess: Bool, notificationSuccess: Bool, post: ReaderPost) { + self.subscribeSuccess = subscribeSuccess + self.notificationSuccess = notificationSuccess + super.init(post: post) + } + + @objc required init?(post: ReaderPost, remote: ReaderPostServiceRemote = ReaderPostServiceRemote.withDefaultApi()) { + super.init(post: post, remote: remote) + } + + @objc override func toggleSubscribed( + _ isSubscribed: Bool, + success: @escaping (Bool) -> Void, + failure: @escaping (Error?) -> Void) { + toggleSubscribedCallCount += 1 + + if subscribeSuccess { + success(true) + } else { + failure(nil) + } + } + + @objc override func toggleNotificationSettings( + _ isNotificationsEnabled: Bool, + success: @escaping () -> Void, + failure: @escaping (Error?) -> Void) { + toggleNotificationSettingsCallCount += 1 + + if notificationSuccess { + success() + } else { + failure(nil) + } + } +} diff --git a/WordPress/WordPressTest/TestContextManager.h b/WordPress/WordPressTest/TestContextManager.h index 0dab35a15bab..c338c938d1e3 100644 --- a/WordPress/WordPressTest/TestContextManager.h +++ b/WordPress/WordPressTest/TestContextManager.h @@ -18,9 +18,7 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readwrite, strong) NSManagedObjectModel *managedObjectModel; @property (nonatomic, readwrite, strong) NSPersistentStoreCoordinator *persistentStoreCoordinator; @property (nonatomic, readonly, strong) NSPersistentStoreCoordinator *standardPSC; -@property (nonatomic, readwrite, assign) BOOL requiresTestExpectation; @property (nonatomic, readonly, strong) NSURL *storeURL; -@property (nonatomic, nullable, readwrite, strong) XCTestExpectation *testExpectation; @property (nonatomic, strong, nullable) id stack; diff --git a/WordPress/WordPressTest/TestContextManager.m b/WordPress/WordPressTest/TestContextManager.m index 5e7c2da267ec..39e0971d639a 100644 --- a/WordPress/WordPressTest/TestContextManager.m +++ b/WordPress/WordPressTest/TestContextManager.m @@ -14,7 +14,6 @@ - (instancetype)init if (self) { // Override the shared ContextManager _stack = [[ContextManagerMock alloc] init]; - _requiresTestExpectation = YES; } return self; @@ -55,45 +54,19 @@ - (void)setMainContext:(NSManagedObjectContext *)mainContext [_stack setMainContext:mainContext]; } --(void)setTestExpectation:(XCTestExpectation *)testExpectation -{ - [_stack setTestExpectation:testExpectation]; -} - - (void)saveContext:(NSManagedObjectContext *)context { - [self saveContext:context withCompletionBlock:^{ - if (self.stack.testExpectation) { - [self.stack.testExpectation fulfill]; - self.stack.testExpectation = nil; - } else if (self.stack.requiresTestExpectation) { - NSLog(@"No test expectation present for context save"); - } - }]; + [_stack saveContext:context]; } - (void)saveContextAndWait:(NSManagedObjectContext *)context { [_stack saveContextAndWait:context]; - if (self.stack.testExpectation) { - [self.stack.testExpectation fulfill]; - self.stack.testExpectation = nil; - } else if (self.stack.requiresTestExpectation) { - NSLog(@"No test expectation present for context save"); - } } - (void)saveContext:(NSManagedObjectContext *)context withCompletionBlock:(void (^)(void))completionBlock { - [_stack saveContext:context withCompletionBlock:^{ - if (self.stack.testExpectation) { - [self.stack.testExpectation fulfill]; - self.stack.testExpectation = nil; - } else if (self.stack.requiresTestExpectation) { - NSLog(@"No test expectation present for context save"); - } - completionBlock(); - }]; + [_stack saveContext:context withCompletionBlock:completionBlock]; } - (nonnull NSManagedObjectContext *const)newDerivedContext { diff --git a/config/Version.internal.xcconfig b/config/Version.internal.xcconfig index f0ac7b096971..60fdcdbd9666 100644 --- a/config/Version.internal.xcconfig +++ b/config/Version.internal.xcconfig @@ -1,4 +1,4 @@ -VERSION_SHORT=19.7 +VERSION_SHORT=19.8 // Internal long version example: VERSION_LONG=9.9.0.20180423 -VERSION_LONG=19.7.0.20220421 +VERSION_LONG=19.8.0.20220502 diff --git a/config/Version.public.xcconfig b/config/Version.public.xcconfig index 9346cbb59175..969cf1527888 100644 --- a/config/Version.public.xcconfig +++ b/config/Version.public.xcconfig @@ -1,4 +1,4 @@ -VERSION_SHORT=19.7 +VERSION_SHORT=19.8 // Public long version example: VERSION_LONG=9.9.0.0 -VERSION_LONG=19.7.0.1 +VERSION_LONG=19.8.0.0 diff --git a/fastlane/Fastfile b/fastlane/Fastfile index dd0a12570879..b94b42746a5e 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -49,7 +49,6 @@ GHHELPER_REPO = 'wordpress-mobile/wordpress-iOS' ENV['PROJECT_NAME'] = 'WordPress' ENV['PUBLIC_CONFIG_FILE'] = File.join(PROJECT_ROOT_FOLDER, 'config', 'Version.Public.xcconfig') ENV['INTERNAL_CONFIG_FILE'] = File.join(PROJECT_ROOT_FOLDER, 'config', 'Version.internal.xcconfig') -ENV['DOWNLOAD_METADATA'] = './fastlane/download_metadata.swift' ENV['PROJECT_ROOT_FOLDER'] = "#{PROJECT_ROOT_FOLDER}/" ENV['APP_STORE_STRINGS_FILE_NAME'] = 'AppStoreStrings.po' diff --git a/fastlane/appstoreres/metadata/source/description.txt b/fastlane/appstoreres/metadata/source/description.txt deleted file mode 100644 index 39bf1bae8901..000000000000 --- a/fastlane/appstoreres/metadata/source/description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Manage or create your WordPress blog or website right from your iOS device: create and edit posts and pages, upload your favorite photos and videos, view stats and reply to comments. - -With WordPress for iOS, you have the power to publish in the palm of your hand. Draft a spontaneous haiku from the couch. Snap and post a photo on your lunch break. Respond to your latest comments, or check your stats to see what new countries today’s visitors are coming from. - -WordPress for iOS is an Open Source project, which means you too can contribute to its development. Learn more at https://apps.wordpress.com/contribute/. - -WordPress for iOS supports WordPress.com and self-hosted WordPress.org sites running WordPress 4.0 or higher. - -Need help with the app? Visit the forums at https://ios.forums.wordpress.org/ or tweet us @WordPressiOS. - -View the Privacy Notice for California Users at https://automattic.com/privacy/#california-consumer-privacy-act-ccpa. \ No newline at end of file diff --git a/fastlane/appstoreres/metadata/source/keywords.txt b/fastlane/appstoreres/metadata/source/keywords.txt deleted file mode 100644 index 7ab147e34e06..000000000000 --- a/fastlane/appstoreres/metadata/source/keywords.txt +++ /dev/null @@ -1 +0,0 @@ -blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs diff --git a/fastlane/appstoreres/metadata/source/name.txt b/fastlane/appstoreres/metadata/source/name.txt deleted file mode 100644 index f1c6744c4874..000000000000 --- a/fastlane/appstoreres/metadata/source/name.txt +++ /dev/null @@ -1 +0,0 @@ -WordPress – Website Builder diff --git a/fastlane/appstoreres/metadata/source/subtitle.txt b/fastlane/appstoreres/metadata/source/subtitle.txt deleted file mode 100644 index 08d11992ce2f..000000000000 --- a/fastlane/appstoreres/metadata/source/subtitle.txt +++ /dev/null @@ -1 +0,0 @@ -Design a site, build a blog diff --git a/fastlane/download_metadata.swift b/fastlane/download_metadata.swift deleted file mode 100755 index 87976d438027..000000000000 --- a/fastlane/download_metadata.swift +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env swift - -import Foundation - -let glotPressNameKey = "app_store_name" -let glotPressSubtitleKey = "app_store_subtitle" -let glotPressWhatsNewKey = "v19.7-whats-new" -let glotPressDescriptionKey = "app_store_desc" -let glotPressKeywordsKey = "app_store_keywords" - -struct Config { - let baseFolder: String - let baseURLString: String - - static let wordPress = Config( - baseFolder: "./metadata", - baseURLString: "https://translate.wordpress.org/projects/apps/ios/release-notes/" - ) - - static let jetpack = Config( - baseFolder: "./jetpack_metadata", - baseURLString: "https://translate.wordpress.com/projects/jetpack/apps/ios/release-notes/" - ) - - static func config(for argument: String?) -> Config { - guard let argument = argument else { return .wordPress } - return argument == "jetpack" ? .jetpack : .wordPress - } -} - -// iTunes Connect language code: GlotPress code -let languages = [ - "ar-SA": "ar", - "da": "da", - "de-DE": "de", - "en-AU": "en-au", - "en-CA": "en-ca", - "en-GB": "en-gb", - "default": "en-us", // Technically not a real GlotPress language - "en-US": "en-us", // Technically not a real GlotPress language - "es-ES": "es", - "es-MX": "es-mx", - "fr-FR": "fr", - "he": "he", - "id": "id", - "it": "it", - "ja": "ja", - "ko": "ko", - "nl-NL": "nl", - "no": "nb", - "pt-BR": "pt-br", - "pt-PT": "pt", - "ru": "ru", - "sv": "sv", - "th": "th", - "tr": "tr", - "zh-Hans": "zh-cn", - "zh-Hant": "zh-tw", -] - -func downloadTranslation( - config: Config = .config(for: CommandLine.arguments.second), - languageCode: String, - folderName: String -) { - let languageCodeOverride = languageCode == "en-us" ? "en-gb" : languageCode - let glotPressURL = "\(config.baseURLString)\(languageCodeOverride)/default/export-translations?format=json" - let requestURL: URL = URL(string: glotPressURL)! - let urlRequest: URLRequest = URLRequest(url: requestURL) - let session = URLSession.shared - - let sema = DispatchSemaphore( value: 0) - - print("Downloading Language: \(languageCode)") - - let task = session.dataTask(with: urlRequest) { - (data, response, error) -> Void in - - defer { - sema.signal() - } - - guard let data = data else { - print(" Invalid data downloaded.") - return - } - - guard let json = try? JSONSerialization.jsonObject(with: data, options: []), - let jsonDict = json as? [String: Any] else { - print(" JSON was not returned") - return - } - - var name: String? - var subtitle: String? - var whatsNew: String? - var keywords: String? - var storeDescription: String? - - jsonDict.forEach({ (key: String, value: Any) in - - guard let index = key.firstIndex(of: Character(UnicodeScalar(0004))) else { - return - } - - let keyFirstPart = String(key[.. `*.lproj` folder name`) # +# TODO: Replace with `LocaleHelper` once provided by release toolkit (https://github.com/wordpress-mobile/release-toolkit/pull/296) GLOTPRESS_TO_LPROJ_APP_LOCALE_CODES = { 'ar' => 'ar', # Arabic 'bg' => 'bg', # Bulgarian @@ -50,6 +50,41 @@ 'zh-tw' => 'zh-Hant' # Chinese (Taiwan) }.freeze +# Mapping of all locales which can be used for AppStore metadata (Glotpress code => AppStore Connect code) +# +# TODO: Replace with `LocaleHelper` once provided by release toolkit (https://github.com/wordpress-mobile/release-toolkit/pull/296) +GLOTPRESS_TO_ASC_METADATA_LOCALE_CODES = { + 'ar' => 'ar-SA', + 'da' => 'da', + 'de' => 'de-DE', + 'en-au' => 'en-AU', + 'en-ca' => 'en-CA', + 'en-gb' => 'en-GB', + 'es' => 'es-ES', + 'es-mx' => 'es-MX', + 'fr' => 'fr-FR', + 'he' => 'he', + 'id' => 'id', + 'it' => 'it', + 'ja' => 'ja', + 'ko' => 'ko', + 'nl' => 'nl-NL', + 'nb' => 'no', + 'pt-br' => 'pt-BR', + 'pt' => 'pt-PT', + 'ru' => 'ru', + 'sv' => 'sv', + 'th' => 'th', + 'tr' => 'tr', + 'zh-cn' => 'zh-Hans', + 'zh-tw' => 'zh-Hant', +}.freeze + +# Locales used in AppStore for WordPress metadata +WORDPRESS_METADATA_GLOTPRESS_LOCALE_CODES = GLOTPRESS_TO_ASC_METADATA_LOCALE_CODES.keys.freeze # all of them +# Locales used in AppStore for Jetpack metadata +JETPACK_METADATA_GLOTPRESS_LOCALE_CODES = %w[ar de es fr he id it ja ko nl pt-br ru sv tr zh-cn zh-tw].freeze + # List of `.strings` files manually maintained by developers (as opposed to being automatically extracted from code and generated) # which we will merge into the main `Localizable.strings` file imported by GlotPress, then extract back once we download the translations. # Each `.strings` file to be merged/extracted is associated with a prefix to add the the keys being used to avoid conflicts and differentiate. @@ -126,7 +161,7 @@ # desc 'Updates the AppStoreStrings.po file for the WordPress app with the latest data' lane :update_wordpress_appstore_strings do |options| - source_metadata_folder = File.join(PROJECT_ROOT_FOLDER, 'fastlane', 'appstoreres', 'metadata', 'source') + source_metadata_folder = File.join(PROJECT_ROOT_FOLDER, 'fastlane', 'metadata', 'default') files = { whats_new: File.join(PROJECT_ROOT_FOLDER, 'WordPress', 'Resources', 'release_notes.txt'), @@ -160,10 +195,11 @@ # desc 'Updates the AppStoreStrings.po file for the Jetpack app with the latest data' lane :update_jetpack_appstore_strings do |options| - source_metadata_folder = File.join(PROJECT_ROOT_FOLDER, 'fastlane', 'appstoreres', 'jetpack_metadata', 'source') + source_metadata_folder = File.join(PROJECT_ROOT_FOLDER, 'fastlane', 'jetpack_metadata', 'default') files = { whats_new: File.join(PROJECT_ROOT_FOLDER, 'WordPress', 'Jetpack', 'Resources', 'release_notes.txt'), + app_store_name: File.join(source_metadata_folder, 'name.txt'), app_store_subtitle: File.join(source_metadata_folder, 'subtitle.txt'), app_store_desc: File.join(source_metadata_folder, 'description.txt'), app_store_keywords: File.join(source_metadata_folder, 'keywords.txt'), @@ -172,8 +208,7 @@ 'screenshot-text-3' => File.join(source_metadata_folder, 'promo_screenshot_3.txt'), 'screenshot-text-4' => File.join(source_metadata_folder, 'promo_screenshot_4.txt'), 'screenshot-text-5' => File.join(source_metadata_folder, 'promo_screenshot_5.txt'), - 'screenshot-text-6' => File.join(source_metadata_folder, 'promo_screenshot_6.txt'), - app_store_name: File.join(source_metadata_folder, 'name.txt') + 'screenshot-text-6' => File.join(source_metadata_folder, 'promo_screenshot_6.txt') } ios_update_metadata_source( @@ -214,7 +249,6 @@ ) # Finally, also download the AppStore metadata (app title, keywords, etc.) - # @FIXME: Replace this whole lane with a call to the future replacement of `gp_downloadmetadata` once it's implemented in the release-toolkit (see paaHJt-31O-p2). download_wordpress_localized_app_store_metadata download_jetpack_localized_app_store_metadata end @@ -223,25 +257,21 @@ # desc 'Downloads the localized metadata (for App Store Connect) from GlotPress for the WordPress app' lane :download_wordpress_localized_app_store_metadata do - # @FIXME: Replace this whole lane with a call to the future replacement of `gp_downloadmetadata` once it's implemented in the release-toolkit (see paaHJt-31O-p2). - - # No need to `cd` into `fastlane` because of how Fastlane manages its paths internally. - sh './download_metadata.swift wordpress' + metadata_directory = File.join(PROJECT_ROOT_FOLDER, 'fastlane', 'metadata') - # @TODO: Make the `fastlane/metadata/en-US/release_notes.txt` path be the source of truth for the original copies in the future. + # FIXME: We should make the `fastlane/metadata/default/release_notes.txt` path be the source of truth for the original copies in the future. # (will require changes in the `update_appstore_strings` lane, the Release Scenario, the MC tool to generate the announcement post…) # - # In the meantime, since GlotPress doesn't have the `en-US` notes because those are the ones used as originals, just copy the file to the right place for `deliver` to find - metadata_directory = File.join(PROJECT_ROOT_FOLDER, 'fastlane', 'metadata') + # In the meantime, just copy the file to the right place for `deliver` to find, for the `default` pseudo-locale which is used as fallback release_notes_source = File.join(PROJECT_ROOT_FOLDER, 'WordPress', 'Resources', 'release_notes.txt') - FileUtils.cp(release_notes_source, File.join(metadata_directory, 'en-US', 'release_notes.txt')) - - metadata_path = File.join(metadata_directory, '**', '*.txt') - git_add(path: metadata_path, shell_escape: true) - git_commit( - path: metadata_path, - message: 'Update WordPress metadata translations', - allow_nothing_to_commit: true + FileUtils.cp(release_notes_source, File.join(metadata_directory, 'default', 'release_notes.txt')) + + # Download metadata translations from GlotPress + download_localized_app_store_metadata( + glotpress_project_url: GLOTPRESS_WORDPRESS_METADATA_PROJECT_URL, + metadata_directory: metadata_directory, + locales: WORDPRESS_METADATA_GLOTPRESS_LOCALE_CODES, + commit_message: 'Update WordPress metadata translations' ) end @@ -249,24 +279,65 @@ # desc 'Downloads the localized metadata (for App Store Connect) from GlotPress for the Jetpack app' lane :download_jetpack_localized_app_store_metadata do - # @FIXME: Replace this whole lane with a call to the future replacement of `gp_downloadmetadata` once it's implemented in the release-toolkit (see paaHJt-31O-p2). - - # No need to `cd` into `fastlane` because of how Fastlane manages its paths internally. - sh './download_metadata.swift jetpack' + metadata_directory = File.join(PROJECT_ROOT_FOLDER, 'fastlane', 'jetpack_metadata') - # @TODO: Make the `fastlane/jetpack_metadata/en-US/release_notes.txt` path be the source of truth for the original copies in the future. + # FIXME: We should make the `fastlane/jetpack_metadata/default/release_notes.txt` path be the source of truth for the original copies in the future. # (will require changes in the `update_appstore_strings` lane, the Release Scenario, the MC tool to generate the announcement post…) # - # In the meantime, since GlotPress doesn't have the `en-US` notes because those are the ones used as originals, just copy the file to the right place for `deliver` to find - metadata_directory = File.join(PROJECT_ROOT_FOLDER, 'fastlane', 'jetpack_metadata') + # In the meantime, just copy the file to the right place for `deliver` to find, for the `default` pseudo-locale which is used as fallback release_notes_source = File.join(PROJECT_ROOT_FOLDER, 'WordPress', 'Jetpack', 'Resources', 'release_notes.txt') - FileUtils.cp(release_notes_source, File.join(metadata_directory, 'en-US', 'release_notes.txt')) + FileUtils.cp(release_notes_source, File.join(metadata_directory, 'default', 'release_notes.txt')) + + # Download metadata translations from GlotPress + download_localized_app_store_metadata( + glotpress_project_url: GLOTPRESS_JETPACK_METADATA_PROJECT_URL, + locales: JETPACK_METADATA_GLOTPRESS_LOCALE_CODES, + metadata_directory: metadata_directory, + commit_message: 'Update Jetpack metadata translations' + ) + end + + def download_localized_app_store_metadata(glotpress_project_url:, locales:, metadata_directory:, commit_message:) + # FIXME: Replace this with a call to the future replacement of `gp_downloadmetadata` once it's implemented in the release-toolkit (see paaHJt-31O-p2). - metadata_path = File.join(metadata_directory, '**', '*.txt') - git_add(path: metadata_path, shell_escape: true) + locales_map = GLOTPRESS_TO_ASC_METADATA_LOCALE_CODES.slice(*locales) + target_files = { + "v#{ios_get_app_version}-whats-new": { desc: "release_notes.txt", max_size: 4000 }, + app_store_name: { desc: "name.txt", max_size: 30 }, + app_store_subtitle: { desc: "subtitle.txt", max_size: 30 }, + app_store_desc: { desc: "description.txt", max_size: 4000 }, + app_store_keywords: { desc: "keywords.txt", max_size: 100 }, + } + + gp_downloadmetadata( + project_url: glotpress_project_url, + target_files: target_files, + locales: locales_map, + download_path: metadata_directory + ) + files_to_commit = [File.join(metadata_directory, '**', '*.txt')] + + # Ensure that none of the `.txt` files in `en-US` would accidentally override our originals in `default` + target_files.values.map { |h| h[:desc] }.each do |file| + en_file_path = File.join(metadata_directory, 'en-US', file) + UI.user_error!("File `#{en_file_path}` would override the same one in `#{metadata_directory}/default`, but `default/` is the source of truth. " \ + + "Delete the `#{en_file_path}` file, ensure the `default/` one has the expected original copy, and try again.") if File.exist?(en_file_path) + end + + # Ensure even empty locale folders have an empty `.gitkeep` file (in case we don't have any translation at all ready for some locales) + locales_map.values.each do |locale| + gitkeep = File.join(metadata_directory, locale, '.gitkeep') + next if File.exist?(gitkeep) + FileUtils.mkdir_p(File.dirname(gitkeep)) + FileUtils.touch(gitkeep) + files_to_commit.append(gitkeep) + end + + # Commit + git_add(path: files_to_commit, shell_escape: false) git_commit( - path: metadata_path, - message: 'Update Jetpack metadata translations', + path: files_to_commit, + message: commit_message, allow_nothing_to_commit: true ) end diff --git a/fastlane/lanes/release.rb b/fastlane/lanes/release.rb index 95261672e94c..a516ea6255d9 100644 --- a/fastlane/lanes/release.rb +++ b/fastlane/lanes/release.rb @@ -16,7 +16,7 @@ gutenberg_dep_check ios_codefreeze_prechecks(options) - ios_bump_version_release(skip_deliver: true) + ios_bump_version_release(skip_deliver: true, skip_glotpress: true) new_version = ios_get_app_version release_notes_source_path = File.join(PROJECT_ROOT_FOLDER, 'RELEASE-NOTES.txt') diff --git a/fastlane/lanes/screenshots.rb b/fastlane/lanes/screenshots.rb index fb92a49cfdc8..777638db8e64 100644 --- a/fastlane/lanes/screenshots.rb +++ b/fastlane/lanes/screenshots.rb @@ -2,39 +2,6 @@ require 'fileutils' -################################################# -# Constants -################################################# - -# rubocop:disable Style/WordArray -GLOTPRESS_TO_ASC_METADATA_LOCALE_CODES = [ - ['ar', 'ar-SA'], - ['en-gb', 'en-US'], - ['en-gb', 'en-GB'], - ['en-ca', 'en-CA'], - ['en-au', 'en-AU'], - ['da', 'da'], - ['de', 'de-DE'], - ['es', 'es-ES'], - ['fr', 'fr-FR'], - ['he', 'he'], - ['id', 'id'], - ['it', 'it'], - ['ja', 'ja'], - ['ko', 'ko'], - ['nl', 'nl-NL'], - ['nb', 'no'], - ['pt-br', 'pt-BR'], - ['pt', 'pt-PT'], - ['ru', 'ru'], - ['sv', 'sv'], - ['th', 'th'], - ['tr', 'tr'], - ['zh-cn', 'zh-Hans'], - ['zh-tw', 'zh-Hant'] -].freeze -# rubocop:enable Style/WordArray - ################################################# # Lanes ################################################# diff --git a/fastlane/metadata/ar-SA/.gitkeep b/fastlane/metadata/ar-SA/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/ar-SA/keywords.txt b/fastlane/metadata/ar-SA/keywords.txt index ac9503d564b9..8cdb610d6e1b 100644 --- a/fastlane/metadata/ar-SA/keywords.txt +++ b/fastlane/metadata/ar-SA/keywords.txt @@ -1 +1 @@ -مدون, كتابة, تدوين, ويب, صانع, عبر الإنترنت, متجر, أعمال, إعداد, إنشاء, كتابة, مدونات \ No newline at end of file +مدون, كتابة, تدوين, ويب, صانع, عبر الإنترنت, متجر, أعمال, إعداد, إنشاء, كتابة, مدونات diff --git a/fastlane/metadata/ar-SA/name.txt b/fastlane/metadata/ar-SA/name.txt index 591d95996f72..9e24718c05fe 100644 --- a/fastlane/metadata/ar-SA/name.txt +++ b/fastlane/metadata/ar-SA/name.txt @@ -1 +1 @@ -ووردبريس – مُنشئ مواقع الويب \ No newline at end of file +ووردبريس – مُنشئ مواقع الويب diff --git a/fastlane/metadata/ar-SA/release_notes.txt b/fastlane/metadata/ar-SA/release_notes.txt new file mode 100644 index 000000000000..8a0b0cdcbfed --- /dev/null +++ b/fastlane/metadata/ar-SA/release_notes.txt @@ -0,0 +1,11 @@ +لقد أجرينا تغييرًا صغيرًا لكنه رائع على محرِّر المكوِّن: أصبح زر "إضافة مكوِّن" أكثر وضوحًا عندما تفتح المحرِّر للمرة الأولى من دون تحديد أي مكوِّنات. قمنا كذلك بإزالة واحد من ثلاثة تنبيهات خطأ عندما يفشل رفع مكوِّن الوسائط أو الصوت—بدا الأمر مبالغًا فيه. + +ستسمع بعض تعديلات إمكانية الوصول في تجربة VoiceOver عندما تقوم بإعادة ترتيب عناصر القائمة. الإرشادات والإشعارات أكثر وضوحًا، ويبدو تسلسل القالب أكثر منطقية بشكل واضح. + +أضفنا شاشة جديدة إلى عملية إنشاء الموقع حيث يمكنك إدخال هدف موقعك. قمنا بتجربة هذه الشاشة باستخدام مجموعة صغيرة من المستخدمين، ونعتقد أنها ستنال إعجابك كذلك. + +لن تحذف معاينات الويب تنبيهات الجزء السفلي من الشاشة عندما يكون شريط أدوات المتصفح الخاص بك مرئيًا. + +ماذا يوجد في الاسم؟ حسنًا، إذا كان موقعك يحتوي على واحد، فستراه في عنوان تنقل موقعي. + +عندما تسحب تعليقًا في تنبيهاتك إلى اليسار، لن ترى خيار "سلة المهملات" بعد الآن. بدلاً من ذلك، سترى خيارات "عدم الموافقة على التعليق" و"الموافقة على التعليق". نحن من نتولى الموافقة. diff --git a/fastlane/metadata/ar-SA/subtitle.txt b/fastlane/metadata/ar-SA/subtitle.txt index 51f5b9ed5182..f59d6fe3500b 100644 --- a/fastlane/metadata/ar-SA/subtitle.txt +++ b/fastlane/metadata/ar-SA/subtitle.txt @@ -1 +1 @@ -تصميم موقع، إنشاء مدونة \ No newline at end of file +تصميم موقع، إنشاء مدونة diff --git a/fastlane/metadata/da/.gitkeep b/fastlane/metadata/da/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/da/description.txt b/fastlane/metadata/da/description.txt deleted file mode 100644 index 04a5230800f7..000000000000 --- a/fastlane/metadata/da/description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Manage or create your WordPress blog or website right from your iOS device: create and edit posts and pages, upload your favorite photos and videos, view stats and reply to comments. - -With WordPress for iOS, you have the power to publish in the palm of your hand. Draft a spontaneous haiku from the couch. Snap and post a photo on your lunch break. Respond to your latest comments, or check your stats to see what new countries today’s visitors are coming from. - -WordPress for iOS is an Open Source project, which means you too can contribute to its development. Learn more at https://apps.wordpress.com/contribute/. - -WordPress for iOS supports WordPress.com and self-hosted WordPress.org sites running WordPress 4.0 or higher. - -Need help with the app? Visit the forums at https://ios.forums.wordpress.org/ or tweet us @WordPressiOS. - -View the Privacy Notice for California Users at https://automattic.com/privacy/#california-consumer-privacy-act-ccpa. diff --git a/fastlane/metadata/da/keywords.txt b/fastlane/metadata/da/keywords.txt deleted file mode 100644 index ab6cbfc0f9a1..000000000000 --- a/fastlane/metadata/da/keywords.txt +++ /dev/null @@ -1 +0,0 @@ -social,network,notes,jetpack,photos,writing,geotagging,media,blog,wordpress,website,blogging,design diff --git a/fastlane/metadata/da/name.txt b/fastlane/metadata/da/name.txt deleted file mode 100644 index bacf8ed91ea2..000000000000 --- a/fastlane/metadata/da/name.txt +++ /dev/null @@ -1 +0,0 @@ -WordPress diff --git a/fastlane/metadata/da/subtitle.txt b/fastlane/metadata/da/subtitle.txt deleted file mode 100644 index 4181b65c7d44..000000000000 --- a/fastlane/metadata/da/subtitle.txt +++ /dev/null @@ -1 +0,0 @@ -Manage your website anywhere diff --git a/fastlane/metadata/de-DE/.gitkeep b/fastlane/metadata/de-DE/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/de-DE/keywords.txt b/fastlane/metadata/de-DE/keywords.txt index ef03c7827fa2..8762b2c9a1dd 100644 --- a/fastlane/metadata/de-DE/keywords.txt +++ b/fastlane/metadata/de-DE/keywords.txt @@ -1 +1 @@ -blogger,schreiben,bloggen,web,maker,online,store,business,entwerfen,erstellen,schreiben,blogs \ No newline at end of file +blogger,schreiben,bloggen,web,maker,online,store,business,entwerfen,erstellen,schreiben,blogs diff --git a/fastlane/metadata/de-DE/name.txt b/fastlane/metadata/de-DE/name.txt index 7019b1be1ac6..7289f714054d 100644 --- a/fastlane/metadata/de-DE/name.txt +++ b/fastlane/metadata/de-DE/name.txt @@ -1 +1 @@ -WordPress – Website-Baukasten \ No newline at end of file +WordPress – Website-Baukasten diff --git a/fastlane/metadata/de-DE/release_notes.txt b/fastlane/metadata/de-DE/release_notes.txt new file mode 100644 index 000000000000..63e33bfa9d0f --- /dev/null +++ b/fastlane/metadata/de-DE/release_notes.txt @@ -0,0 +1,11 @@ +Wir haben eine kleine, aber sehr nützliche Änderung am Block-Editor vorgenommen: Der Button „Block hinzufügen“ ist besser zu erkennen, wenn du den Editor zuerst ohne ausgewählte Blöcke öffnest. Zudem haben wir eine von drei Fehlerbenachrichtigungen entfernt, die angezeigt wurden, wenn ein Medien- oder Audioblock nicht hochgeladen werden konnte – das war zu viel des Guten. + +Wenn du Menüeinträge neu anordnest, wirst du bemerken, dass wir einige Funktionen zur Barrierefreiheit beim VoiceOver-Erlebnis optimiert haben. Die Anweisungen und Hinweise sind klarer und die Menühierarchie klingt logischer. + +Wir haben bei der Website-Erstellung eine neue Ansicht hinzugefügt, auf der du den Intent für deine Website eingeben kannst. Diese Ansicht haben wir mit einer kleinen Benutzergruppe getestet. Daher glauben wir, dass sie dir auch gefallen wird. + +Bei der Web-Vorschau werden Benachrichtigungen am Ende des Bildschirms nicht mehr abgeschnitten, wenn deine Browser-Werkzeugleiste angezeigt wird. + +Ist ein Name wichtig? Nun, falls deine Website einen hat, wird er dir im Navigationstitel unter „Meine Website“ angezeigt. + +Wenn du bei einem Kommentar in deinen Benachrichtigungen nach links wischst, wird dir nicht mehr die Option „Papierkorb“ angezeigt. Stattdessen siehst du die Optionen „Kommentar zurückweisen“ und „Kommentar genehmigen“. Genehmigt. diff --git a/fastlane/metadata/de-DE/subtitle.txt b/fastlane/metadata/de-DE/subtitle.txt index 17da612d1d1f..d2fd51a1ada2 100644 --- a/fastlane/metadata/de-DE/subtitle.txt +++ b/fastlane/metadata/de-DE/subtitle.txt @@ -1 +1 @@ -Website und Blog erstellen \ No newline at end of file +Website und Blog erstellen diff --git a/fastlane/metadata/default/description.txt b/fastlane/metadata/default/description.txt index 04a5230800f7..39bf1bae8901 100644 --- a/fastlane/metadata/default/description.txt +++ b/fastlane/metadata/default/description.txt @@ -8,4 +8,4 @@ WordPress for iOS supports WordPress.com and self-hosted WordPress.org sites run Need help with the app? Visit the forums at https://ios.forums.wordpress.org/ or tweet us @WordPressiOS. -View the Privacy Notice for California Users at https://automattic.com/privacy/#california-consumer-privacy-act-ccpa. +View the Privacy Notice for California Users at https://automattic.com/privacy/#california-consumer-privacy-act-ccpa. \ No newline at end of file diff --git a/fastlane/metadata/default/keywords.txt b/fastlane/metadata/default/keywords.txt index 46d9ead15c94..7ab147e34e06 100644 --- a/fastlane/metadata/default/keywords.txt +++ b/fastlane/metadata/default/keywords.txt @@ -1 +1 @@ -blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs \ No newline at end of file +blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs diff --git a/fastlane/metadata/default/marketing_url.txt b/fastlane/metadata/default/marketing_url.txt deleted file mode 100644 index 0ad53b917f84..000000000000 --- a/fastlane/metadata/default/marketing_url.txt +++ /dev/null @@ -1 +0,0 @@ -https://apps.wordpress.com/mobile/ \ No newline at end of file diff --git a/fastlane/metadata/default/name.txt b/fastlane/metadata/default/name.txt index 028d836eea1f..f1c6744c4874 100644 --- a/fastlane/metadata/default/name.txt +++ b/fastlane/metadata/default/name.txt @@ -1 +1 @@ -WordPress – Website Builder \ No newline at end of file +WordPress – Website Builder diff --git a/fastlane/metadata/default/release_notes.txt b/fastlane/metadata/default/release_notes.txt new file mode 100644 index 000000000000..16fdae8901ab --- /dev/null +++ b/fastlane/metadata/default/release_notes.txt @@ -0,0 +1,11 @@ +We made a small but mighty change to the block editor: the “Add Block” button is more visible when you first open the editor with no blocks selected. We also removed one of three error notifications when a media or audio block fails to upload—it felt like overkill. + +You’ll hear some accessibility tweaks in the VoiceOver experience when you’re rearranging menu items. Instructions and notices are clearer, and the menu hierarchy makes more sense out loud. + +We added a new screen to the site creation process where you can enter your site’s intent. We tested this screen with a small group of users, and we think you’ll like it, too. + +Web previews won’t cut off bottom-of-the-screen notifications when your browser toolbar is visible. + +What’s in a name? Well, if your site has one, you’ll see it in the My Site navigation title. + +When you swipe left on a comment in your Notifications, you won’t see the “Trash” option anymore. Instead you’ll see “Unapprove Comment” and “Approve Comment.” We approve. diff --git a/fastlane/metadata/default/subtitle.txt b/fastlane/metadata/default/subtitle.txt index b082dcb78bf7..08d11992ce2f 100644 --- a/fastlane/metadata/default/subtitle.txt +++ b/fastlane/metadata/default/subtitle.txt @@ -1 +1 @@ -Design a site, build a blog \ No newline at end of file +Design a site, build a blog diff --git a/fastlane/metadata/en-AU/.gitkeep b/fastlane/metadata/en-AU/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/en-AU/description.txt b/fastlane/metadata/en-AU/description.txt deleted file mode 100644 index 04a5230800f7..000000000000 --- a/fastlane/metadata/en-AU/description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Manage or create your WordPress blog or website right from your iOS device: create and edit posts and pages, upload your favorite photos and videos, view stats and reply to comments. - -With WordPress for iOS, you have the power to publish in the palm of your hand. Draft a spontaneous haiku from the couch. Snap and post a photo on your lunch break. Respond to your latest comments, or check your stats to see what new countries today’s visitors are coming from. - -WordPress for iOS is an Open Source project, which means you too can contribute to its development. Learn more at https://apps.wordpress.com/contribute/. - -WordPress for iOS supports WordPress.com and self-hosted WordPress.org sites running WordPress 4.0 or higher. - -Need help with the app? Visit the forums at https://ios.forums.wordpress.org/ or tweet us @WordPressiOS. - -View the Privacy Notice for California Users at https://automattic.com/privacy/#california-consumer-privacy-act-ccpa. diff --git a/fastlane/metadata/en-AU/keywords.txt b/fastlane/metadata/en-AU/keywords.txt deleted file mode 100644 index 7ab147e34e06..000000000000 --- a/fastlane/metadata/en-AU/keywords.txt +++ /dev/null @@ -1 +0,0 @@ -blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs diff --git a/fastlane/metadata/en-AU/name.txt b/fastlane/metadata/en-AU/name.txt deleted file mode 100644 index f1c6744c4874..000000000000 --- a/fastlane/metadata/en-AU/name.txt +++ /dev/null @@ -1 +0,0 @@ -WordPress – Website Builder diff --git a/fastlane/metadata/en-AU/subtitle.txt b/fastlane/metadata/en-AU/subtitle.txt deleted file mode 100644 index 08d11992ce2f..000000000000 --- a/fastlane/metadata/en-AU/subtitle.txt +++ /dev/null @@ -1 +0,0 @@ -Design a site, build a blog diff --git a/fastlane/metadata/en-CA/.gitkeep b/fastlane/metadata/en-CA/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/en-CA/keywords.txt b/fastlane/metadata/en-CA/keywords.txt index 46d9ead15c94..7ab147e34e06 100644 --- a/fastlane/metadata/en-CA/keywords.txt +++ b/fastlane/metadata/en-CA/keywords.txt @@ -1 +1 @@ -blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs \ No newline at end of file +blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs diff --git a/fastlane/metadata/en-CA/name.txt b/fastlane/metadata/en-CA/name.txt index 028d836eea1f..f1c6744c4874 100644 --- a/fastlane/metadata/en-CA/name.txt +++ b/fastlane/metadata/en-CA/name.txt @@ -1 +1 @@ -WordPress – Website Builder \ No newline at end of file +WordPress – Website Builder diff --git a/fastlane/metadata/en-CA/subtitle.txt b/fastlane/metadata/en-CA/subtitle.txt index b082dcb78bf7..08d11992ce2f 100644 --- a/fastlane/metadata/en-CA/subtitle.txt +++ b/fastlane/metadata/en-CA/subtitle.txt @@ -1 +1 @@ -Design a site, build a blog \ No newline at end of file +Design a site, build a blog diff --git a/fastlane/metadata/en-GB/.gitkeep b/fastlane/metadata/en-GB/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/en-GB/keywords.txt b/fastlane/metadata/en-GB/keywords.txt index 46d9ead15c94..7ab147e34e06 100644 --- a/fastlane/metadata/en-GB/keywords.txt +++ b/fastlane/metadata/en-GB/keywords.txt @@ -1 +1 @@ -blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs \ No newline at end of file +blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs diff --git a/fastlane/metadata/en-GB/name.txt b/fastlane/metadata/en-GB/name.txt index 028d836eea1f..f1c6744c4874 100644 --- a/fastlane/metadata/en-GB/name.txt +++ b/fastlane/metadata/en-GB/name.txt @@ -1 +1 @@ -WordPress – Website Builder \ No newline at end of file +WordPress – Website Builder diff --git a/fastlane/metadata/en-GB/release_notes.txt b/fastlane/metadata/en-GB/release_notes.txt new file mode 100644 index 000000000000..d60e8d1febe9 --- /dev/null +++ b/fastlane/metadata/en-GB/release_notes.txt @@ -0,0 +1,11 @@ +We made a small but mighty change to the block editor: the “Add Block” button is more visible when you first open the editor with no blocks selected. We also removed one of three error notifications when a media or audio block fails to upload—it felt like overkill. + +You’ll hear some accessibility tweaks in the VoiceOver experience when you’re rearranging menu items. Instructions and notices are clearer, and the menu hierarchy makes more sense out loud. + +We added a new screen to the site creation process where you can enter your site's intent. We tested this screen with a small group of users, and we think you’ll like it, too. + +Web previews won’t cut off bottom-of-the-screen notifications when your browser toolbar is visible. + +What’s in a name? Well, if your site has one, you’ll see it in the My Site navigation title. + +When you swipe left on a comment in your Notifications, you won’t see the “Bin” option anymore. Instead you’ll see “Unapprove Comment” and “Approve Comment.” We approve. diff --git a/fastlane/metadata/en-GB/subtitle.txt b/fastlane/metadata/en-GB/subtitle.txt index b082dcb78bf7..08d11992ce2f 100644 --- a/fastlane/metadata/en-GB/subtitle.txt +++ b/fastlane/metadata/en-GB/subtitle.txt @@ -1 +1 @@ -Design a site, build a blog \ No newline at end of file +Design a site, build a blog diff --git a/fastlane/metadata/en-US/.gitkeep b/fastlane/metadata/en-US/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/en-US/description.txt b/fastlane/metadata/en-US/description.txt deleted file mode 100644 index 04a5230800f7..000000000000 --- a/fastlane/metadata/en-US/description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Manage or create your WordPress blog or website right from your iOS device: create and edit posts and pages, upload your favorite photos and videos, view stats and reply to comments. - -With WordPress for iOS, you have the power to publish in the palm of your hand. Draft a spontaneous haiku from the couch. Snap and post a photo on your lunch break. Respond to your latest comments, or check your stats to see what new countries today’s visitors are coming from. - -WordPress for iOS is an Open Source project, which means you too can contribute to its development. Learn more at https://apps.wordpress.com/contribute/. - -WordPress for iOS supports WordPress.com and self-hosted WordPress.org sites running WordPress 4.0 or higher. - -Need help with the app? Visit the forums at https://ios.forums.wordpress.org/ or tweet us @WordPressiOS. - -View the Privacy Notice for California Users at https://automattic.com/privacy/#california-consumer-privacy-act-ccpa. diff --git a/fastlane/metadata/en-US/keywords.txt b/fastlane/metadata/en-US/keywords.txt deleted file mode 100644 index 46d9ead15c94..000000000000 --- a/fastlane/metadata/en-US/keywords.txt +++ /dev/null @@ -1 +0,0 @@ -blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs \ No newline at end of file diff --git a/fastlane/metadata/en-US/name.txt b/fastlane/metadata/en-US/name.txt deleted file mode 100644 index 028d836eea1f..000000000000 --- a/fastlane/metadata/en-US/name.txt +++ /dev/null @@ -1 +0,0 @@ -WordPress – Website Builder \ No newline at end of file diff --git a/fastlane/metadata/en-US/release_notes.txt b/fastlane/metadata/en-US/release_notes.txt deleted file mode 100644 index adc15766a572..000000000000 --- a/fastlane/metadata/en-US/release_notes.txt +++ /dev/null @@ -1,10 +0,0 @@ -* [*] a11y: VoiceOver has been improved on the Menus view and now announces changes to ordering. [#18155] -* [*] Notifications list: remove comment Trash swipe action. [#18349] -* [*] Web previews now abide by safe areas when a toolbar is shown [#18127] -* [*] Site creation: Adds a new screen asking the user the intent of the site [#18367] -* [**] Block Editor: Quote block: Adds support for V2 behind a feature flag [https://github.com/WordPress/gutenberg/pull/40133] -* [**] Block Editor: Update "add block" button's style in default editor view [https://github.com/WordPress/gutenberg/pull/39726] -* [*] Block Editor: Remove banner error notification on upload failure [https://github.com/WordPress/gutenberg/pull/39694] -* [*] My Site: display site name in My Site screen nav title [#18373] -* [*] [internal] Site creation: Adds a new screen asking the user the name of the site [#18280] - diff --git a/fastlane/metadata/en-US/subtitle.txt b/fastlane/metadata/en-US/subtitle.txt deleted file mode 100644 index b082dcb78bf7..000000000000 --- a/fastlane/metadata/en-US/subtitle.txt +++ /dev/null @@ -1 +0,0 @@ -Design a site, build a blog \ No newline at end of file diff --git a/fastlane/metadata/es-ES/.gitkeep b/fastlane/metadata/es-ES/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/es-ES/keywords.txt b/fastlane/metadata/es-ES/keywords.txt index 9fa7ea3941f7..53eac7946caf 100644 --- a/fastlane/metadata/es-ES/keywords.txt +++ b/fastlane/metadata/es-ES/keywords.txt @@ -1 +1 @@ -bloguero,escritura,bloguear,web,creador,online,tienda,negocio,construir,crear,escribir,blogs \ No newline at end of file +bloguero,escritura,bloguear,web,creador,online,tienda,negocio,construir,crear,escribir,blogs diff --git a/fastlane/metadata/es-ES/name.txt b/fastlane/metadata/es-ES/name.txt index fbca32a5e561..678c41168ce0 100644 --- a/fastlane/metadata/es-ES/name.txt +++ b/fastlane/metadata/es-ES/name.txt @@ -1 +1 @@ -WordPress - Constructor web \ No newline at end of file +WordPress - Constructor web diff --git a/fastlane/metadata/es-ES/release_notes.txt b/fastlane/metadata/es-ES/release_notes.txt new file mode 100644 index 000000000000..904d23f91b34 --- /dev/null +++ b/fastlane/metadata/es-ES/release_notes.txt @@ -0,0 +1,11 @@ +Hemos hecho un pequeño pero mágico cambio al editor de bloques: El botón de «Añadir bloque» es más visible cuando abres el editor y no hay ningún bloque seleccionado. También hemos quitado uno de los tres avisos de error cuando falla en subirse un bloque de audio o medios - era un poco exagerado. + +Escucharás algunos retoques de accesibilidad en la experiencia con VoiceOver cuando reordenes elementos de un menú. Las instrucciones y avisos son más claros, y la jerarquía del menú tiene más sentido al hablarla. + +Hemos añadido una nueva pantalla al proceso de creación del sitio en la que puedes introducir la intención del sitio. Hemos probado esta pantalla con un pequeño grupo de usuarios y creemos que también te gustará. + +Las vistas previas web no cortan el fondo de los avisos cuando está visible la barra de herramientas de tu navegador. + +¿Qué hay del nombre? Bueno, si tu sitio tiene nombre, lo verás en el título de navegación de «Mi sitio». + +Cuando deslizas hacia la izquierda en un comentario en tu sección de avisos, ya no verás la opción de «Enviar a la papelera». En su lugar verás «Rechazar comentario» y «Aprobar comentario». Lo aprobamos. diff --git a/fastlane/metadata/es-ES/subtitle.txt b/fastlane/metadata/es-ES/subtitle.txt index 695eb975fd7a..ea5b02af5b52 100644 --- a/fastlane/metadata/es-ES/subtitle.txt +++ b/fastlane/metadata/es-ES/subtitle.txt @@ -1 +1 @@ -Diseña un sitio, crea un blog \ No newline at end of file +Diseña un sitio, crea un blog diff --git a/fastlane/metadata/es-MX/.gitkeep b/fastlane/metadata/es-MX/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/es-MX/keywords.txt b/fastlane/metadata/es-MX/keywords.txt index 9fa7ea3941f7..53eac7946caf 100644 --- a/fastlane/metadata/es-MX/keywords.txt +++ b/fastlane/metadata/es-MX/keywords.txt @@ -1 +1 @@ -bloguero,escritura,bloguear,web,creador,online,tienda,negocio,construir,crear,escribir,blogs \ No newline at end of file +bloguero,escritura,bloguear,web,creador,online,tienda,negocio,construir,crear,escribir,blogs diff --git a/fastlane/metadata/es-MX/name.txt b/fastlane/metadata/es-MX/name.txt index fbca32a5e561..678c41168ce0 100644 --- a/fastlane/metadata/es-MX/name.txt +++ b/fastlane/metadata/es-MX/name.txt @@ -1 +1 @@ -WordPress - Constructor web \ No newline at end of file +WordPress - Constructor web diff --git a/fastlane/metadata/es-MX/subtitle.txt b/fastlane/metadata/es-MX/subtitle.txt index 695eb975fd7a..ea5b02af5b52 100644 --- a/fastlane/metadata/es-MX/subtitle.txt +++ b/fastlane/metadata/es-MX/subtitle.txt @@ -1 +1 @@ -Diseña un sitio, crea un blog \ No newline at end of file +Diseña un sitio, crea un blog diff --git a/fastlane/metadata/fr-FR/.gitkeep b/fastlane/metadata/fr-FR/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/fr-FR/keywords.txt b/fastlane/metadata/fr-FR/keywords.txt index 63916c8815f8..bc957286bcac 100644 --- a/fastlane/metadata/fr-FR/keywords.txt +++ b/fastlane/metadata/fr-FR/keywords.txt @@ -1 +1 @@ -blogueur,écriture,blogs,web,créateur,en ligne,boutique,entreprise,créer,écrire,blog \ No newline at end of file +blogueur,écriture,blogs,web,créateur,en ligne,boutique,entreprise,créer,écrire,blog diff --git a/fastlane/metadata/fr-FR/name.txt b/fastlane/metadata/fr-FR/name.txt index 9610a3500dfe..f0ecebc43067 100644 --- a/fastlane/metadata/fr-FR/name.txt +++ b/fastlane/metadata/fr-FR/name.txt @@ -1 +1 @@ -WordPress - Création de sites \ No newline at end of file +WordPress - Création de sites diff --git a/fastlane/metadata/fr-FR/release_notes.txt b/fastlane/metadata/fr-FR/release_notes.txt new file mode 100644 index 000000000000..ab025f8e6723 --- /dev/null +++ b/fastlane/metadata/fr-FR/release_notes.txt @@ -0,0 +1,11 @@ +Nous avons apporté un petit changement, mais non des moindres, à l’éditeur de blocs : le bouton « Ajouter un bloc » gagne en visibilité lors de la première ouverture de l’éditeur, lorsqu’aucun bloc n’est encore sélectionné. Nous avons également supprimé l’une des trois notifications d’erreur (c’était un peu exagéré) lors de l’échec de chargement d’un bloc média ou audio. + +Vous entendrez certains changements dans l’expérience d’accessibilité VoiceOver lors de la réorganisation des éléments de menu. Les instructions et notifications sont plus claires, et la hiérarchie du menu a plus de sens à voix haute. + +Nous avons ajouté un nouvel écran au processus de création de site, où vous pouvez saisir l’intention de ce dernier. Nous avons testé cet écran auprès d’un petit groupe d’utilisateurs - il devrait aussi vous plaire ! + +Les aperçus Web ne couperont pas les notifications au bas de l’écran lorsque la barre d’outils de votre navigateur sera visible. + +Un nom bien choisi peut être un réel atout. Si vous avez donné un nom à votre site, vous le verrez dans le titre de navigation de l’écran Mon site. + +Lorsque vous effectuerez un balayage vers la gauche sur un commentaire dans vos notifications, vous ne verrez plus l’option « Déplacer vers la corbeille », mais « Désapprouver le commentaire » et « Approuver le commentaire ». On approuve ! diff --git a/fastlane/metadata/fr-FR/subtitle.txt b/fastlane/metadata/fr-FR/subtitle.txt index 0916feea62b9..c439391d070a 100644 --- a/fastlane/metadata/fr-FR/subtitle.txt +++ b/fastlane/metadata/fr-FR/subtitle.txt @@ -1 +1 @@ -Concevez un site créez un blog \ No newline at end of file +Concevez un site créez un blog diff --git a/fastlane/metadata/he/.gitkeep b/fastlane/metadata/he/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/he/keywords.txt b/fastlane/metadata/he/keywords.txt index 46d9ead15c94..7ab147e34e06 100644 --- a/fastlane/metadata/he/keywords.txt +++ b/fastlane/metadata/he/keywords.txt @@ -1 +1 @@ -blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs \ No newline at end of file +blogger,writing,blogging,web,maker,online,store,business,make,create,write,blogs diff --git a/fastlane/metadata/he/name.txt b/fastlane/metadata/he/name.txt index 028d836eea1f..f1c6744c4874 100644 --- a/fastlane/metadata/he/name.txt +++ b/fastlane/metadata/he/name.txt @@ -1 +1 @@ -WordPress – Website Builder \ No newline at end of file +WordPress – Website Builder diff --git a/fastlane/metadata/he/release_notes.txt b/fastlane/metadata/he/release_notes.txt new file mode 100644 index 000000000000..fd7370aa7529 --- /dev/null +++ b/fastlane/metadata/he/release_notes.txt @@ -0,0 +1,11 @@ +ביצענו שינוי קטן אך עוצמתי בעורך הבלוקים: התצוגה של הכפתור 'להוסיף בלוק' ברורה יותר כאשר פותחים לראשונה את העורך ללא בלוקים שנבחרו. הסרנו גם אחת משלוש הודעות השגיאה שמופיעות כאשר נכשלת הטעינה של בלוק מדיה או אודיו – חשבנו ששלוש היו יותר מדי. + +אפשר לשמוע גם כמה שינויים בנגישות בחוויית השימוש עם VoiceOver כאשר משנים את סדר הפריטים בתפריט. ההוראות וההודעות ברורות יותר וההיררכיה של התפריט הגיונית יותר לקריאה בקול. + +הוספנו מסך חדש לתהליך יצירת האתר וכעת אפשר להזין את הכוונה של האתר שלך. בדקנו את המסך הזה מול קבוצה קטנה של משתמשים ואנחנו חושבים שהוא ימצא חן גם בעיניך. + +תצוגות מקדימות לפריסת אינטרנט כבר לא חותכות הודעות שמוצגות בתחתית המסך כאשר סרגל הכלים של הדפדפן מוצג. + +איפה שמנו את השם? אם הענקת לאתר שלך שם, הוא יוצג בכותרת הניווט של 'האתר שלי'. + +כאשר עומדים על תגובה ומחליקים שמאלה במקטע 'הודעות', לא תופיע עוד האפשרות 'להעביר לפח'. במקום, יופיעו האפשרויות 'לבטל אישור תגובה' ו'לאשר תגובה'. אנחנו מאושרים. diff --git a/fastlane/metadata/he/subtitle.txt b/fastlane/metadata/he/subtitle.txt index b082dcb78bf7..08d11992ce2f 100644 --- a/fastlane/metadata/he/subtitle.txt +++ b/fastlane/metadata/he/subtitle.txt @@ -1 +1 @@ -Design a site, build a blog \ No newline at end of file +Design a site, build a blog diff --git a/fastlane/metadata/id/.gitkeep b/fastlane/metadata/id/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/id/keywords.txt b/fastlane/metadata/id/keywords.txt index 082f945adfc8..6e65dcd4514f 100644 --- a/fastlane/metadata/id/keywords.txt +++ b/fastlane/metadata/id/keywords.txt @@ -1 +1 @@ -blogger,tulisan,blogging,web,kreator,online,toko,bisnis,buat,ciptakan,tulis,blog \ No newline at end of file +blogger,tulisan,blogging,web,kreator,online,toko,bisnis,buat,ciptakan,tulis,blog diff --git a/fastlane/metadata/id/name.txt b/fastlane/metadata/id/name.txt index 838f34ae88e7..61b4296a6651 100644 --- a/fastlane/metadata/id/name.txt +++ b/fastlane/metadata/id/name.txt @@ -1 +1 @@ -WordPress – Pembuat Situs Web \ No newline at end of file +WordPress – Pembuat Situs Web diff --git a/fastlane/metadata/id/release_notes.txt b/fastlane/metadata/id/release_notes.txt new file mode 100644 index 000000000000..ac27ad02715f --- /dev/null +++ b/fastlane/metadata/id/release_notes.txt @@ -0,0 +1,11 @@ +Kami membuat perubahan kecil yang berarti pada editor blok: tombol "Tambah Blok" lebih terlihat saat Anda pertama kali membuka editor tanpa ada blok yang dipilih. Kami juga menghapus salah satu dari tiga pemberitahuan kesalahan saat media atau blok audio gagal diunggah—rasanya berlebihan. + +Anda akan mendengar beberapa penyesuaian aksesibilitas pada pengalaman VoiceOver saat Anda mengatur ulang item menu. Panduan dan catatan lebih jelas, dan hirarki menu lebih terstruktur. + +Kami menambahkan layar baru ke proses pembuatan situs, tempat Anda dapat menuliskan maksud situs Anda. Kami telah menguji layar tersebut dengan sekelompok kecil pengguna. Kami pikir Anda juga akan menyukainya. + +Pratinjau web tidak akan memotong pemberitahuan di bagian bawah layar saat toolbar browser Anda terlihat. + +Apa maksud sebuah nama? Nah, jika situs Anda memiliki nama, Anda akan melihatnya di judul navigasi Situs Saya. + +Saat Anda menggeser ke kiri pada komentar di Notifikasi, Anda tidak akan melihat opsi "Tong Sampah" lagi. Sebagai gantinya, Anda akan melihat "Komentar yang Tidak Disetujui" dan "Setujui Komentar". Kami menyetujui. diff --git a/fastlane/metadata/id/subtitle.txt b/fastlane/metadata/id/subtitle.txt index b699dc2c20e9..d568ccd36e2c 100644 --- a/fastlane/metadata/id/subtitle.txt +++ b/fastlane/metadata/id/subtitle.txt @@ -1 +1 @@ -Desain situs, buat blog \ No newline at end of file +Desain situs, buat blog diff --git a/fastlane/metadata/it/.gitkeep b/fastlane/metadata/it/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/it/keywords.txt b/fastlane/metadata/it/keywords.txt index e211ad9021d5..0b09861ed2b9 100644 --- a/fastlane/metadata/it/keywords.txt +++ b/fastlane/metadata/it/keywords.txt @@ -1 +1 @@ -blogger,scrittura,blogging,web,realizzatore,online,negozio,attività,creare,scrivere,blog \ No newline at end of file +blogger,scrittura,blogging,web,realizzatore,online,negozio,attività,creare,scrivere,blog diff --git a/fastlane/metadata/it/name.txt b/fastlane/metadata/it/name.txt index e18bcccc6fb0..87bafecc5499 100644 --- a/fastlane/metadata/it/name.txt +++ b/fastlane/metadata/it/name.txt @@ -1 +1 @@ -WordPress – Costruzione siti \ No newline at end of file +WordPress – Costruzione siti diff --git a/fastlane/metadata/it/release_notes.txt b/fastlane/metadata/it/release_notes.txt new file mode 100644 index 000000000000..3082a1220969 --- /dev/null +++ b/fastlane/metadata/it/release_notes.txt @@ -0,0 +1,11 @@ +Abbiamo apportato alcune piccole ma significative modifiche all'editor a blocchi: il pulsante "Aggiungi blocco" è ora visibile alla prima apertura dell'editor senza i blocchi selezionati. Abbiamo anche rimosso una delle tre notifiche di errore quando un blocco Media o Audio non si caricava: sembrava eccessivo. + +Sentirai alcune ottimizzazioni all'accessibilità nell'esperienza VoiceOver durante la riorganizzazione degli elementi di menu. Le istruzioni e gli avvisi sono più chiari e la gerarchia del menu ha più senso ad alta voce. + +Abbiamo aggiunto una nuova schermata al processo di creazione del sito in cui puoi inserire lo scopo del sito. Abbiamo provato questa schermata con un piccolo gruppo di utenti e pensiamo potrà piacere anche a te. + +Le anteprime web non interromperanno le notifiche nella parte inferiore dello schermo quando la barra degli strumenti del browser è visibile. + +Cosa c'è in un nome? Se il sito ne ha uno, lo vedrai nel titolo della navigazione Il mio sito. + +Quando scorri verso sinistra su un commento nelle Notifiche, non vedrai più l'opzione "Sposta nel cestino". Vedrai invece "Rimuovi l'approvazione del commento" e "Approva commento". Approviamo. diff --git a/fastlane/metadata/it/subtitle.txt b/fastlane/metadata/it/subtitle.txt index b2d4709d40c7..bcd33ae73152 100644 --- a/fastlane/metadata/it/subtitle.txt +++ b/fastlane/metadata/it/subtitle.txt @@ -1 +1 @@ -Progetta un sito, crea un blog \ No newline at end of file +Progetta un sito, crea un blog diff --git a/fastlane/metadata/ja/.gitkeep b/fastlane/metadata/ja/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/ja/keywords.txt b/fastlane/metadata/ja/keywords.txt index b9c7cc21adc3..d61b533720d2 100644 --- a/fastlane/metadata/ja/keywords.txt +++ b/fastlane/metadata/ja/keywords.txt @@ -1 +1 @@ -ブロガー,ライティング,ブログ執筆,ウェブ,メーカー,オンライン,ストア,ビジネス,構築,作成,執筆,ブログ \ No newline at end of file +ブロガー,ライティング,ブログ執筆,ウェブ,メーカー,オンライン,ストア,ビジネス,構築,作成,執筆,ブログ diff --git a/fastlane/metadata/ja/name.txt b/fastlane/metadata/ja/name.txt index 48acd04a8199..a88bf76f2002 100644 --- a/fastlane/metadata/ja/name.txt +++ b/fastlane/metadata/ja/name.txt @@ -1 +1 @@ -WordPress - サイトビルダー \ No newline at end of file +WordPress - サイトビルダー diff --git a/fastlane/metadata/ja/release_notes.txt b/fastlane/metadata/ja/release_notes.txt new file mode 100644 index 000000000000..a144a3267f99 --- /dev/null +++ b/fastlane/metadata/ja/release_notes.txt @@ -0,0 +1,11 @@ +ブロックエディターに小さいながらも重要な変更を加えました。ブロックを選択していない状態でエディターを初めて開いたときに、「ブロックを追加」ボタンがこれまでよりもわかりやすく表示されます。 また、メディアブロックや音声ブロックをアップロードできなかったときに表示される3つのエラー通知のうち、不要と思われるものを1つ削除しました。 + +VoiceOver を使ってメニュー項目を並べ替える際に、アクセシビリティの調整に関するガイダンスが再生されます。 手順や注意点が明確になり、メニュー階層を音声で確認しやすくなりました。 + +サイト作成時に、そのサイトの目的を入力できる画面を新たに追加しました。 この画面は小規模のユーザーグループで検証されたものですが、皆さまにも気に入っていただけると思います。 + +ブラウザーのツールバーが表示されていると、ウェブプレビューで画面下部の通知が見えなくなってしまう問題が解消されました。 + +名前にはどんな意味が込められていますか ? サイト名に由来がある場合、「参加サイト」のナビゲーションタイトルに表示できます。 + +通知のコメントを左にスワイプしたときの「ゴミ箱へ移動」オプションが表示されなくなりました。 今後は「コメントを承認しない」と「コメントを承認する」が代わりに表示されます。 当社で承認を行います。 diff --git a/fastlane/metadata/ja/subtitle.txt b/fastlane/metadata/ja/subtitle.txt index c8e2d8235ba9..4505b21a7510 100644 --- a/fastlane/metadata/ja/subtitle.txt +++ b/fastlane/metadata/ja/subtitle.txt @@ -1 +1 @@ -サイトをデザイン、ブログを作成 \ No newline at end of file +サイトをデザイン、ブログを作成 diff --git a/fastlane/metadata/ko/.gitkeep b/fastlane/metadata/ko/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/ko/keywords.txt b/fastlane/metadata/ko/keywords.txt index 82379101486a..cfced05c8a88 100644 --- a/fastlane/metadata/ko/keywords.txt +++ b/fastlane/metadata/ko/keywords.txt @@ -1 +1 @@ -블로거,글쓰기,블로깅,웹,제작자,온라인,스토어,비즈니스,만들기,생성,쓰기,블로그 \ No newline at end of file +블로거,글쓰기,블로깅,웹,제작자,온라인,스토어,비즈니스,만들기,생성,쓰기,블로그 diff --git a/fastlane/metadata/ko/name.txt b/fastlane/metadata/ko/name.txt index 8c935b5d153a..eb024ef3bbea 100644 --- a/fastlane/metadata/ko/name.txt +++ b/fastlane/metadata/ko/name.txt @@ -1 +1 @@ -워드프레스 – 웹사이트 제작 도구 \ No newline at end of file +워드프레스 – 웹사이트 제작 도구 diff --git a/fastlane/metadata/ko/release_notes.txt b/fastlane/metadata/ko/release_notes.txt new file mode 100644 index 000000000000..3f33ae43d1bd --- /dev/null +++ b/fastlane/metadata/ko/release_notes.txt @@ -0,0 +1,11 @@ +블록 편집기에 작지만 강력한 변경 사항을 적용했습니다. 블록을 선택하지 않고 편집기를 처음 열 때 "블록 추가" 버튼이 더 잘 보입니다. 또한 미디어 또는 오디오 블록이 업로드되지 않을 때 표시되는 3가지 오류 알림 중 지나치다고 느껴졌던 하나를 제거했습니다. + +메뉴 항목을 재정렬할 때 VoiceOver 환경의 일부 접근성이 조정됩니다. 지침과 공지가 더 명확하고, 메뉴 계층구조가 훨씬 잘 이해됩니다. + +사이트의 의도를 입력할 수 있는 새 화면을 사이트 생성 프로세스에 추가했습니다. 작은 사용자 그룹으로 이 화면을 테스트했으며 마음에 드시리라 생각합니다. + +웹 미리보기에서 브라우저 도구 모음이 표시될 때 화면 하단 알림이 잘리지 않습니다. + +이름은 어떻게 되나요? 사이트에 이름이 있으면 내 사이트 탐색 제목이 표시됩니다. + +알림에서 댓글을 왼쪽으로 살짝 밀 때 이제는 "휴지통" 옵션이 표시되지 않습니다. 그 대신에 "댓글 미승인"과 "댓글 승인"이 표시됩니다. 자동으로 승인됩니다. diff --git a/fastlane/metadata/ko/subtitle.txt b/fastlane/metadata/ko/subtitle.txt index 83cfcab15b51..d414cfad6190 100644 --- a/fastlane/metadata/ko/subtitle.txt +++ b/fastlane/metadata/ko/subtitle.txt @@ -1 +1 @@ -사이트 디자인, 블로그 제작 \ No newline at end of file +사이트 디자인, 블로그 제작 diff --git a/fastlane/metadata/nl-NL/.gitkeep b/fastlane/metadata/nl-NL/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/nl-NL/keywords.txt b/fastlane/metadata/nl-NL/keywords.txt index c6146c7062f8..a34914743428 100644 --- a/fastlane/metadata/nl-NL/keywords.txt +++ b/fastlane/metadata/nl-NL/keywords.txt @@ -1 +1 @@ -blogger,schrijven,blogging,web,maker,online,winkel,bedrijf,maak,creëer,schrijf,blogs \ No newline at end of file +blogger,schrijven,blogging,web,maker,online,winkel,bedrijf,maak,creëer,schrijf,blogs diff --git a/fastlane/metadata/nl-NL/name.txt b/fastlane/metadata/nl-NL/name.txt index 11448f85e18c..699fcf110050 100644 --- a/fastlane/metadata/nl-NL/name.txt +++ b/fastlane/metadata/nl-NL/name.txt @@ -1 +1 @@ -WordPress – Website bouwer \ No newline at end of file +WordPress – Website bouwer diff --git a/fastlane/metadata/nl-NL/release_notes.txt b/fastlane/metadata/nl-NL/release_notes.txt new file mode 100644 index 000000000000..4637ce371f6a --- /dev/null +++ b/fastlane/metadata/nl-NL/release_notes.txt @@ -0,0 +1,11 @@ +We hebben een kleine maar toffe aanpassing gedaan aan de blokeditor: de knop 'Blokken toevoegen' is nu duidelijker weergegeven als je de editor opent wanneer er nog geen blokken zijn geselecteerd. Daarnaast hebben we een van de drie foutmeldingen verwijderd die bij een mislukte upload van een media- of audioblok verschijnt. Deze leek overbodig. + +Je zult enkele kleine veranderingen aan de toegankelijkheid merken in de VoiceOver wanneer je delen van het menu opnieuw ordent. Instructies en berichtgevingen zijn duidelijker en de menuhiërarchie is logischer wanneer deze wordt uitgesproken. + +We hebben een nieuw scherm aan het aanmaakproces van websites toegevoegd, waar je het doel van je site kunt invoeren. We hebben dit scherm getest bij een kleine groep gebruikers en denken dat je dit ook leuk zult vinden. + +Voorbeeldweergaven van websites snijden meldingen onderaan het scherm niet meer af wanneer de browserwerkbalk open staat. + +Shakespeare schreef ooit: What's in a name? Nou, als je site een naam heeft, zie je deze in de navigatietitel bij Mijn site. + +Als je naar links veegt bij een opmerking in je meldingen, zie je geen optie 'Prullenbak' meer. In plaats daarvan zie je 'Opmerking afkeuren' en 'Opmerking goedkeuren'. We keuren het goed. diff --git a/fastlane/metadata/nl-NL/subtitle.txt b/fastlane/metadata/nl-NL/subtitle.txt index 860c1c7b6c10..6fcc6ea493d0 100644 --- a/fastlane/metadata/nl-NL/subtitle.txt +++ b/fastlane/metadata/nl-NL/subtitle.txt @@ -1 +1 @@ -Ontwerp je site, bouw je blog \ No newline at end of file +Ontwerp je site, bouw je blog diff --git a/fastlane/metadata/no/.gitkeep b/fastlane/metadata/no/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/no/keywords.txt b/fastlane/metadata/no/keywords.txt deleted file mode 100644 index 216b4985fa33..000000000000 --- a/fastlane/metadata/no/keywords.txt +++ /dev/null @@ -1 +0,0 @@ -sosial,notater,foto,skriving,geotagging,medier,blogg,wordpress,nettsted,hjemmeside,blogging,design diff --git a/fastlane/metadata/no/name.txt b/fastlane/metadata/no/name.txt deleted file mode 100644 index bacf8ed91ea2..000000000000 --- a/fastlane/metadata/no/name.txt +++ /dev/null @@ -1 +0,0 @@ -WordPress diff --git a/fastlane/metadata/no/subtitle.txt b/fastlane/metadata/no/subtitle.txt deleted file mode 100644 index 9114a459ffc9..000000000000 --- a/fastlane/metadata/no/subtitle.txt +++ /dev/null @@ -1 +0,0 @@ -Administrer nettsted overalt \ No newline at end of file diff --git a/fastlane/metadata/pt-BR/.gitkeep b/fastlane/metadata/pt-BR/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/pt-BR/keywords.txt b/fastlane/metadata/pt-BR/keywords.txt index b7ff165b6962..612155c522b0 100644 --- a/fastlane/metadata/pt-BR/keywords.txt +++ b/fastlane/metadata/pt-BR/keywords.txt @@ -1 +1 @@ -blogueiro,escrita,blog,web,criador,online,loja,negócio,criar,fazer,escrever,blogs \ No newline at end of file +blogueiro,escrita,blog,web,criador,online,loja,negócio,criar,fazer,escrever,blogs diff --git a/fastlane/metadata/pt-BR/name.txt b/fastlane/metadata/pt-BR/name.txt index c43a37e40408..cdd44ec19838 100644 --- a/fastlane/metadata/pt-BR/name.txt +++ b/fastlane/metadata/pt-BR/name.txt @@ -1 +1 @@ -WordPress – Criador de sites \ No newline at end of file +WordPress – Criador de sites diff --git a/fastlane/metadata/pt-BR/release_notes.txt b/fastlane/metadata/pt-BR/release_notes.txt new file mode 100644 index 000000000000..74c8099441a0 --- /dev/null +++ b/fastlane/metadata/pt-BR/release_notes.txt @@ -0,0 +1,11 @@ +Fizemos uma melhoria pequena mas importante no editor de blocos: o botão "Adicionar bloco" agora está mais visível ao abrir o editor sem nenhum bloco selecionado. Também removemos uma das três notificações de erro quando o bloco de áudio ou mídia não consegue enviar o arquivo - estava exagerado. + +Você ouvirá algumas melhorias em acessibilidade na experiência VoiceOver ao reordenar itens de menu. Instruções e avisos são mais claros e a hierarquia do menu faz mais sentido em voz alta. + +Adicionamos uma nova tela no processo de criação do site onde você poderá definir o objetivo do site. Essa nova tela foi testada com um pequeno grupo de usuários e acreditamos que você também gostará. + +A pré-visualização no navegador não será mais cortada quando a barra de ferramentas de seu navegador estiver visível. + +O que é um nome? Bem, se o seu site tiver um nome, ele será exibido no título de Meu Site. + +Ao deslizar um comentário para a direita em suas notificações, você não verá mais a opção Lixeira. Ao invés, você verá as opções "Desaprovar comentário" e "Aprovar comentário". Nós aprovamos! diff --git a/fastlane/metadata/pt-BR/subtitle.txt b/fastlane/metadata/pt-BR/subtitle.txt index b5e051496d72..7b522406a32d 100644 --- a/fastlane/metadata/pt-BR/subtitle.txt +++ b/fastlane/metadata/pt-BR/subtitle.txt @@ -1 +1 @@ -Faça um site, crie um blog \ No newline at end of file +Faça um site, crie um blog diff --git a/fastlane/metadata/pt-PT/.gitkeep b/fastlane/metadata/pt-PT/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/pt-PT/description.txt b/fastlane/metadata/pt-PT/description.txt deleted file mode 100644 index 04a5230800f7..000000000000 --- a/fastlane/metadata/pt-PT/description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Manage or create your WordPress blog or website right from your iOS device: create and edit posts and pages, upload your favorite photos and videos, view stats and reply to comments. - -With WordPress for iOS, you have the power to publish in the palm of your hand. Draft a spontaneous haiku from the couch. Snap and post a photo on your lunch break. Respond to your latest comments, or check your stats to see what new countries today’s visitors are coming from. - -WordPress for iOS is an Open Source project, which means you too can contribute to its development. Learn more at https://apps.wordpress.com/contribute/. - -WordPress for iOS supports WordPress.com and self-hosted WordPress.org sites running WordPress 4.0 or higher. - -Need help with the app? Visit the forums at https://ios.forums.wordpress.org/ or tweet us @WordPressiOS. - -View the Privacy Notice for California Users at https://automattic.com/privacy/#california-consumer-privacy-act-ccpa. diff --git a/fastlane/metadata/pt-PT/keywords.txt b/fastlane/metadata/pt-PT/keywords.txt deleted file mode 100644 index ab6cbfc0f9a1..000000000000 --- a/fastlane/metadata/pt-PT/keywords.txt +++ /dev/null @@ -1 +0,0 @@ -social,network,notes,jetpack,photos,writing,geotagging,media,blog,wordpress,website,blogging,design diff --git a/fastlane/metadata/pt-PT/name.txt b/fastlane/metadata/pt-PT/name.txt deleted file mode 100644 index bacf8ed91ea2..000000000000 --- a/fastlane/metadata/pt-PT/name.txt +++ /dev/null @@ -1 +0,0 @@ -WordPress diff --git a/fastlane/metadata/pt-PT/subtitle.txt b/fastlane/metadata/pt-PT/subtitle.txt deleted file mode 100644 index 4181b65c7d44..000000000000 --- a/fastlane/metadata/pt-PT/subtitle.txt +++ /dev/null @@ -1 +0,0 @@ -Manage your website anywhere diff --git a/fastlane/metadata/ru/.gitkeep b/fastlane/metadata/ru/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/ru/keywords.txt b/fastlane/metadata/ru/keywords.txt index 1f4be17077d5..827eea729852 100644 --- a/fastlane/metadata/ru/keywords.txt +++ b/fastlane/metadata/ru/keywords.txt @@ -1 +1 @@ -блогер,написание статей,ведение блога,веб,создатель,онлайн,магазин,бизнес,создавать,творить,писать \ No newline at end of file +блогер,написание статей,ведение блога,веб,создатель,онлайн,магазин,бизнес,создавать,творить,писать diff --git a/fastlane/metadata/ru/name.txt b/fastlane/metadata/ru/name.txt index e088ad38f18a..c6f82962c874 100644 --- a/fastlane/metadata/ru/name.txt +++ b/fastlane/metadata/ru/name.txt @@ -1 +1 @@ -WordPress – конструктор сайтов \ No newline at end of file +WordPress – конструктор сайтов diff --git a/fastlane/metadata/ru/release_notes.txt b/fastlane/metadata/ru/release_notes.txt new file mode 100644 index 000000000000..c6e7b0c5a525 --- /dev/null +++ b/fastlane/metadata/ru/release_notes.txt @@ -0,0 +1,11 @@ +Мы внесли небольшое, но важное изменение в редактор блоков: кнопка "Добавить блок" стала лучше видна при открытии редактора без выбранных блоков. Кроме того, мы удалили одно из трёх уведомлений об ошибке при неуспешной выгрузке медиа- или аудиоблока, так как оно было избыточным. + +Вы услышите некоторые изменения в интерфейсе VoiceOver для слабовидящих, когда будете менять порядок элементов меню. Инструкции и уведомления стали более наглядными, а иерархия меню — более логичной. + +Мы добавили новый экран в процесс создания сайта, на котором можно указать предназначение сайта. Экран был протестирован небольшой группой пользователей, и мы надеемся, что вам он также понравится. + +Окно предварительного просмотра веб-страниц не усекает уведомления в нижней части экрана при отображении панели инструментов браузера. + +Что даёт название? Если у вашего сайта есть название, оно отображается в заголовке окна навигации "Мой сайт". + +При смахивании комментария влево в разделе уведомлений больше не отображается опция "Корзина". Вместо него отображаются опции "Отменить утверждение комментария" и "Утвердить комментарий". Мы одобряем. diff --git a/fastlane/metadata/ru/subtitle.txt b/fastlane/metadata/ru/subtitle.txt index 633f1a06f843..8efcce480a22 100644 --- a/fastlane/metadata/ru/subtitle.txt +++ b/fastlane/metadata/ru/subtitle.txt @@ -1 +1 @@ -Создайте веб-сайт или блог \ No newline at end of file +Создайте веб-сайт или блог diff --git a/fastlane/metadata/sv/.gitkeep b/fastlane/metadata/sv/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/sv/keywords.txt b/fastlane/metadata/sv/keywords.txt index faf412f6b335..c8a4b649888e 100644 --- a/fastlane/metadata/sv/keywords.txt +++ b/fastlane/metadata/sv/keywords.txt @@ -1 +1 @@ -bloggare,skriva,bloggande,webb,ebutik,handel,system,bygga,skapa,bloggar \ No newline at end of file +bloggare,skriva,bloggande,webb,ebutik,handel,system,bygga,skapa,bloggar diff --git a/fastlane/metadata/sv/name.txt b/fastlane/metadata/sv/name.txt index d944d4d838d2..e7f5c55225cc 100644 --- a/fastlane/metadata/sv/name.txt +++ b/fastlane/metadata/sv/name.txt @@ -1 +1 @@ -WordPress – webbplatsbyggare \ No newline at end of file +WordPress – webbplatsbyggare diff --git a/fastlane/metadata/sv/release_notes.txt b/fastlane/metadata/sv/release_notes.txt new file mode 100644 index 000000000000..4fb7dcf5a04a --- /dev/null +++ b/fastlane/metadata/sv/release_notes.txt @@ -0,0 +1,11 @@ +Vi har gjort en liten men viktig ändring i blockredigeraren: knappen "Lägg till block" är nu mer synlig när du öppnar redigeraren och inte har valt några block. Vi har även tagit bort ett av de tre felmeddelandena som visades om uppladdningen av en mediafil eller ett ljudblock misslyckades – det behövdes helt enkelt inte. + +Du kommer dessutom att kunna höra några tillgänglighetsförbättringar i VoiceOver-upplevelsen när du arrangerar om menyval. Instruktionerna och meddelandena är nu tydligare och menyhierarkin låter mer vettig. + +Vi har lagt till en ny skärm i processen för webbplatsskapande, där du kan ange syftet med din webbplats. Vi har testat den här skärmen med en lite grupp användare och vi tror att du också kommer att gilla den. + +Webbförhandsgranskningar kommer inte längre att skära av meddelanden längst ner på skärmen när din webbläsares verktygsfält är synligt. + +Vad säger ett namn? Om din webbplats har ett kommer du i alla fall att se det i navigeringsrubriken för Min webbplats. + +När du sveper åt vänster på en kommentar i dina Notiser kommer du inte längre att se alternativet "Ta bort". Istället kommer alternativen "Godkänn ej kommentar" och "Godkänn kommentar" att visas. Det godkänner vi. diff --git a/fastlane/metadata/sv/subtitle.txt b/fastlane/metadata/sv/subtitle.txt index 562fd5055106..d038d0f9365a 100644 --- a/fastlane/metadata/sv/subtitle.txt +++ b/fastlane/metadata/sv/subtitle.txt @@ -1 +1 @@ -Skapa webbplats eller blogg \ No newline at end of file +Skapa webbplats eller blogg diff --git a/fastlane/metadata/th/.gitkeep b/fastlane/metadata/th/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/th/description.txt b/fastlane/metadata/th/description.txt deleted file mode 100644 index 04a5230800f7..000000000000 --- a/fastlane/metadata/th/description.txt +++ /dev/null @@ -1,11 +0,0 @@ -Manage or create your WordPress blog or website right from your iOS device: create and edit posts and pages, upload your favorite photos and videos, view stats and reply to comments. - -With WordPress for iOS, you have the power to publish in the palm of your hand. Draft a spontaneous haiku from the couch. Snap and post a photo on your lunch break. Respond to your latest comments, or check your stats to see what new countries today’s visitors are coming from. - -WordPress for iOS is an Open Source project, which means you too can contribute to its development. Learn more at https://apps.wordpress.com/contribute/. - -WordPress for iOS supports WordPress.com and self-hosted WordPress.org sites running WordPress 4.0 or higher. - -Need help with the app? Visit the forums at https://ios.forums.wordpress.org/ or tweet us @WordPressiOS. - -View the Privacy Notice for California Users at https://automattic.com/privacy/#california-consumer-privacy-act-ccpa. diff --git a/fastlane/metadata/th/keywords.txt b/fastlane/metadata/th/keywords.txt deleted file mode 100644 index ab6cbfc0f9a1..000000000000 --- a/fastlane/metadata/th/keywords.txt +++ /dev/null @@ -1 +0,0 @@ -social,network,notes,jetpack,photos,writing,geotagging,media,blog,wordpress,website,blogging,design diff --git a/fastlane/metadata/th/name.txt b/fastlane/metadata/th/name.txt deleted file mode 100644 index bacf8ed91ea2..000000000000 --- a/fastlane/metadata/th/name.txt +++ /dev/null @@ -1 +0,0 @@ -WordPress diff --git a/fastlane/metadata/th/subtitle.txt b/fastlane/metadata/th/subtitle.txt deleted file mode 100644 index 4181b65c7d44..000000000000 --- a/fastlane/metadata/th/subtitle.txt +++ /dev/null @@ -1 +0,0 @@ -Manage your website anywhere diff --git a/fastlane/metadata/tr/.gitkeep b/fastlane/metadata/tr/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/tr/keywords.txt b/fastlane/metadata/tr/keywords.txt index 066982aa1d36..274a912a79e5 100644 --- a/fastlane/metadata/tr/keywords.txt +++ b/fastlane/metadata/tr/keywords.txt @@ -1 +1 @@ -blogger,yazı,bloglama,web,maker,çevrimiçi,mağaza,iş,yap,oluştur,yaz,bloglar \ No newline at end of file +blogger,yazı,bloglama,web,maker,çevrimiçi,mağaza,iş,yap,oluştur,yaz,bloglar diff --git a/fastlane/metadata/tr/name.txt b/fastlane/metadata/tr/name.txt index 5af11bc5d4e2..895b84237ceb 100644 --- a/fastlane/metadata/tr/name.txt +++ b/fastlane/metadata/tr/name.txt @@ -1 +1 @@ -WordPress – Site Oluşturucu \ No newline at end of file +WordPress – Site Oluşturucu diff --git a/fastlane/metadata/tr/release_notes.txt b/fastlane/metadata/tr/release_notes.txt new file mode 100644 index 000000000000..a5bdb54632d5 --- /dev/null +++ b/fastlane/metadata/tr/release_notes.txt @@ -0,0 +1,11 @@ +Blok düzenleyicide küçük ama güçlü bir değişiklik yaptık: Düzenleyiciyi hiçbir blok seçili olmadan ilk açtığınızda "Blok Ekle" düğmesi artık daha kolay görülüyor. Ayrıca, bir ortam veya ses bloku yüklenemediğinde görünen ve insanı bezdiren üç hata bildiriminden birini kaldırdık. + +Artık menü öğelerini yeniden düznelerken VoiceOver deneyiminde erişilebilirlikle ilgili bazı ipuçları duyacaksınız. Talimatlar ve bildirimler artık daha net, ses özellikli menü hiyerarşisi ise daha anlamlı. + +Site oluşturma işlemine sitenizin amacını girebileceğiniz yeni bir ekran eklendi. Bu ekran küçük bir kullanıcı grubuyla test edildi, sizin de beğeneceğinizi düşünüyoruz. + +Tarayıcı araç çubuğunuz görünür durumdayken web önizlemeleri artık ekranın alt kısmındaki bildirimleri engellemiyor. + +Ya ad? Sitenizde varsa, bunu Sitem gezinme başlığında görürsünüz. + +Bildirimlerinizden bir yorumu sola kaydırdığınızda artık "Çöp Kutusu" seçeneğini görmeyeceksiniz. Bunun yerine "Yorumu Onaylama" ve "Yorumu Onayla" mesajlarını göreceksiniz. Biz onaylıyoruz. diff --git a/fastlane/metadata/tr/subtitle.txt b/fastlane/metadata/tr/subtitle.txt index 864b54c82f19..d742bfb8bc5e 100644 --- a/fastlane/metadata/tr/subtitle.txt +++ b/fastlane/metadata/tr/subtitle.txt @@ -1 +1 @@ -Siteni tasarla, blog oluştur \ No newline at end of file +Siteni tasarla, blog oluştur diff --git a/fastlane/metadata/zh-Hans/.gitkeep b/fastlane/metadata/zh-Hans/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/zh-Hans/keywords.txt b/fastlane/metadata/zh-Hans/keywords.txt index 307408df3f93..3087f6c90f0d 100644 --- a/fastlane/metadata/zh-Hans/keywords.txt +++ b/fastlane/metadata/zh-Hans/keywords.txt @@ -1 +1 @@ -博主,撰写,博客,网页,制作工具,在线,商店,业务,制作,创建,撰写,博客 \ No newline at end of file +博主,撰写,博客,网页,制作工具,在线,商店,业务,制作,创建,撰写,博客 diff --git a/fastlane/metadata/zh-Hans/name.txt b/fastlane/metadata/zh-Hans/name.txt index ccc2b01af848..4547d43f7ce6 100644 --- a/fastlane/metadata/zh-Hans/name.txt +++ b/fastlane/metadata/zh-Hans/name.txt @@ -1 +1 @@ -WordPress - 网站构建器 \ No newline at end of file +WordPress - 网站构建器 diff --git a/fastlane/metadata/zh-Hans/release_notes.txt b/fastlane/metadata/zh-Hans/release_notes.txt new file mode 100644 index 000000000000..7eac1afeb8fe --- /dev/null +++ b/fastlane/metadata/zh-Hans/release_notes.txt @@ -0,0 +1,11 @@ +我们对区块编辑器做了一个微小而强大的更改:当您首次打开未选择区块的编辑器时,“添加区块”按钮会更加显眼。 媒体或音频区块上传失败后,我们也会移除三个错误通知中的其中一个 - 这感觉过犹不及。 + +当重新排列菜单项时,您将在 VoiceOver 体验中听到一些可访问性微调。 说明和通知更加清晰,并且菜单层级更有意义。 + +我们在站点创建过程中添加了新屏幕,您可以输入站点意图。 我们用一小组用户测试了此屏幕,并且我们相信您也会喜欢。 + +显示浏览器工具栏时,网页预览不会切断屏幕底端的通知。 + +名称里有什么? 如果您的站点有一个名称,您将在“我的站点”导航标题中看到该名称。 + +在“通知”中向左滑动评论时,您将不会再看到“回收站”选项。 相反的是,您将看到“不批准评论”和“批准评论”。 我们大力支持。 diff --git a/fastlane/metadata/zh-Hans/subtitle.txt b/fastlane/metadata/zh-Hans/subtitle.txt index 79e4f081d709..a43b04c50bf9 100644 --- a/fastlane/metadata/zh-Hans/subtitle.txt +++ b/fastlane/metadata/zh-Hans/subtitle.txt @@ -1 +1 @@ -设计站点,创建博客 \ No newline at end of file +设计站点,创建博客 diff --git a/fastlane/metadata/zh-Hant/.gitkeep b/fastlane/metadata/zh-Hant/.gitkeep new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/fastlane/metadata/zh-Hant/keywords.txt b/fastlane/metadata/zh-Hant/keywords.txt index a7257502b1dd..e88c89311f60 100644 --- a/fastlane/metadata/zh-Hant/keywords.txt +++ b/fastlane/metadata/zh-Hant/keywords.txt @@ -1 +1 @@ -部落客,寫作,撰寫網誌,網頁,製作工具,線上,商店,商用版,製作,建立,撰寫,網誌 \ No newline at end of file +部落客,寫作,撰寫網誌,網頁,製作工具,線上,商店,商用版,製作,建立,撰寫,網誌 diff --git a/fastlane/metadata/zh-Hant/name.txt b/fastlane/metadata/zh-Hant/name.txt index c7a8e02234dd..1bc7f4f30c3b 100644 --- a/fastlane/metadata/zh-Hant/name.txt +++ b/fastlane/metadata/zh-Hant/name.txt @@ -1 +1 @@ -WordPress – 網站建立工具 \ No newline at end of file +WordPress – 網站建立工具 diff --git a/fastlane/metadata/zh-Hant/release_notes.txt b/fastlane/metadata/zh-Hant/release_notes.txt new file mode 100644 index 000000000000..41fb94d4707e --- /dev/null +++ b/fastlane/metadata/zh-Hant/release_notes.txt @@ -0,0 +1,11 @@ +我們對區塊編輯器進行了細微卻重大的調整:首次開啟編輯器且未選取區塊時,「新增區塊」按鈕變得更顯眼了。 我們也移除了在媒體或音訊區塊上傳失敗時的錯誤通知之一 (原本共有三個錯誤通知),因為這顯得有點多餘。 + +重新排序選單項目時,你會在 VoiceOver 中聽到一些輔助功能調整。 操作指示和通知變得更清楚了,選單階層也變得更清晰好懂。 + +我們在網站建立流程中新增一個畫面,可讓你輸入網站用途。 我們已請一群使用者測試過此畫面,想必你也會喜歡的。 + +畫面出現瀏覽器工具列時,網頁預覽不會切掉畫面底部的通知了。 + +為網站命名了嗎? 如果有,你會在「我的網站」導覽標題中看到網站名稱。 + +在通知中將留言向左滑動時,你不會再看到「垃圾桶」選項。 畫面會改為顯示「駁回留言」和「核准留言」。 我們很贊賞此設計。 diff --git a/fastlane/metadata/zh-Hant/subtitle.txt b/fastlane/metadata/zh-Hant/subtitle.txt index 9ccb19178b32..1304820b0bfa 100644 --- a/fastlane/metadata/zh-Hant/subtitle.txt +++ b/fastlane/metadata/zh-Hant/subtitle.txt @@ -1 +1 @@ -設計網站,建立網誌 \ No newline at end of file +設計網站,建立網誌