From 7ef6503bdcc248fa659214ae901b38c1d32c1272 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Fri, 3 Jul 2026 14:28:28 +1200 Subject: [PATCH 1/5] Format stats widget sources with swift-format --- .../Sources/Helpers/WidgetDataReader.swift | 5 +-- .../LockScreenSiteListProvider.swift | 23 ++++++++++--- .../LockScreenStatsWidget.swift | 4 +-- .../Sources/SiteListProvider.swift | 23 ++++++++++--- .../Sources/Widgets/HomeWidgetAllTime.swift | 12 ++++--- .../Sources/Widgets/HomeWidgetThisWeek.swift | 33 +++++++++++------- .../Sources/Widgets/HomeWidgetToday.swift | 34 +++++++++++-------- 7 files changed, 89 insertions(+), 45 deletions(-) diff --git a/Sources/JetpackStatsWidgets/Sources/Helpers/WidgetDataReader.swift b/Sources/JetpackStatsWidgets/Sources/Helpers/WidgetDataReader.swift index e3901539f4a1..36d28bfe7549 100644 --- a/Sources/JetpackStatsWidgets/Sources/Helpers/WidgetDataReader.swift +++ b/Sources/JetpackStatsWidgets/Sources/Helpers/WidgetDataReader.swift @@ -6,8 +6,9 @@ final class WidgetDataReader { let userDefaults: UserDefaults? let cacheReader: WidgetDataCacheReader - init(_ userDefaults: UserDefaults? = UserDefaults(suiteName: BuildSettings.current.appGroupName), - _ cacheReader: any WidgetDataCacheReader = HomeWidgetDataFileReader() + init( + _ userDefaults: UserDefaults? = UserDefaults(suiteName: BuildSettings.current.appGroupName), + _ cacheReader: any WidgetDataCacheReader = HomeWidgetDataFileReader() ) { self.userDefaults = userDefaults self.cacheReader = cacheReader diff --git a/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenSiteListProvider.swift b/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenSiteListProvider.swift index 2e9f57e16c1f..0f677a1ce171 100644 --- a/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenSiteListProvider.swift +++ b/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenSiteListProvider.swift @@ -15,7 +15,8 @@ struct LockScreenSiteListProvider: IntentTimelineProvider { let minElapsedTimeToRefresh = 1 private var defaultSiteID: Int? { - UserDefaults(suiteName: BuildSettings.current.appGroupName)?.object(forKey: WidgetStatsConfiguration.userDefaultsSiteIdKey) as? Int + UserDefaults(suiteName: BuildSettings.current.appGroupName)? + .object(forKey: WidgetStatsConfiguration.userDefaultsSiteIdKey) as? Int } private let widgetDataLoader = WidgetDataReader() @@ -24,7 +25,11 @@ struct LockScreenSiteListProvider: IntentTimelineProvider { LockScreenStatsWidgetEntry.siteSelected(placeholderContent, context) } - func getSnapshot(for configuration: SelectSiteIntent, in context: Context, completion: @escaping (LockScreenStatsWidgetEntry) -> Void) { + func getSnapshot( + for configuration: SelectSiteIntent, + in context: Context, + completion: @escaping (LockScreenStatsWidgetEntry) -> Void + ) { switch widgetDataLoader.widgetData(for: configuration, defaultSiteID: defaultSiteID) { case .success(let widgetData): completion(.siteSelected(widgetData, context)) @@ -33,7 +38,11 @@ struct LockScreenSiteListProvider: IntentTimelineProvider { } } - func getTimeline(for configuration: SelectSiteIntent, in context: Context, completion: @escaping (Timeline>) -> Void) { + func getTimeline( + for configuration: SelectSiteIntent, + in context: Context, + completion: @escaping (Timeline>) -> Void + ) { switch widgetDataLoader.widgetData( for: configuration, defaultSiteID: defaultSiteID @@ -41,7 +50,9 @@ struct LockScreenSiteListProvider: IntentTimelineProvider { case .success(let widgetData): let date = Date() let nextRefreshDate = Calendar.current.date(byAdding: .minute, value: refreshInterval, to: date) ?? date - let elapsedTime = abs(Calendar.current.dateComponents([.minute], from: widgetData.date, to: date).minute ?? 0) + let elapsedTime = abs( + Calendar.current.dateComponents([.minute], from: widgetData.date, to: date).minute ?? 0 + ) let privateCompletion = { (timelineEntry: LockScreenStatsWidgetEntry) in let timeline = Timeline(entries: [timelineEntry], policy: .after(nextRefreshDate)) @@ -56,7 +67,9 @@ struct LockScreenSiteListProvider: IntentTimelineProvider { service.fetchStats(for: widgetData) { result in switch result { case .failure(let error): - DDLogError("LockScreen StatsWidgets: failed to fetch remote stats. Returned error: \(error.localizedDescription)") + DDLogError( + "LockScreen StatsWidgets: failed to fetch remote stats. Returned error: \(error.localizedDescription)" + ) privateCompletion(.siteSelected(widgetData, context)) case .success(let newWidgetData): if let newWidgetData = newWidgetData as? T { diff --git a/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenStatsWidget.swift b/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenStatsWidget.swift index 2ca0ae596a0e..660dd3f257d9 100644 --- a/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenStatsWidget.swift +++ b/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenStatsWidget.swift @@ -25,7 +25,7 @@ struct LockScreenStatsWidget: Widget { placeholderContent: config.placeholderContent ) ) { (entry: LockScreenStatsWidgetEntry) -> LockScreenStatsWidgetsView in - return LockScreenStatsWidgetsView( + LockScreenStatsWidgetsView( timelineEntry: entry, viewProvider: config.viewProvider ) @@ -33,6 +33,6 @@ struct LockScreenStatsWidget: Widget { .configurationDisplayName(config.displayName) .description(config.description) .supportedFamilies(config.supportFamilies) - .iOS17ContentMarginsDisabled() /// Temporarily disable additional iOS17 margins for widgets + .iOS17ContentMarginsDisabled()/// Temporarily disable additional iOS17 margins for widgets } } diff --git a/Sources/JetpackStatsWidgets/Sources/SiteListProvider.swift b/Sources/JetpackStatsWidgets/Sources/SiteListProvider.swift index f71a19efe822..1daddf00cf05 100644 --- a/Sources/JetpackStatsWidgets/Sources/SiteListProvider.swift +++ b/Sources/JetpackStatsWidgets/Sources/SiteListProvider.swift @@ -17,7 +17,8 @@ struct SiteListProvider: IntentTimelineProvider { let minElapsedTimeToRefresh = 1 private var defaultSiteID: Int? { - UserDefaults(suiteName: BuildSettings.current.appGroupName)?.object(forKey: WidgetStatsConfiguration.userDefaultsSiteIdKey) as? Int + UserDefaults(suiteName: BuildSettings.current.appGroupName)? + .object(forKey: WidgetStatsConfiguration.userDefaultsSiteIdKey) as? Int } private let widgetDataLoader = WidgetDataReader() @@ -26,7 +27,11 @@ struct SiteListProvider: IntentTimelineProvider { StatsWidgetEntry.siteSelected(placeholderContent, context) } - func getSnapshot(for configuration: SelectSiteIntent, in context: Context, completion: @escaping (StatsWidgetEntry) -> Void) { + func getSnapshot( + for configuration: SelectSiteIntent, + in context: Context, + completion: @escaping (StatsWidgetEntry) -> Void + ) { switch widgetDataLoader.widgetData(for: configuration, defaultSiteID: defaultSiteID) { case .success(let widgetData): completion(.siteSelected(widgetData, context)) @@ -35,7 +40,11 @@ struct SiteListProvider: IntentTimelineProvider { } } - func getTimeline(for configuration: SelectSiteIntent, in context: Context, completion: @escaping (Timeline) -> Void) { + func getTimeline( + for configuration: SelectSiteIntent, + in context: Context, + completion: @escaping (Timeline) -> Void + ) { switch widgetDataLoader.widgetData( for: configuration, defaultSiteID: defaultSiteID @@ -43,7 +52,9 @@ struct SiteListProvider: IntentTimelineProvider { case .success(let widgetData): let date = Date() let nextRefreshDate = Calendar.current.date(byAdding: .minute, value: refreshInterval, to: date) ?? date - let elapsedTime = abs(Calendar.current.dateComponents([.minute], from: widgetData.date, to: date).minute ?? 0) + let elapsedTime = abs( + Calendar.current.dateComponents([.minute], from: widgetData.date, to: date).minute ?? 0 + ) let privateCompletion = { (timelineEntry: StatsWidgetEntry) in let timeline = Timeline(entries: [timelineEntry], policy: .after(nextRefreshDate)) @@ -58,7 +69,9 @@ struct SiteListProvider: IntentTimelineProvider { service.fetchStats(for: widgetData) { result in switch result { case .failure(let error): - DDLogError("StatsWidgets: failed to fetch remote stats. Returned error: \(error.localizedDescription)") + DDLogError( + "StatsWidgets: failed to fetch remote stats. Returned error: \(error.localizedDescription)" + ) privateCompletion(.siteSelected(widgetData, context)) case .success(let newWidgetData): privateCompletion(.siteSelected(newWidgetData, context)) diff --git a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetAllTime.swift b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetAllTime.swift index e80473c00a9b..13f3e59a93bf 100644 --- a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetAllTime.swift +++ b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetAllTime.swift @@ -24,15 +24,17 @@ struct HomeWidgetAllTime: Widget { IntentConfiguration( kind: WidgetStatsConfiguration.Kind.homeAllTime.rawValue, intent: SelectSiteIntent.self, - provider: SiteListProvider(service: StatsWidgetsService(), - placeholderContent: placeholderContent, - widgetKind: .allTime) + provider: SiteListProvider( + service: StatsWidgetsService(), + placeholderContent: placeholderContent, + widgetKind: .allTime + ) ) { (entry: StatsWidgetEntry) -> StatsWidgetsView in - return StatsWidgetsView(timelineEntry: entry) + StatsWidgetsView(timelineEntry: entry) } .configurationDisplayName(LocalizableStrings.allTimeWidgetTitle) .description(LocalizableStrings.allTimePreviewDescription) .supportedFamilies([.systemSmall, .systemMedium]) - .iOS17ContentMarginsDisabled() /// Temporarily disable additional iOS17 margins for widgets + .iOS17ContentMarginsDisabled()/// Temporarily disable additional iOS17 margins for widgets } } diff --git a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetThisWeek.swift b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetThisWeek.swift index fd71a0fe4e07..0aa7d4d5411f 100644 --- a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetThisWeek.swift +++ b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetThisWeek.swift @@ -18,31 +18,38 @@ struct HomeWidgetThisWeek: Widget { ThisWeekWidgetDay( date: Date(), viewsCount: 130, - dailyChangePercent: -0.22), + dailyChangePercent: -0.22 + ), ThisWeekWidgetDay( date: Date(timeIntervalSinceNow: -Self.secondsPerDay), viewsCount: 250, - dailyChangePercent: -0.06), + dailyChangePercent: -0.06 + ), ThisWeekWidgetDay( date: Date(timeIntervalSinceNow: -(Self.secondsPerDay * 2)), viewsCount: 260, - dailyChangePercent: 0.86), + dailyChangePercent: 0.86 + ), ThisWeekWidgetDay( date: Date(timeIntervalSinceNow: -(Self.secondsPerDay * 3)), viewsCount: 140, - dailyChangePercent: -0.3), + dailyChangePercent: -0.3 + ), ThisWeekWidgetDay( date: Date(timeIntervalSinceNow: -(Self.secondsPerDay * 4)), viewsCount: 200, - dailyChangePercent: -0.46), + dailyChangePercent: -0.46 + ), ThisWeekWidgetDay( date: Date(timeIntervalSinceNow: -(Self.secondsPerDay * 5)), viewsCount: 370, - dailyChangePercent: 0.19), + dailyChangePercent: 0.19 + ), ThisWeekWidgetDay( date: Date(timeIntervalSinceNow: -(Self.secondsPerDay * 6)), viewsCount: 310, - dailyChangePercent: 0.07) + dailyChangePercent: 0.07 + ) ]) ) @@ -50,15 +57,17 @@ struct HomeWidgetThisWeek: Widget { IntentConfiguration( kind: WidgetStatsConfiguration.Kind.homeThisWeek.rawValue, intent: SelectSiteIntent.self, - provider: SiteListProvider(service: StatsWidgetsService(), - placeholderContent: placeholderContent, - widgetKind: .thisWeek) + provider: SiteListProvider( + service: StatsWidgetsService(), + placeholderContent: placeholderContent, + widgetKind: .thisWeek + ) ) { (entry: StatsWidgetEntry) -> StatsWidgetsView in - return StatsWidgetsView(timelineEntry: entry) + StatsWidgetsView(timelineEntry: entry) } .configurationDisplayName(LocalizableStrings.thisWeekWidgetTitle) .description(LocalizableStrings.thisWeekPreviewDescription) .supportedFamilies([.systemMedium, .systemLarge]) - .iOS17ContentMarginsDisabled() /// Temporarily disable additional iOS17 margins for widgets + .iOS17ContentMarginsDisabled()/// Temporarily disable additional iOS17 margins for widgets } } diff --git a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetToday.swift b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetToday.swift index 96807ed150d6..eff6ebbd18cb 100644 --- a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetToday.swift +++ b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetToday.swift @@ -7,29 +7,35 @@ import TracksMini struct HomeWidgetToday: Widget { private let tracks = Tracks() - private let placeholderContent = HomeWidgetTodayData(siteID: 0, - siteName: "My WordPress Site", - url: "", - timeZone: TimeZone.current, - date: Date(), - stats: TodayWidgetStats(views: 649, - visitors: 572, - likes: 16, - comments: 8)) + private let placeholderContent = HomeWidgetTodayData( + siteID: 0, + siteName: "My WordPress Site", + url: "", + timeZone: TimeZone.current, + date: Date(), + stats: TodayWidgetStats( + views: 649, + visitors: 572, + likes: 16, + comments: 8 + ) + ) var body: some WidgetConfiguration { IntentConfiguration( kind: WidgetStatsConfiguration.Kind.homeToday.rawValue, intent: SelectSiteIntent.self, - provider: SiteListProvider(service: StatsWidgetsService(), - placeholderContent: placeholderContent, - widgetKind: .today) + provider: SiteListProvider( + service: StatsWidgetsService(), + placeholderContent: placeholderContent, + widgetKind: .today + ) ) { (entry: StatsWidgetEntry) -> StatsWidgetsView in - return StatsWidgetsView(timelineEntry: entry) + StatsWidgetsView(timelineEntry: entry) } .configurationDisplayName(LocalizableStrings.todayWidgetTitle) .description(LocalizableStrings.todayPreviewDescription) .supportedFamilies([.systemSmall, .systemMedium]) - .iOS17ContentMarginsDisabled() /// Temporarily disable additional iOS17 margins for widgets for StandBy + .iOS17ContentMarginsDisabled()/// Temporarily disable additional iOS17 margins for widgets for StandBy } } From 47d23c12952464931c747952cd2dabfb461109c1 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 7 Jul 2026 13:38:54 +1200 Subject: [PATCH 2/5] Add App Intents site entity and configuration intent for stats widgets Introduces SiteEntity, SiteEntityQuery, and an App Intents SelectSiteIntent in JetpackStatsWidgetsCore, backed by the same widget plist cache and shared defaults the SiriKit intents extension reads today. The entity identifier matches the legacy Site identifier so existing widget configurations survive the upcoming migration. No AppIntentsPackage registration is included because linkd rejects package references from statically linked modules, and static linking already merges the intent metadata into the consuming targets. CFBundleName in the test bundle plist keeps xcodebuild test working once the project contains App Intents. --- Modules/Package.swift | 6 +- .../AppIntents/SelectSiteIntent.swift | 36 +++++ .../AppIntents/SiteEntity.swift | 44 ++++++ .../AppIntents/SiteEntityQuery.swift | 56 ++++++++ .../WidgetStatsConfiguration.swift | 7 +- .../SiteEntityQueryTests.swift | 132 ++++++++++++++++++ Tests/KeystoneTests/WordPressTest-Info.plist | 2 + 7 files changed, 281 insertions(+), 2 deletions(-) create mode 100644 Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SelectSiteIntent.swift create mode 100644 Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SiteEntity.swift create mode 100644 Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SiteEntityQuery.swift create mode 100644 Modules/Tests/JetpackStatsWidgetsCoreTests/SiteEntityQueryTests.swift diff --git a/Modules/Package.swift b/Modules/Package.swift index 59b9cc1e5458..470a4adaa525 100644 --- a/Modules/Package.swift +++ b/Modules/Package.swift @@ -120,7 +120,11 @@ let package = Package( ], resources: [.process("Resources")] ), - .target(name: "JetpackStatsWidgetsCore", swiftSettings: [.swiftLanguageMode(.v5)]), + .target( + name: "JetpackStatsWidgetsCore", + dependencies: ["BuildSettingsKit"], + swiftSettings: [.swiftLanguageMode(.v5)] + ), .target( name: "JetpackSocial", dependencies: [ diff --git a/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SelectSiteIntent.swift b/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SelectSiteIntent.swift new file mode 100644 index 000000000000..a2cafa9a4b81 --- /dev/null +++ b/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SelectSiteIntent.swift @@ -0,0 +1,36 @@ +import AppIntents + +/// The widget configuration intent that lets the user pick which site a stats widget shows. +/// +/// Replaces the SiriKit intent of the same name that was generated from `Sites.intentdefinition`. +/// `intentClassName` and the `site` parameter name must not change: the system uses them to +/// migrate widget configurations created with the SiriKit intent, and a mismatch silently resets +/// users' widgets to the default site. +/// +/// The localization keys are the app-bundle names of the identifiers Xcode generated for the +/// legacy `.intentdefinition` ("gpCwrM", "ILcGmf"): GlotPress uploads them under the +/// `ios-widget.` prefix, and the downloaded translations land in the app's +/// `Localizable.strings` under those prefixed keys. +/// +/// The keys must resolve in two bundles, because the OS picks a different one depending on +/// version (verified on simulators): iOS 26 resolves the widget configuration UI's strings +/// against the app bundle (whose GlotPress-managed `Localizable.strings` carries the prefixed +/// keys in every locale), while iOS 17 resolves against the widget extension bundle, which +/// ships static copies of the same prefixed keys in +/// `Sources/JetpackStatsWidgets/Resources/.lproj/Localizable.strings`. +/// A nested SPM package resource bundle is never consulted, so the strings cannot live in +/// this package. +public struct SelectSiteIntent: WidgetConfigurationIntent, CustomIntentMigratedAppIntent { + public static let intentClassName = "SelectSiteIntent" + + public static let title = LocalizedStringResource("ios-widget.gpCwrM", defaultValue: "Select Site") + + // The legacy intent was ineligible for Siri suggestions; keep this + // configuration-only intent out of Shortcuts and Spotlight the same way. + public static let isDiscoverable = false + + @Parameter(title: LocalizedStringResource("ios-widget.ILcGmf", defaultValue: "Site")) + public var site: SiteEntity? + + public init() {} +} diff --git a/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SiteEntity.swift b/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SiteEntity.swift new file mode 100644 index 000000000000..cf5dbaf3dd9f --- /dev/null +++ b/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SiteEntity.swift @@ -0,0 +1,44 @@ +import AppIntents +import Foundation + +/// A WordPress.com (or Jetpack-connected) site, as exposed to the system via App Intents. +/// +/// The identifier is the site's WP.com ID encoded as a decimal string. It deliberately matches +/// the `identifier` of the legacy SiriKit `Site` object so that widget configurations created +/// before the App Intents migration keep resolving to the same site. +/// +/// The "ios-widget.ILcGmf" localization key resolves against the app bundle on iOS 26 and +/// the widget extension bundle on iOS 17; see `SelectSiteIntent` for the details. +public struct SiteEntity: AppEntity { + public static let typeDisplayRepresentation = TypeDisplayRepresentation( + name: LocalizedStringResource("ios-widget.ILcGmf", defaultValue: "Site") + ) + + public static var defaultQuery: SiteEntityQuery { SiteEntityQuery() } + + public let id: String + public let name: String + public let domain: String? + + public var displayRepresentation: DisplayRepresentation { + if let domain { + return DisplayRepresentation(title: "\(name)", subtitle: "\(domain)") + } + return DisplayRepresentation(title: "\(name)") + } + + init(siteID: Int, data: HomeWidgetTodayData) { + self.id = String(siteID) + self.name = data.siteName + self.domain = URLComponents(string: data.url)?.host + } + + /// A placeholder for a configured site that cannot currently be resolved from the + /// widget cache. Preserving the identifier keeps the user's widget configuration + /// intact until the cache becomes readable again. + init(unresolvedID: String) { + self.id = unresolvedID + self.name = unresolvedID + self.domain = nil + } +} diff --git a/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SiteEntityQuery.swift b/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SiteEntityQuery.swift new file mode 100644 index 000000000000..d231ea8dd057 --- /dev/null +++ b/Modules/Sources/JetpackStatsWidgetsCore/AppIntents/SiteEntityQuery.swift @@ -0,0 +1,56 @@ +import AppIntents +import BuildSettingsKit +import Foundation + +/// Resolves `SiteEntity` values from the widget data cache in the app group container. +/// +/// The site list mirrors what the stats widgets can display: the sites written by the app +/// into the Today widget's cache. +/// +/// The query deliberately provides no `defaultResult()`: a widget whose site parameter is +/// nil follows the app's current default site dynamically (resolved by `WidgetDataReader` +/// on every reload), matching the legacy SiriKit behavior. A default result would be baked +/// into the configuration at widget-add time and pin the widget to that site forever. +public struct SiteEntityQuery: EntityQuery { + private let appGroup: String + + public init() { + self.init(appGroup: BuildSettings.current.appGroupName) + } + + init(appGroup: String) { + self.appGroup = appGroup + } + + public func entities(for identifiers: [SiteEntity.ID]) async throws -> [SiteEntity] { + let sites = cachedSites() + // A configured widget re-resolves its site through this method on every reload. + // An identifier missing from the cache (deleted mid-write, decode failure) must + // stay attached to the configuration, or the widget silently falls back to the + // default site. Keep unknown identifiers as placeholder entities. + return identifiers.map { identifier in + sites.first { $0.id == identifier } ?? SiteEntity(unresolvedID: identifier) + } + } + + public func suggestedEntities() async throws -> [SiteEntity] { + cachedSites() + } + + private func cachedSites() -> [SiteEntity] { + guard let items = try? HomeWidgetCache(appGroup: appGroup).read() else { + return [] + } + return + items + .map { SiteEntity(siteID: $0.key, data: $0.value) } + .sorted { lhs, rhs in + let lhsName = lhs.name.lowercased() + let rhsName = rhs.name.lowercased() + guard lhsName != rhsName else { + return (lhs.domain?.lowercased() ?? "") < (rhs.domain?.lowercased() ?? "") + } + return lhsName < rhsName + } + } +} diff --git a/Modules/Sources/JetpackStatsWidgetsCore/WidgetStatsConfiguration.swift b/Modules/Sources/JetpackStatsWidgetsCore/WidgetStatsConfiguration.swift index 435dc8b56deb..d344957168c2 100644 --- a/Modules/Sources/JetpackStatsWidgetsCore/WidgetStatsConfiguration.swift +++ b/Modules/Sources/JetpackStatsWidgetsCore/WidgetStatsConfiguration.swift @@ -5,6 +5,11 @@ public enum WidgetStatsConfiguration { public static let keychainServiceName = "JetpackTodayWidget" public static let userDefaultsSiteIdKey = "JetpackHomeWidgetsSiteId" public static let userDefaultsLoggedInKey = "JetpackHomeWidgetsLoggedIn" + + /// The ID of the account's default site, as stored in the shared user defaults by the app. + public static func defaultSiteID(appGroup: String) -> Int? { + UserDefaults(suiteName: appGroup)?.object(forKey: userDefaultsSiteIdKey) as? Int + } public static let todayFilename = "JetpackHomeWidgetTodayData.plist" public static let allTimeFilename = "JetpackHomeWidgetAllTimeData.plist" public static let thisWeekFilename = "JetpackHomeWidgetThisWeekData.plist" @@ -21,7 +26,7 @@ public enum WidgetStatsConfiguration { case lockScreenAllTimePostsBestViews = "JetpackLockScreenWidgetAllTimePostsBestViews" public var countKey: String { - return rawValue + "Properties" + rawValue + "Properties" } } } diff --git a/Modules/Tests/JetpackStatsWidgetsCoreTests/SiteEntityQueryTests.swift b/Modules/Tests/JetpackStatsWidgetsCoreTests/SiteEntityQueryTests.swift new file mode 100644 index 000000000000..0d1cb7feb2d0 --- /dev/null +++ b/Modules/Tests/JetpackStatsWidgetsCoreTests/SiteEntityQueryTests.swift @@ -0,0 +1,132 @@ +import Foundation +import Testing +@testable import JetpackStatsWidgetsCore + +@Suite +struct SiteEntityQueryTests { + + /// Uses the `xctest` app-group prefix so `HomeWidgetCache` writes to a temporary + /// directory instead of a real security application group. + private let appGroup = + "\(HomeWidgetCache.testAppGroupNamePrefix).site-entity-query.\(UUID().uuidString)" + + private var cache: HomeWidgetCache { + HomeWidgetCache(appGroup: appGroup) + } + + private var query: SiteEntityQuery { + SiteEntityQuery(appGroup: appGroup) + } + + private func populateCache(_ sites: [HomeWidgetTodayData]) throws { + try cache.write(items: Dictionary(uniqueKeysWithValues: sites.map { ($0.siteID, $0) })) + } + + private func makeSite(siteID: Int, name: String, url: String = "https://example.com") -> HomeWidgetTodayData { + HomeWidgetTodayData( + siteID: siteID, + siteName: name, + url: url, + timeZone: .current, + date: Date(), + stats: TodayWidgetStats(views: 0, visitors: 0, likes: 0, comments: 0) + ) + } + + // MARK: - Entity mapping + + @Test + func entityFieldsMapFromWidgetData() async throws { + try populateCache([ + makeSite(siteID: 1234567, name: "My Test Site", url: "https://mytestsite.wordpress.com/some/path") + ]) + + let entities = try await query.entities(for: ["1234567"]) + + let entity = try #require(entities.first) + #expect(entity.id == "1234567") + #expect(entity.name == "My Test Site") + #expect(entity.domain == "mytestsite.wordpress.com") + } + + @Test + func entityDomainIsNilForUnparseableURL() async throws { + try populateCache([makeSite(siteID: 1, name: "Broken", url: "")]) + + let entities = try await query.entities(for: ["1"]) + + let entity = try #require(entities.first) + #expect(entity.domain == nil) + } + + // MARK: - entities(for:) + + @Test + func entitiesForIdentifiersResolvesCachedSites() async throws { + try populateCache([ + makeSite(siteID: 1, name: "Alpha"), + makeSite(siteID: 2, name: "Beta"), + makeSite(siteID: 3, name: "Gamma") + ]) + + let entities = try await query.entities(for: ["1", "3"]) + + #expect(entities.map(\.id) == ["1", "3"]) + #expect(entities.map(\.name) == ["Alpha", "Gamma"]) + } + + /// A configured site must never silently resolve to nothing (the widget would + /// fall back to the default site): identifiers missing from the cache are + /// preserved as placeholder entities. + @Test + func entitiesForIdentifiersPreservesUnknownIdentifiers() async throws { + try populateCache([makeSite(siteID: 1, name: "Alpha")]) + + let entities = try await query.entities(for: ["1", "999"]) + + #expect(entities.map(\.id) == ["1", "999"]) + #expect(entities.first?.name == "Alpha") + #expect(entities.last?.name == "999") + } + + @Test + func entitiesForIdentifiersPreservesIdentifiersWhenCacheIsMissing() async throws { + let entities = try await query.entities(for: ["1"]) + + #expect(entities.map(\.id) == ["1"]) + } + + // MARK: - suggestedEntities() + + @Test + func suggestedEntitiesReturnsAllCachedSitesSortedByName() async throws { + try populateCache([ + makeSite(siteID: 3, name: "zebra"), + makeSite(siteID: 1, name: "Apple"), + makeSite(siteID: 2, name: "mango") + ]) + + let entities = try await query.suggestedEntities() + + #expect(entities.map(\.name) == ["Apple", "mango", "zebra"]) + } + + @Test + func suggestedEntitiesBreaksNameTiesByDomain() async throws { + try populateCache([ + makeSite(siteID: 1, name: "Same Name", url: "https://zzz.example.com"), + makeSite(siteID: 2, name: "Same Name", url: "https://aaa.example.com") + ]) + + let entities = try await query.suggestedEntities() + + #expect(entities.map(\.id) == ["2", "1"]) + } + + @Test + func suggestedEntitiesIsEmptyWhenCacheIsMissing() async throws { + let entities = try await query.suggestedEntities() + + #expect(entities.isEmpty) + } +} diff --git a/Tests/KeystoneTests/WordPressTest-Info.plist b/Tests/KeystoneTests/WordPressTest-Info.plist index 169b6f710ecc..6d32c15c20c2 100644 --- a/Tests/KeystoneTests/WordPressTest-Info.plist +++ b/Tests/KeystoneTests/WordPressTest-Info.plist @@ -10,6 +10,8 @@ $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 + CFBundleName + ${PRODUCT_NAME} CFBundlePackageType BNDL CFBundleShortVersionString From d6e04c24481515eeac40a5416382102d994bedad Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 7 Jul 2026 13:39:35 +1200 Subject: [PATCH 3/5] Migrate stats widgets to AppIntentConfiguration and remove the SiriKit intents extension Switches all nine Jetpack stats widgets to AppIntentConfiguration with async AppIntentTimelineProviders using the SelectSiteIntent from JetpackStatsWidgetsCore. The site option list now comes from an in-process entity query, so the JetpackIntents extension, Sites.intentdefinition, and their localizations are removed along with the target's build tooling references, and the GlotPress upload source for the ios-widget. keys moves to an unshipped en.lproj under WordPress/JetpackStatsWidgets. The system migrates existing widget configurations by matching the legacy intent class name and site identifier. fetchStats now reports a failure instead of silently dropping the completion when a refresh is already in progress. --- Modules/Package.swift | 19 - .../XcodeTarget_Intents/Empty.swift | 3 - Scripts/BuildPhases/GenerateCredentials.sh | 2 +- .../Sources/Helpers/WidgetDataReader.swift | 4 +- .../LockScreenSiteListProvider.swift | 75 ++-- .../LockScreenStatsWidget.swift | 4 +- .../Services/StatsWidgetsService.swift | 19 +- .../Sources/SiteListProvider.swift | 68 ++-- .../Sources/StatsWidgets.swift | 3 +- .../Sources/Widgets/HomeWidgetAllTime.swift | 4 +- .../Sources/Widgets/HomeWidgetThisWeek.swift | 4 +- .../Sources/Widgets/HomeWidgetToday.swift | 4 +- .../Base.lproj/Sites.intentdefinition | 193 ---------- WordPress/JetpackIntents/Info.plist | 47 --- WordPress/JetpackIntents/IntentHandler.swift | 35 -- .../JetpackIntents/SitesDataProvider.swift | 86 ----- .../JetpackIntents.entitlements | 10 - .../JetpackIntentsRelease-Alpha.entitlements | 10 - .../Supporting Files/PrivacyInfo.xcprivacy | 25 -- .../WordPressIntentsDebug.entitlements | 8 - .../JetpackIntents/ar.lproj/Sites.strings | 19 - .../JetpackIntents/bg.lproj/Sites.strings | 19 - .../JetpackIntents/cs.lproj/Sites.strings | 19 - .../JetpackIntents/cy.lproj/Sites.strings | 11 - .../JetpackIntents/da.lproj/Sites.strings | 11 - .../JetpackIntents/de.lproj/Sites.strings | 19 - .../JetpackIntents/en-AU.lproj/Sites.strings | 19 - .../JetpackIntents/en-CA.lproj/Sites.strings | 19 - .../JetpackIntents/en-GB.lproj/Sites.strings | 19 - .../JetpackIntents/en.lproj/Sites.strings | 17 - .../JetpackIntents/es.lproj/Sites.strings | 19 - .../JetpackIntents/fr.lproj/Sites.strings | 19 - .../JetpackIntents/he.lproj/Sites.strings | 19 - .../JetpackIntents/hr.lproj/Sites.strings | 11 - .../JetpackIntents/hu.lproj/Sites.strings | 11 - .../JetpackIntents/id.lproj/Sites.strings | 19 - .../JetpackIntents/is.lproj/Sites.strings | 11 - .../JetpackIntents/it.lproj/Sites.strings | 19 - .../JetpackIntents/ja.lproj/Sites.strings | 19 - .../JetpackIntents/ko.lproj/Sites.strings | 19 - .../JetpackIntents/nb.lproj/Sites.strings | 11 - .../JetpackIntents/nl.lproj/Sites.strings | 19 - .../JetpackIntents/pl.lproj/Sites.strings | 19 - .../JetpackIntents/pt-BR.lproj/Sites.strings | 19 - .../JetpackIntents/pt.lproj/Sites.strings | 11 - .../JetpackIntents/ro.lproj/Sites.strings | 19 - .../JetpackIntents/ru.lproj/Sites.strings | 19 - .../JetpackIntents/sk.lproj/Sites.strings | 11 - .../JetpackIntents/sq.lproj/Sites.strings | 19 - .../JetpackIntents/sv.lproj/Sites.strings | 19 - .../JetpackIntents/th.lproj/Sites.strings | 11 - .../JetpackIntents/tr.lproj/Sites.strings | 19 - .../zh-Hans.lproj/Sites.strings | 19 - .../zh-Hant.lproj/Sites.strings | 19 - .../en.lproj/Localizable.strings | 14 + WordPress/WordPress.xcodeproj/project.pbxproj | 363 ------------------ .../xcschemes/JetpackIntents.xcscheme | 71 ---- fastlane/Fastfile | 1 - fastlane/lanes/localization.rb | 2 +- 59 files changed, 101 insertions(+), 1545 deletions(-) delete mode 100644 Modules/Sources/XcodeSupport/XcodeTarget_Intents/Empty.swift delete mode 100644 WordPress/JetpackIntents/Base.lproj/Sites.intentdefinition delete mode 100644 WordPress/JetpackIntents/Info.plist delete mode 100644 WordPress/JetpackIntents/IntentHandler.swift delete mode 100644 WordPress/JetpackIntents/SitesDataProvider.swift delete mode 100644 WordPress/JetpackIntents/Supporting Files/JetpackIntents.entitlements delete mode 100644 WordPress/JetpackIntents/Supporting Files/JetpackIntentsRelease-Alpha.entitlements delete mode 100644 WordPress/JetpackIntents/Supporting Files/PrivacyInfo.xcprivacy delete mode 100644 WordPress/JetpackIntents/WordPressIntentsDebug.entitlements delete mode 100644 WordPress/JetpackIntents/ar.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/bg.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/cs.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/cy.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/da.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/de.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/en-AU.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/en-CA.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/en-GB.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/en.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/es.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/fr.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/he.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/hr.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/hu.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/id.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/is.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/it.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/ja.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/ko.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/nb.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/nl.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/pl.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/pt-BR.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/pt.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/ro.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/ru.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/sk.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/sq.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/sv.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/th.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/tr.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/zh-Hans.lproj/Sites.strings delete mode 100644 WordPress/JetpackIntents/zh-Hant.lproj/Sites.strings create mode 100644 WordPress/JetpackStatsWidgets/en.lproj/Localizable.strings delete mode 100644 WordPress/WordPress.xcodeproj/xcshareddata/xcschemes/JetpackIntents.xcscheme diff --git a/Modules/Package.swift b/Modules/Package.swift index 470a4adaa525..10b6d8b2016b 100644 --- a/Modules/Package.swift +++ b/Modules/Package.swift @@ -409,7 +409,6 @@ enum XcodeSupport { name: "XcodeTarget_NotificationServiceExtension", targets: ["XcodeTarget_NotificationServiceExtension"] ), - .library(name: "XcodeTarget_Intents", targets: ["XcodeTarget_Intents"]), .library(name: "XcodeTarget_StatsWidget", targets: ["XcodeTarget_StatsWidget"]) ] } @@ -575,24 +574,6 @@ enum XcodeSupport { .product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack"), .product(name: "WordPressAPI", package: "wordpress-rs") ] - ), - .xcodeTarget( - "XcodeTarget_Intents", - dependencies: [ - "BuildSettingsKit", - "JetpackStatsWidgetsCore", - // Even though the extensions are all in Swift, we need to include the Objective-C - // version of CocoaLumberjack to avoid linking issues with other dependencies that - // use it. - // - // Example: - // - // Undefined symbols for architecture arm64: - // "_OBJC_CLASS_$_DDLog", referenced from: - // in AppExtensionsService.o - .product(name: "CocoaLumberjack", package: "CocoaLumberjack"), - .product(name: "CocoaLumberjackSwift", package: "CocoaLumberjack") - ] ) ] } diff --git a/Modules/Sources/XcodeSupport/XcodeTarget_Intents/Empty.swift b/Modules/Sources/XcodeSupport/XcodeTarget_Intents/Empty.swift deleted file mode 100644 index 41fadb0ed76f..000000000000 --- a/Modules/Sources/XcodeSupport/XcodeTarget_Intents/Empty.swift +++ /dev/null @@ -1,3 +0,0 @@ -import Foundation - -public struct __Empty {} diff --git a/Scripts/BuildPhases/GenerateCredentials.sh b/Scripts/BuildPhases/GenerateCredentials.sh index 947541ff1707..ebef9d0644cc 100755 --- a/Scripts/BuildPhases/GenerateCredentials.sh +++ b/Scripts/BuildPhases/GenerateCredentials.sh @@ -71,7 +71,7 @@ if [ -f "$WORDPRESS_SECRETS_FILE" ] && [[ " ${WORDPRESS_TARGETS[*]} " == *" $TAR exit 0 fi -JETPACK_TARGETS=("Jetpack" "JetpackStatsWidgets" "JetpackShareExtension" "JetpackDraftActionExtension" "JetpackNotificationServiceExtension" "JetpackIntents") +JETPACK_TARGETS=("Jetpack" "JetpackStatsWidgets" "JetpackShareExtension" "JetpackDraftActionExtension" "JetpackNotificationServiceExtension") # If the Jetpack Secrets are available and if we're building Jetpack use them if [ -f "$JETPACK_SECRETS_FILE" ] && [[ " ${JETPACK_TARGETS[*]} " == *" $TARGET_NAME "* ]]; then echo "Applying Jetpack Secrets" diff --git a/Sources/JetpackStatsWidgets/Sources/Helpers/WidgetDataReader.swift b/Sources/JetpackStatsWidgets/Sources/Helpers/WidgetDataReader.swift index 36d28bfe7549..e04347aec0cb 100644 --- a/Sources/JetpackStatsWidgets/Sources/Helpers/WidgetDataReader.swift +++ b/Sources/JetpackStatsWidgets/Sources/Helpers/WidgetDataReader.swift @@ -15,7 +15,7 @@ final class WidgetDataReader { } /// Returns cached widget data based on the selected site when editing widget and the default site. - /// Configuration.site is nil until IntentHandler is initialized. + /// Configuration.site is nil until the user picks a site in the widget configuration. /// Configuration.site can have old value after logging in with a different account. No way to reset configuration when the user logs out. /// Using defaultSiteID if both of these cases. /// - Parameters: @@ -31,7 +31,7 @@ final class WidgetDataReader { } return cacheReader.widgetData( - forSiteIdentifier: configuration.site?.identifier, + forSiteIdentifier: configuration.site?.id, defaultSiteID: defaultSiteID, userLoggedIn: defaults.bool(forKey: WidgetStatsConfiguration.userDefaultsLoggedInKey) ) diff --git a/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenSiteListProvider.swift b/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenSiteListProvider.swift index 0f677a1ce171..7756ec3b18ac 100644 --- a/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenSiteListProvider.swift +++ b/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenSiteListProvider.swift @@ -1,11 +1,10 @@ -import Foundation -import CocoaLumberjackSwift -import WidgetKit -import SwiftUI import BuildSettingsKit +import CocoaLumberjackSwift +import Foundation import JetpackStatsWidgetsCore +import WidgetKit -struct LockScreenSiteListProvider: IntentTimelineProvider { +struct LockScreenSiteListProvider: AppIntentTimelineProvider { let service: StatsWidgetsService let placeholderContent: T @@ -15,8 +14,7 @@ struct LockScreenSiteListProvider: IntentTimelineProvider { let minElapsedTimeToRefresh = 1 private var defaultSiteID: Int? { - UserDefaults(suiteName: BuildSettings.current.appGroupName)? - .object(forKey: WidgetStatsConfiguration.userDefaultsSiteIdKey) as? Int + WidgetStatsConfiguration.defaultSiteID(appGroup: BuildSettings.current.appGroupName) } private let widgetDataLoader = WidgetDataReader() @@ -25,28 +23,20 @@ struct LockScreenSiteListProvider: IntentTimelineProvider { LockScreenStatsWidgetEntry.siteSelected(placeholderContent, context) } - func getSnapshot( - for configuration: SelectSiteIntent, - in context: Context, - completion: @escaping (LockScreenStatsWidgetEntry) -> Void - ) { + func snapshot(for configuration: SelectSiteIntent, in context: Context) async -> LockScreenStatsWidgetEntry { switch widgetDataLoader.widgetData(for: configuration, defaultSiteID: defaultSiteID) { case .success(let widgetData): - completion(.siteSelected(widgetData, context)) + return .siteSelected(widgetData, context) case .failure: - completion(.siteSelected(placeholderContent, context)) + return .siteSelected(placeholderContent, context) } } - func getTimeline( + func timeline( for configuration: SelectSiteIntent, - in context: Context, - completion: @escaping (Timeline>) -> Void - ) { - switch widgetDataLoader.widgetData( - for: configuration, - defaultSiteID: defaultSiteID - ) { + in context: Context + ) async -> Timeline> { + switch widgetDataLoader.widgetData(for: configuration, defaultSiteID: defaultSiteID) { case .success(let widgetData): let date = Date() let nextRefreshDate = Calendar.current.date(byAdding: .minute, value: refreshInterval, to: date) ?? date @@ -54,42 +44,37 @@ struct LockScreenSiteListProvider: IntentTimelineProvider { Calendar.current.dateComponents([.minute], from: widgetData.date, to: date).minute ?? 0 ) - let privateCompletion = { (timelineEntry: LockScreenStatsWidgetEntry) in - let timeline = Timeline(entries: [timelineEntry], policy: .after(nextRefreshDate)) - completion(timeline) - } // if cached data are "too old", refresh them from the backend, otherwise keep them guard elapsedTime > minElapsedTimeToRefresh else { - privateCompletion(.siteSelected(widgetData, context)) - return + return Timeline(entries: [.siteSelected(widgetData, context)], policy: .after(nextRefreshDate)) } - service.fetchStats(for: widgetData) { result in - switch result { - case .failure(let error): - DDLogError( - "LockScreen StatsWidgets: failed to fetch remote stats. Returned error: \(error.localizedDescription)" - ) - privateCompletion(.siteSelected(widgetData, context)) - case .success(let newWidgetData): - if let newWidgetData = newWidgetData as? T { - privateCompletion(.siteSelected(newWidgetData, context)) - } else { - privateCompletion(.siteSelected(widgetData, context)) - } + let entry: LockScreenStatsWidgetEntry + do { + let newWidgetData = try await service.fetchStats(for: widgetData) + if let newWidgetData = newWidgetData as? T { + entry = .siteSelected(newWidgetData, context) + } else { + entry = .siteSelected(widgetData, context) } + } catch { + DDLogError( + "LockScreen StatsWidgets: failed to fetch remote stats. Returned error: \(error.localizedDescription)" + ) + entry = .siteSelected(widgetData, context) } + return Timeline(entries: [entry], policy: .after(nextRefreshDate)) case .failure(let error): switch error { case .noData: - completion(Timeline(entries: [.noData], policy: .never)) + return Timeline(entries: [.noData], policy: .never) case .noSite: - completion(Timeline(entries: [.noSite], policy: .never)) + return Timeline(entries: [.noSite], policy: .never) case .loggedOut: - completion(Timeline(entries: [.loggedOut], policy: .never)) + return Timeline(entries: [.loggedOut], policy: .never) case .jetpackFeatureDisabled: DDLogError("LockScreen StatsWidgets: lock screen widget should have Jetpack feature disable error") - completion(Timeline(entries: [.noData], policy: .never)) + return Timeline(entries: [.noData], policy: .never) } } } diff --git a/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenStatsWidget.swift b/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenStatsWidget.swift index 660dd3f257d9..9d648b5c38df 100644 --- a/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenStatsWidget.swift +++ b/Sources/JetpackStatsWidgets/Sources/LockScreenWidgets/LockScreenStatsWidget.swift @@ -17,7 +17,7 @@ struct LockScreenStatsWidget: Widget { } var body: some WidgetConfiguration { - IntentConfiguration( + AppIntentConfiguration( kind: config.kind.rawValue, intent: SelectSiteIntent.self, provider: LockScreenSiteListProvider( @@ -33,6 +33,6 @@ struct LockScreenStatsWidget: Widget { .configurationDisplayName(config.displayName) .description(config.description) .supportedFamilies(config.supportFamilies) - .iOS17ContentMarginsDisabled()/// Temporarily disable additional iOS17 margins for widgets + .iOS17ContentMarginsDisabled() // Temporarily disable additional iOS17 margins for widgets } } diff --git a/Sources/JetpackStatsWidgets/Sources/Services/StatsWidgetsService.swift b/Sources/JetpackStatsWidgets/Sources/Services/StatsWidgetsService.swift index 20a1ad83265b..59d11509dd8f 100644 --- a/Sources/JetpackStatsWidgets/Sources/Services/StatsWidgetsService.swift +++ b/Sources/JetpackStatsWidgets/Sources/Services/StatsWidgetsService.swift @@ -28,12 +28,26 @@ class StatsWidgetsService { private var state: State = .ready - func fetchStats( + enum FetchError: Error { + case refreshAlreadyInProgress + case unsupportedWidgetData + } + + func fetchStats(for widgetData: HomeWidgetData) async throws -> ResultType { + try await withCheckedThrowingContinuation { continuation in + fetchStats(for: widgetData) { result in + continuation.resume(with: result) + } + } + } + + private func fetchStats( for widgetData: HomeWidgetData, completion: @escaping (Result) -> Void ) { guard !state.isLoading else { + completion(.failure(FetchError.refreshAlreadyInProgress)) return } state = .loading @@ -46,6 +60,9 @@ class StatsWidgetsService { fetchAllTimeStats(widgetData: widgetData, completion: completion) } else if let widgetData = widgetData as? HomeWidgetThisWeekData { fetchThisWeekStats(widgetData: widgetData, completion: completion) + } else { + state = .error + completion(.failure(FetchError.unsupportedWidgetData)) } } diff --git a/Sources/JetpackStatsWidgets/Sources/SiteListProvider.swift b/Sources/JetpackStatsWidgets/Sources/SiteListProvider.swift index 1daddf00cf05..3fbc9848e2bb 100644 --- a/Sources/JetpackStatsWidgets/Sources/SiteListProvider.swift +++ b/Sources/JetpackStatsWidgets/Sources/SiteListProvider.swift @@ -1,11 +1,10 @@ -import Foundation -import CocoaLumberjackSwift -import WidgetKit import BuildSettingsKit -import SwiftUI +import CocoaLumberjackSwift +import Foundation import JetpackStatsWidgetsCore +import WidgetKit -struct SiteListProvider: IntentTimelineProvider { +struct SiteListProvider: AppIntentTimelineProvider { let service: StatsWidgetsService let placeholderContent: T @@ -17,8 +16,7 @@ struct SiteListProvider: IntentTimelineProvider { let minElapsedTimeToRefresh = 1 private var defaultSiteID: Int? { - UserDefaults(suiteName: BuildSettings.current.appGroupName)? - .object(forKey: WidgetStatsConfiguration.userDefaultsSiteIdKey) as? Int + WidgetStatsConfiguration.defaultSiteID(appGroup: BuildSettings.current.appGroupName) } private let widgetDataLoader = WidgetDataReader() @@ -27,28 +25,17 @@ struct SiteListProvider: IntentTimelineProvider { StatsWidgetEntry.siteSelected(placeholderContent, context) } - func getSnapshot( - for configuration: SelectSiteIntent, - in context: Context, - completion: @escaping (StatsWidgetEntry) -> Void - ) { + func snapshot(for configuration: SelectSiteIntent, in context: Context) async -> StatsWidgetEntry { switch widgetDataLoader.widgetData(for: configuration, defaultSiteID: defaultSiteID) { case .success(let widgetData): - completion(.siteSelected(widgetData, context)) + return .siteSelected(widgetData, context) case .failure: - completion(.siteSelected(placeholderContent, context)) + return .siteSelected(placeholderContent, context) } } - func getTimeline( - for configuration: SelectSiteIntent, - in context: Context, - completion: @escaping (Timeline) -> Void - ) { - switch widgetDataLoader.widgetData( - for: configuration, - defaultSiteID: defaultSiteID - ) { + func timeline(for configuration: SelectSiteIntent, in context: Context) async -> Timeline { + switch widgetDataLoader.widgetData(for: configuration, defaultSiteID: defaultSiteID) { case .success(let widgetData): let date = Date() let nextRefreshDate = Calendar.current.date(byAdding: .minute, value: refreshInterval, to: date) ?? date @@ -56,37 +43,32 @@ struct SiteListProvider: IntentTimelineProvider { Calendar.current.dateComponents([.minute], from: widgetData.date, to: date).minute ?? 0 ) - let privateCompletion = { (timelineEntry: StatsWidgetEntry) in - let timeline = Timeline(entries: [timelineEntry], policy: .after(nextRefreshDate)) - completion(timeline) - } // if cached data are "too old", refresh them from the backend, otherwise keep them guard elapsedTime > minElapsedTimeToRefresh else { - privateCompletion(.siteSelected(widgetData, context)) - return + return Timeline(entries: [.siteSelected(widgetData, context)], policy: .after(nextRefreshDate)) } - service.fetchStats(for: widgetData) { result in - switch result { - case .failure(let error): - DDLogError( - "StatsWidgets: failed to fetch remote stats. Returned error: \(error.localizedDescription)" - ) - privateCompletion(.siteSelected(widgetData, context)) - case .success(let newWidgetData): - privateCompletion(.siteSelected(newWidgetData, context)) - } + let entry: StatsWidgetEntry + do { + let newWidgetData = try await service.fetchStats(for: widgetData) + entry = .siteSelected(newWidgetData, context) + } catch { + DDLogError( + "StatsWidgets: failed to fetch remote stats. Returned error: \(error.localizedDescription)" + ) + entry = .siteSelected(widgetData, context) } + return Timeline(entries: [entry], policy: .after(nextRefreshDate)) case .failure(let error): switch error { case .noData: - completion(Timeline(entries: [.noData(widgetKind)], policy: .never)) + return Timeline(entries: [.noData(widgetKind)], policy: .never) case .noSite: - completion(Timeline(entries: [.noSite(widgetKind)], policy: .never)) + return Timeline(entries: [.noSite(widgetKind)], policy: .never) case .loggedOut: - completion(Timeline(entries: [.loggedOut(widgetKind)], policy: .never)) + return Timeline(entries: [.loggedOut(widgetKind)], policy: .never) case .jetpackFeatureDisabled: - completion(Timeline(entries: [.disabled(widgetKind)], policy: .never)) + return Timeline(entries: [.disabled(widgetKind)], policy: .never) } } } diff --git a/Sources/JetpackStatsWidgets/Sources/StatsWidgets.swift b/Sources/JetpackStatsWidgets/Sources/StatsWidgets.swift index 103bac1afc33..ef039a4a1666 100644 --- a/Sources/JetpackStatsWidgets/Sources/StatsWidgets.swift +++ b/Sources/JetpackStatsWidgets/Sources/StatsWidgets.swift @@ -1,6 +1,7 @@ +import BuildSettingsKit +import JetpackStatsWidgetsCore import SwiftUI import WidgetKit -import BuildSettingsKit @main struct JetpackStatsWidgets: WidgetBundle { diff --git a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetAllTime.swift b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetAllTime.swift index 13f3e59a93bf..903b25d13af4 100644 --- a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetAllTime.swift +++ b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetAllTime.swift @@ -21,7 +21,7 @@ struct HomeWidgetAllTime: Widget { ) var body: some WidgetConfiguration { - IntentConfiguration( + AppIntentConfiguration( kind: WidgetStatsConfiguration.Kind.homeAllTime.rawValue, intent: SelectSiteIntent.self, provider: SiteListProvider( @@ -35,6 +35,6 @@ struct HomeWidgetAllTime: Widget { .configurationDisplayName(LocalizableStrings.allTimeWidgetTitle) .description(LocalizableStrings.allTimePreviewDescription) .supportedFamilies([.systemSmall, .systemMedium]) - .iOS17ContentMarginsDisabled()/// Temporarily disable additional iOS17 margins for widgets + .iOS17ContentMarginsDisabled() // Temporarily disable additional iOS17 margins for widgets } } diff --git a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetThisWeek.swift b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetThisWeek.swift index 0aa7d4d5411f..ab98afd48cc7 100644 --- a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetThisWeek.swift +++ b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetThisWeek.swift @@ -54,7 +54,7 @@ struct HomeWidgetThisWeek: Widget { ) var body: some WidgetConfiguration { - IntentConfiguration( + AppIntentConfiguration( kind: WidgetStatsConfiguration.Kind.homeThisWeek.rawValue, intent: SelectSiteIntent.self, provider: SiteListProvider( @@ -68,6 +68,6 @@ struct HomeWidgetThisWeek: Widget { .configurationDisplayName(LocalizableStrings.thisWeekWidgetTitle) .description(LocalizableStrings.thisWeekPreviewDescription) .supportedFamilies([.systemMedium, .systemLarge]) - .iOS17ContentMarginsDisabled()/// Temporarily disable additional iOS17 margins for widgets + .iOS17ContentMarginsDisabled() // Temporarily disable additional iOS17 margins for widgets } } diff --git a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetToday.swift b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetToday.swift index eff6ebbd18cb..494de2de5120 100644 --- a/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetToday.swift +++ b/Sources/JetpackStatsWidgets/Sources/Widgets/HomeWidgetToday.swift @@ -22,7 +22,7 @@ struct HomeWidgetToday: Widget { ) var body: some WidgetConfiguration { - IntentConfiguration( + AppIntentConfiguration( kind: WidgetStatsConfiguration.Kind.homeToday.rawValue, intent: SelectSiteIntent.self, provider: SiteListProvider( @@ -36,6 +36,6 @@ struct HomeWidgetToday: Widget { .configurationDisplayName(LocalizableStrings.todayWidgetTitle) .description(LocalizableStrings.todayPreviewDescription) .supportedFamilies([.systemSmall, .systemMedium]) - .iOS17ContentMarginsDisabled()/// Temporarily disable additional iOS17 margins for widgets for StandBy + .iOS17ContentMarginsDisabled() // Temporarily disable additional iOS17 margins for widgets for StandBy } } diff --git a/WordPress/JetpackIntents/Base.lproj/Sites.intentdefinition b/WordPress/JetpackIntents/Base.lproj/Sites.intentdefinition deleted file mode 100644 index 0ca59c04507b..000000000000 --- a/WordPress/JetpackIntents/Base.lproj/Sites.intentdefinition +++ /dev/null @@ -1,193 +0,0 @@ - - - - - INEnums - - INIntentDefinitionModelVersion - 1.2 - INIntentDefinitionNamespace - 88xZPY - INIntentDefinitionSystemVersion - 20C69 - INIntentDefinitionToolsBuildVersion - 12C33 - INIntentDefinitionToolsVersion - 12.3 - INIntents - - - INIntentCategory - information - INIntentDescription - Select Site Intent - INIntentDescriptionID - tVvJ9c - INIntentEligibleForWidgets - - INIntentIneligibleForSuggestions - - INIntentLastParameterTag - 2 - INIntentName - SelectSite - INIntentParameters - - - INIntentParameterConfigurable - - INIntentParameterCustomDisambiguation - - INIntentParameterDisplayName - Site - INIntentParameterDisplayNameID - ILcGmf - INIntentParameterDisplayPriority - 1 - INIntentParameterName - site - INIntentParameterObjectType - Site - INIntentParameterObjectTypeNamespace - 88xZPY - INIntentParameterPromptDialogs - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Configuration - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogType - Primary - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogFormatString - There are ${count} options matching ‘${site}’. - INIntentParameterPromptDialogFormatStringID - BOl9KQ - INIntentParameterPromptDialogType - DisambiguationIntroduction - - - INIntentParameterPromptDialogCustom - - INIntentParameterPromptDialogFormatString - Just to confirm, you wanted ‘${site}’? - INIntentParameterPromptDialogFormatStringID - s4dJhx - INIntentParameterPromptDialogType - Confirmation - - - INIntentParameterSupportsDynamicEnumeration - - INIntentParameterSupportsResolution - - INIntentParameterTag - 2 - INIntentParameterType - Object - - - INIntentResponse - - INIntentResponseCodes - - - INIntentResponseCodeName - success - INIntentResponseCodeSuccess - - - - INIntentResponseCodeName - failure - - - INIntentResponseLastParameterTag - 2 - - INIntentTitle - Select Site - INIntentTitleID - gpCwrM - INIntentType - Custom - INIntentVerb - View - - - INTypes - - - INTypeDisplayName - Site - INTypeDisplayNameID - cyajMn - INTypeLastPropertyTag - 100 - INTypeName - Site - INTypeProperties - - - INTypePropertyDefault - - INTypePropertyDisplayPriority - 1 - INTypePropertyName - identifier - INTypePropertyTag - 1 - INTypePropertyType - String - - - INTypePropertyDefault - - INTypePropertyDisplayPriority - 2 - INTypePropertyName - displayString - INTypePropertyTag - 2 - INTypePropertyType - String - - - INTypePropertyDefault - - INTypePropertyDisplayPriority - 3 - INTypePropertyName - pronunciationHint - INTypePropertyTag - 3 - INTypePropertyType - String - - - INTypePropertyDefault - - INTypePropertyDisplayPriority - 4 - INTypePropertyName - alternativeSpeakableMatches - INTypePropertySupportsMultipleValues - - INTypePropertyTag - 4 - INTypePropertyType - SpeakableString - - - - - - diff --git a/WordPress/JetpackIntents/Info.plist b/WordPress/JetpackIntents/Info.plist deleted file mode 100644 index 6037556bfebc..000000000000 --- a/WordPress/JetpackIntents/Info.plist +++ /dev/null @@ -1,47 +0,0 @@ - - - - - CFBundleDevelopmentRegion - $(DEVELOPMENT_LANGUAGE) - CFBundleDisplayName - JetpackIntents - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - $(PRODUCT_BUNDLE_PACKAGE_TYPE) - CFBundleShortVersionString - ${VERSION_SHORT} - CFBundleVersion - ${VERSION_LONG} - NSAppTransportSecurity - - NSAllowsArbitraryLoads - - - NSExtension - - NSExtensionAttributes - - IntentsRestrictedWhileLocked - - IntentsRestrictedWhileProtectedDataUnavailable - - IntentsSupported - - SelectSiteIntent - - - NSExtensionPointIdentifier - com.apple.intents-service - NSExtensionPrincipalClass - $(PRODUCT_MODULE_NAME).IntentHandler - - - diff --git a/WordPress/JetpackIntents/IntentHandler.swift b/WordPress/JetpackIntents/IntentHandler.swift deleted file mode 100644 index c081e0219ab8..000000000000 --- a/WordPress/JetpackIntents/IntentHandler.swift +++ /dev/null @@ -1,35 +0,0 @@ -import Intents -import BuildSettingsKit - -class IntentHandler: INExtension, SelectSiteIntentHandling { - - let sitesDataProvider: SitesDataProvider - - override init() { - BuildSettings.configure(secrets: ApiCredentials.toSecrets()) - sitesDataProvider = SitesDataProvider() - super.init() - } - - // MARK: - INIntentHandlerProviding - - override func handler(for intent: INIntent) -> Any { - return self - } - - // MARK: - SelectSiteIntentHandling - - func defaultSite(for intent: SelectSiteIntent) -> Site? { - return sitesDataProvider.defaultSite - } - - func resolveSite(for intent: SelectSiteIntent, with completion: @escaping (SiteResolutionResult) -> Void) { - /// - TODO: I have to test if this method can be called by interacting with Siri, and define an implementation. This is probably called whenever you ask the selected site, since the value can theoretically be requested through Siri. Check out Widgets.intentdefinition. - } - - func provideSiteOptionsCollection(for intent: SelectSiteIntent, with completion: @escaping (INObjectCollection?, Error?) -> Void) { - let sitesCollection = INObjectCollection(items: sitesDataProvider.sites) - - completion(sitesCollection, nil) - } -} diff --git a/WordPress/JetpackIntents/SitesDataProvider.swift b/WordPress/JetpackIntents/SitesDataProvider.swift deleted file mode 100644 index ede87c7b80dd..000000000000 --- a/WordPress/JetpackIntents/SitesDataProvider.swift +++ /dev/null @@ -1,86 +0,0 @@ -import Intents -import BuildSettingsKit -import JetpackStatsWidgetsCore - -class SitesDataProvider { - private(set) var sites = [Site]() - - init() { - initializeSites() - } - - // MARK: - Init Support - - private func initializeSites() { - guard let data = HomeWidgetTodayData.read() else { - sites = [] - return - } - - sites = data.map { (key: Int, data: HomeWidgetTodayData) -> Site in - - // Note: the image for the site was being set through: - // - // icon(from: data) - // - // Unfortunately, this had to be turned off for now since images aren't working very well in the - // customizer as reported here: https://github.com/wordpress-mobile/WordPress-iOS/pull/15397#pullrequestreview-539474644 - - let siteDomain: String? - - if let urlComponents = URLComponents(string: data.url), - let host = urlComponents.host { - - siteDomain = host - } else { - siteDomain = nil - } - - return Site( - identifier: String(key), - display: data.siteName, - subtitle: siteDomain, - image: nil) - }.sorted(by: { firstSite, secondSite -> Bool in - let firstTitle = firstSite.displayString.lowercased() - let secondTitle = secondSite.displayString.lowercased() - - guard firstTitle != secondTitle else { - let firstSubtitle = firstSite.subtitleString?.lowercased() ?? "" - let secondSubtitle = secondSite.subtitleString?.lowercased() ?? "" - - return firstSubtitle <= secondSubtitle - } - - return firstTitle < secondTitle - }) - } - - // MARK: - Default Site - - private var defaultSiteID: Int? { - UserDefaults(suiteName: BuildSettings.current.appGroupName)?.object(forKey: WidgetStatsConfiguration.userDefaultsSiteIdKey) as? Int - } - - var defaultSite: Site? { - guard let defaultSiteID = self.defaultSiteID else { - return nil - } - - return sites.first { site in - return site.identifier == String(defaultSiteID) - } - } -} - -private extension HomeWidgetData { - static func read(from cache: HomeWidgetCache? = nil) -> [Int: Self]? { - - let cache = cache ?? HomeWidgetCache(fileName: Self.filename, appGroup: BuildSettings.current.appGroupName) - do { - return try cache.read() - } catch { - return nil - } - } -} diff --git a/WordPress/JetpackIntents/Supporting Files/JetpackIntents.entitlements b/WordPress/JetpackIntents/Supporting Files/JetpackIntents.entitlements deleted file mode 100644 index 82da242fbdbe..000000000000 --- a/WordPress/JetpackIntents/Supporting Files/JetpackIntents.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.application-groups - - group.org.wordpress - - - diff --git a/WordPress/JetpackIntents/Supporting Files/JetpackIntentsRelease-Alpha.entitlements b/WordPress/JetpackIntents/Supporting Files/JetpackIntentsRelease-Alpha.entitlements deleted file mode 100644 index 008824899c59..000000000000 --- a/WordPress/JetpackIntents/Supporting Files/JetpackIntentsRelease-Alpha.entitlements +++ /dev/null @@ -1,10 +0,0 @@ - - - - - com.apple.security.application-groups - - group.org.wordpress.alpha - - - diff --git a/WordPress/JetpackIntents/Supporting Files/PrivacyInfo.xcprivacy b/WordPress/JetpackIntents/Supporting Files/PrivacyInfo.xcprivacy deleted file mode 100644 index 325a4f28eaf8..000000000000 --- a/WordPress/JetpackIntents/Supporting Files/PrivacyInfo.xcprivacy +++ /dev/null @@ -1,25 +0,0 @@ - - - - - NSPrivacyAccessedAPITypes - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryFileTimestamp - NSPrivacyAccessedAPITypeReasons - - C617.1 - - - - NSPrivacyAccessedAPIType - NSPrivacyAccessedAPICategoryUserDefaults - NSPrivacyAccessedAPITypeReasons - - 1C8F.1 - - - - - diff --git a/WordPress/JetpackIntents/WordPressIntentsDebug.entitlements b/WordPress/JetpackIntents/WordPressIntentsDebug.entitlements deleted file mode 100644 index 2eb7e333a6f6..000000000000 --- a/WordPress/JetpackIntents/WordPressIntentsDebug.entitlements +++ /dev/null @@ -1,8 +0,0 @@ - - - - - com.apple.security.application-groups - - - diff --git a/WordPress/JetpackIntents/ar.lproj/Sites.strings b/WordPress/JetpackIntents/ar.lproj/Sites.strings deleted file mode 100644 index 266a57d89a73..000000000000 --- a/WordPress/JetpackIntents/ar.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - توجد ${count} من الخيارات تطابق "${site}". - ILcGmf - الموقع - cyajMn - الموقع - gpCwrM - تحديد موقع - s4dJhx - للتأكيد فقط، هل أردت "${site}"؟ - tVvJ9c - تحديد هدف الموقع - - diff --git a/WordPress/JetpackIntents/bg.lproj/Sites.strings b/WordPress/JetpackIntents/bg.lproj/Sites.strings deleted file mode 100644 index 72c17b6ce028..000000000000 --- a/WordPress/JetpackIntents/bg.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Има ${count}, съвпадащи с ‘${site}’. - ILcGmf - Сайт - cyajMn - Сайт - gpCwrM - Select Site - s4dJhx - Само да потвърдим, искате ‘${site}’? - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/cs.lproj/Sites.strings b/WordPress/JetpackIntents/cs.lproj/Sites.strings deleted file mode 100644 index 515c8556577d..000000000000 --- a/WordPress/JetpackIntents/cs.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - „${site}“ odpovídá ${count} možností. - ILcGmf - Web - cyajMn - Web - gpCwrM - Vybrat web - s4dJhx - Jen pro potvrzení, chtěli jste „${site}“? - tVvJ9c - Vyberte záměr webu - - diff --git a/WordPress/JetpackIntents/cy.lproj/Sites.strings b/WordPress/JetpackIntents/cy.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/cy.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/da.lproj/Sites.strings b/WordPress/JetpackIntents/da.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/da.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/de.lproj/Sites.strings b/WordPress/JetpackIntents/de.lproj/Sites.strings deleted file mode 100644 index ad2a5eb4b27d..000000000000 --- a/WordPress/JetpackIntents/de.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Es gibt ${count} Optionen, die zu „${site}“ passen. - ILcGmf - Website - cyajMn - Website - gpCwrM - Website auswählen - s4dJhx - Nur um sicherzugehen, du willst „${site}“? - tVvJ9c - Website-Intent auswählen - - diff --git a/WordPress/JetpackIntents/en-AU.lproj/Sites.strings b/WordPress/JetpackIntents/en-AU.lproj/Sites.strings deleted file mode 100644 index 318bb8365ff2..000000000000 --- a/WordPress/JetpackIntents/en-AU.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - There are ${count} options matching ‘${site}’. - ILcGmf - Site - cyajMn - Site - gpCwrM - Select Site - s4dJhx - Just to confirm, you wanted ‘${site}’? - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/en-CA.lproj/Sites.strings b/WordPress/JetpackIntents/en-CA.lproj/Sites.strings deleted file mode 100644 index 318bb8365ff2..000000000000 --- a/WordPress/JetpackIntents/en-CA.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - There are ${count} options matching ‘${site}’. - ILcGmf - Site - cyajMn - Site - gpCwrM - Select Site - s4dJhx - Just to confirm, you wanted ‘${site}’? - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/en-GB.lproj/Sites.strings b/WordPress/JetpackIntents/en-GB.lproj/Sites.strings deleted file mode 100644 index 318bb8365ff2..000000000000 --- a/WordPress/JetpackIntents/en-GB.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - There are ${count} options matching ‘${site}’. - ILcGmf - Site - cyajMn - Site - gpCwrM - Select Site - s4dJhx - Just to confirm, you wanted ‘${site}’? - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/en.lproj/Sites.strings b/WordPress/JetpackIntents/en.lproj/Sites.strings deleted file mode 100644 index 0de34e087277..000000000000 --- a/WordPress/JetpackIntents/en.lproj/Sites.strings +++ /dev/null @@ -1,17 +0,0 @@ -/* This text is used when the user is configuring the iOS widget and selecting which WordPress site they want the widget to be for */ -"BOl9KQ" = "There are ${count} options matching ‘${site}’."; - -/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ -"ILcGmf" = "Site"; - -/* This text is used when the user is configuring the iOS widget, as the title for the modal when selecting the site to configure it for */ -"cyajMn" = "Site"; - -/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ -"gpCwrM" = "Select Site"; - -/* This text is required by Apple to be part of the translations but is not shown to the users. You can use the English version verbatim without translation for this entry. */ -"tVvJ9c" = "Select Site Intent"; - -/* This text is used when configuring the iOS widget and confirming the WordPress site the user wants the widget to be for */ -"s4dJhx" = "Just to confirm, you wanted ‘${site}’?"; diff --git a/WordPress/JetpackIntents/es.lproj/Sites.strings b/WordPress/JetpackIntents/es.lproj/Sites.strings deleted file mode 100644 index 98e22adf36f0..000000000000 --- a/WordPress/JetpackIntents/es.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - ${count} opciones coinciden con «${site}». - ILcGmf - Sitio - cyajMn - Sitio - gpCwrM - Seleccionar sitio - s4dJhx - Solo por confirmar, ¿querías ‘${site}’? - tVvJ9c - Seleccionar intención del sitio - - diff --git a/WordPress/JetpackIntents/fr.lproj/Sites.strings b/WordPress/JetpackIntents/fr.lproj/Sites.strings deleted file mode 100644 index 0fb8392700d8..000000000000 --- a/WordPress/JetpackIntents/fr.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Il existe ${count} options correspondant à « ${site} ». - ILcGmf - Site - cyajMn - Site - gpCwrM - Sélectionnez le site - s4dJhx - Vous cherchiez bien « ${site} » ? - tVvJ9c - Sélectionner l’intention du site - - diff --git a/WordPress/JetpackIntents/he.lproj/Sites.strings b/WordPress/JetpackIntents/he.lproj/Sites.strings deleted file mode 100644 index df24c01136d8..000000000000 --- a/WordPress/JetpackIntents/he.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - יש ${count} אפשרויות שתואמות לנתון ‘${site}’. - ILcGmf - אתר - cyajMn - אתר - gpCwrM - יש לבחור אתר - s4dJhx - אנחנו רוצים לוודא, האם התכוונת לרשום ‘${site}’? - tVvJ9c - יש לבחור את כוונת האתר - - diff --git a/WordPress/JetpackIntents/hr.lproj/Sites.strings b/WordPress/JetpackIntents/hr.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/hr.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/hu.lproj/Sites.strings b/WordPress/JetpackIntents/hu.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/hu.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/id.lproj/Sites.strings b/WordPress/JetpackIntents/id.lproj/Sites.strings deleted file mode 100644 index 4e0aec915c57..000000000000 --- a/WordPress/JetpackIntents/id.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Ada pilihan ${count} yang cocok dengan ‘${site}’. - ILcGmf - Situs - cyajMn - Situs - gpCwrM - Pilih Situs - s4dJhx - Hanya untuk mengonfirmasi, Anda menginginkan '${site}'? - tVvJ9c - Pilih Kegunaan Situs - - diff --git a/WordPress/JetpackIntents/is.lproj/Sites.strings b/WordPress/JetpackIntents/is.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/is.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/it.lproj/Sites.strings b/WordPress/JetpackIntents/it.lproj/Sites.strings deleted file mode 100644 index 598306914c33..000000000000 --- a/WordPress/JetpackIntents/it.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Esistono le opzioni ${count} che corrispondono a ‘${site}’. - ILcGmf - Sito - cyajMn - Sito - gpCwrM - Seleziona sito - s4dJhx - Giusto per conferma, hai voluto ‘${site}’? - tVvJ9c - Seleziona lo scopo del sito - - diff --git a/WordPress/JetpackIntents/ja.lproj/Sites.strings b/WordPress/JetpackIntents/ja.lproj/Sites.strings deleted file mode 100644 index 6cd452485e78..000000000000 --- a/WordPress/JetpackIntents/ja.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - 「${site}」に一致するオプションが${count}件あります - ILcGmf - サイト - cyajMn - サイト - gpCwrM - サイトを選択 - s4dJhx - 「${site}」でよろしいですか? - tVvJ9c - サイトの目的を選択 - - diff --git a/WordPress/JetpackIntents/ko.lproj/Sites.strings b/WordPress/JetpackIntents/ko.lproj/Sites.strings deleted file mode 100644 index 6f408d82cd0f..000000000000 --- a/WordPress/JetpackIntents/ko.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - ‘${site}’과(와) 일치하는 옵션이 ${count}개 있습니다. - ILcGmf - 사이트 - cyajMn - 사이트 - gpCwrM - 사이트 선택 - s4dJhx - ‘${site}’을(를) 원하시나요? - tVvJ9c - 사이트 의도 선택 - - diff --git a/WordPress/JetpackIntents/nb.lproj/Sites.strings b/WordPress/JetpackIntents/nb.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/nb.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/nl.lproj/Sites.strings b/WordPress/JetpackIntents/nl.lproj/Sites.strings deleted file mode 100644 index cb07cc2ed12c..000000000000 --- a/WordPress/JetpackIntents/nl.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Er zijn ${count} opties die overeenkomen met '${site}'. - ILcGmf - Site - cyajMn - Site - gpCwrM - Selecteer site - s4dJhx - Even ter bevestiging, je wilt '${site}'? - tVvJ9c - Selecteer site doel - - diff --git a/WordPress/JetpackIntents/pl.lproj/Sites.strings b/WordPress/JetpackIntents/pl.lproj/Sites.strings deleted file mode 100644 index 7883c35b3bc9..000000000000 --- a/WordPress/JetpackIntents/pl.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Istnieją opcje pasujące do „${site}” (liczba: ${count}). - ILcGmf - Witryna - cyajMn - Witryna - gpCwrM - Select Site - s4dJhx - Dla potwierdzenia, czy chodziło o „${site}”? - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/pt-BR.lproj/Sites.strings b/WordPress/JetpackIntents/pt-BR.lproj/Sites.strings deleted file mode 100644 index 81432d83583f..000000000000 --- a/WordPress/JetpackIntents/pt-BR.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Existem ${count} opções correspondentes a ‘${site}’. - ILcGmf - Site - cyajMn - Site - gpCwrM - Selecionar site - s4dJhx - Só para confirmar, você queria ‘${site}’? - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/pt.lproj/Sites.strings b/WordPress/JetpackIntents/pt.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/pt.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/ro.lproj/Sites.strings b/WordPress/JetpackIntents/ro.lproj/Sites.strings deleted file mode 100644 index e8f58fb3570e..000000000000 --- a/WordPress/JetpackIntents/ro.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Există ${count} opțiuni care se potrivesc cu „${site}”. - ILcGmf - Site - cyajMn - Site - gpCwrM - Selectează site-ul - s4dJhx - Trebuie să confirmi, ai vrut „${site}”? - tVvJ9c - Selectează scopul site-ului - - diff --git a/WordPress/JetpackIntents/ru.lproj/Sites.strings b/WordPress/JetpackIntents/ru.lproj/Sites.strings deleted file mode 100644 index 22a16e3eb8cc..000000000000 --- a/WordPress/JetpackIntents/ru.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Есть опции (${count}), соответствующие "${site}". - ILcGmf - Сайт - cyajMn - Сайт - gpCwrM - Выбрать сайт - s4dJhx - Вы действительно хотели "${site}"? - tVvJ9c - Выберите назначение сайта - - diff --git a/WordPress/JetpackIntents/sk.lproj/Sites.strings b/WordPress/JetpackIntents/sk.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/sk.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/sq.lproj/Sites.strings b/WordPress/JetpackIntents/sq.lproj/Sites.strings deleted file mode 100644 index cd112a88020f..000000000000 --- a/WordPress/JetpackIntents/sq.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Ka ${count} mundësi me përputhje me ‘${site}’. - ILcGmf - Sajt - cyajMn - Sajt - gpCwrM - Përzgjidhni Sajt - s4dJhx - Sa për ripohim, donit ‘${site}’? - tVvJ9c - Përzgjidhni Synim Sajti - - diff --git a/WordPress/JetpackIntents/sv.lproj/Sites.strings b/WordPress/JetpackIntents/sv.lproj/Sites.strings deleted file mode 100644 index 05a7f74af6a6..000000000000 --- a/WordPress/JetpackIntents/sv.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - Det finns ${count} alternativ som matchar "${site}". - ILcGmf - Webbplats - cyajMn - Webbplats - gpCwrM - Välj webbplats - s4dJhx - Bara för att bekräfta, du önskade "${site}"? - tVvJ9c - Välj syfte med webbplats - - diff --git a/WordPress/JetpackIntents/th.lproj/Sites.strings b/WordPress/JetpackIntents/th.lproj/Sites.strings deleted file mode 100644 index edd8ef15d7be..000000000000 --- a/WordPress/JetpackIntents/th.lproj/Sites.strings +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - gpCwrM - Select Site - tVvJ9c - Select Site Intent - - diff --git a/WordPress/JetpackIntents/tr.lproj/Sites.strings b/WordPress/JetpackIntents/tr.lproj/Sites.strings deleted file mode 100644 index 5b93c818e2b0..000000000000 --- a/WordPress/JetpackIntents/tr.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - ‘${site}’ ile eşleşen '${count}' seçenekleri var. - ILcGmf - Site - cyajMn - Site - gpCwrM - Site seçin - s4dJhx - ‘${site}’ istediğinize emin misiniz? - tVvJ9c - Sitenin amacını seçin - - diff --git a/WordPress/JetpackIntents/zh-Hans.lproj/Sites.strings b/WordPress/JetpackIntents/zh-Hans.lproj/Sites.strings deleted file mode 100644 index 6126863d700b..000000000000 --- a/WordPress/JetpackIntents/zh-Hans.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - 有 ${count} 个选项与“${site}”匹配。 - ILcGmf - 站点 - cyajMn - 站点 - gpCwrM - 选择站点 - s4dJhx - 再确认一下,您是想要“${site}”吗? - tVvJ9c - 选择“站点意图” - - diff --git a/WordPress/JetpackIntents/zh-Hant.lproj/Sites.strings b/WordPress/JetpackIntents/zh-Hant.lproj/Sites.strings deleted file mode 100644 index 1a3d9a2a3ea7..000000000000 --- a/WordPress/JetpackIntents/zh-Hant.lproj/Sites.strings +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - BOl9KQ - 有 ${count} 個選項和「${site}」相符。 - ILcGmf - 網站 - cyajMn - 網站 - gpCwrM - 選取網站 - s4dJhx - 確認一下,你想要的是「${site}」嗎? - tVvJ9c - 選擇網站用途 - - diff --git a/WordPress/JetpackStatsWidgets/en.lproj/Localizable.strings b/WordPress/JetpackStatsWidgets/en.lproj/Localizable.strings new file mode 100644 index 000000000000..cc870542d162 --- /dev/null +++ b/WordPress/JetpackStatsWidgets/en.lproj/Localizable.strings @@ -0,0 +1,14 @@ +/* Source strings for the stats widget configuration UI, uploaded to GlotPress under the + "ios-widget." prefix (see MANUALLY_MAINTAINED_STRINGS_FILES in fastlane/lanes/localization.rb). + The keys are the identifiers Xcode generated for the legacy Sites.intentdefinition; they are + kept so the existing GlotPress translations keep matching after the migration to App Intents. + + This file is not shipped in any bundle. At runtime the prefixed keys are resolved from the + app's Localizable.strings (iOS 26) or from the static copies in + Sources/JetpackStatsWidgets/Resources/.lproj/Localizable.strings (iOS 17). */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"gpCwrM" = "Select Site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ILcGmf" = "Site"; diff --git a/WordPress/WordPress.xcodeproj/project.pbxproj b/WordPress/WordPress.xcodeproj/project.pbxproj index ab53a122a86a..02d96a9fa6b1 100644 --- a/WordPress/WordPress.xcodeproj/project.pbxproj +++ b/WordPress/WordPress.xcodeproj/project.pbxproj @@ -21,15 +21,9 @@ /* End PBXAggregateTarget section */ /* Begin PBXBuildFile section */ - 0107E0D728F97D5000DE87DB /* Sites.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 3F46AB0225BF5D6300CE2E98 /* Sites.intentdefinition */; }; 0107E0DE28F97D5000DE87DB /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F526C4F2538CF2A0069706C /* SwiftUI.framework */; }; 0107E0DF28F97D5000DE87DB /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F526C4D2538CF2A0069706C /* WidgetKit.framework */; }; 0107E0EE28F97E6900DE87DB /* JetpackStatsWidgets.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0107E0EA28F97D5000DE87DB /* JetpackStatsWidgets.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - 0107E13B28FE9DB200DE87DB /* Sites.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 3F46AB0225BF5D6300CE2E98 /* Sites.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; }; - 0107E13E28FE9DB200DE87DB /* SitesDataProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1482CDF2575BDA4007E4DD6 /* SitesDataProvider.swift */; }; - 0107E14928FE9DB200DE87DB /* IntentHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1F163C025658B4D003DC13B /* IntentHandler.swift */; }; - 0107E14D28FE9DB200DE87DB /* AppImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 433840C622C2BA5B00CB13F8 /* AppImages.xcassets */; }; - 0107E15928FEB10E00DE87DB /* JetpackIntents.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = 0107E15428FE9DB200DE87DB /* JetpackIntents.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 099D768327D14B8E00F77EDE /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 099D768127D14B8E00F77EDE /* InfoPlist.strings */; }; 0C235BD22C3862D400D0E163 /* XcodeTarget_WordPressTests in Frameworks */ = {isa = PBXBuildFile; productRef = 0C235BD12C3862D400D0E163 /* XcodeTarget_WordPressTests */; }; 0C28A01C2DAD7CFD00F81F20 /* XcodeTarget_App in Frameworks */ = {isa = PBXBuildFile; productRef = 0C28A01B2DAD7CFD00F81F20 /* XcodeTarget_App */; }; @@ -56,7 +50,6 @@ 0C6AC6202C364A7500BF7600 /* XcodeTarget_DraftActionExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 0C6AC61F2C364A7500BF7600 /* XcodeTarget_DraftActionExtension */; }; 0C6AC6222C364A7B00BF7600 /* XcodeTarget_NotificationServiceExtension in Frameworks */ = {isa = PBXBuildFile; productRef = 0C6AC6212C364A7B00BF7600 /* XcodeTarget_NotificationServiceExtension */; }; 0C6AC6242C364A8000BF7600 /* XcodeTarget_StatsWidget in Frameworks */ = {isa = PBXBuildFile; productRef = 0C6AC6232C364A8000BF7600 /* XcodeTarget_StatsWidget */; }; - 0C6AC6262C364A8500BF7600 /* XcodeTarget_Intents in Frameworks */ = {isa = PBXBuildFile; productRef = 0C6AC6252C364A8500BF7600 /* XcodeTarget_Intents */; }; 0CCA99512DAD76AD0048F0A9 /* AppImages.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 433840C622C2BA5B00CB13F8 /* AppImages.xcassets */; }; 0CCA99592DAD76BA0048F0A9 /* Noticons.ttf in Resources */ = {isa = PBXBuildFile; fileRef = F5A34D0C25DF2F7700C9654B /* Noticons.ttf */; }; 0CCA995A2DAD76C20048F0A9 /* n.caf in Resources */ = {isa = PBXBuildFile; fileRef = 5D69DBC3165428CA00A2D1F7 /* n.caf */; }; @@ -79,7 +72,6 @@ 374CB16215B93C0800DD0EBC /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */; }; 3F1A64F62DA7A4B300786B92 /* Secrets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24351253264DCA08009BB2B6 /* Secrets.swift */; }; 3F1AFCC22DA3AAEA00786B92 /* WebKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F1AFCC12DA3AAE900786B92 /* WebKit.framework */; }; - 3F46AAFE25BF5D6300CE2E98 /* Sites.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 3F46AB0225BF5D6300CE2E98 /* Sites.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; }; 3F608F7F2D2D1A9E008ACD86 /* Gutenberg.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F60D3902D2C4BA3008ACD86 /* Gutenberg.xcframework */; }; 3F608F802D2D1A9E008ACD86 /* Gutenberg.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3F60D3902D2C4BA3008ACD86 /* Gutenberg.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 3F608F812D2D1A9E008ACD86 /* hermes.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F60D3922D2C4BA3008ACD86 /* hermes.xcframework */; }; @@ -107,7 +99,6 @@ 4A690C162BA791B200A8E0C5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4A690C142BA790BC00A8E0C5 /* PrivacyInfo.xcprivacy */; }; 4A690C182BA794C800A8E0C5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4A690C172BA794C300A8E0C5 /* PrivacyInfo.xcprivacy */; }; 4A690C192BA794CD00A8E0C5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4A690C172BA794C300A8E0C5 /* PrivacyInfo.xcprivacy */; }; - 4A690C1B2BA7964100A8E0C5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4A690C1A2BA7958F00A8E0C5 /* PrivacyInfo.xcprivacy */; }; 4A690C1E2BA796CB00A8E0C5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4A690C1D2BA796C500A8E0C5 /* PrivacyInfo.xcprivacy */; }; 4A690C1F2BA796CD00A8E0C5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4A690C1D2BA796C500A8E0C5 /* PrivacyInfo.xcprivacy */; }; 4A690C212BA7975500A8E0C5 /* PrivacyInfo.xcprivacy in Resources */ = {isa = PBXBuildFile; fileRef = 4A690C202BA7974E00A8E0C5 /* PrivacyInfo.xcprivacy */; }; @@ -117,7 +108,6 @@ 4ABCAB2A2DE52E80005A6B84 /* Secrets-JetpackDraftActionExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ABCAB272DE52E6B005A6B84 /* Secrets-JetpackDraftActionExtension.swift */; }; 4ABCAB2B2DE52E86005A6B84 /* Secrets-JetpackShareExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ABCAB282DE52E6B005A6B84 /* Secrets-JetpackShareExtension.swift */; }; 4ABCAB2E2DE53092005A6B84 /* Secrets-JetpackNotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ABCAB2D2DE53092005A6B84 /* Secrets-JetpackNotificationServiceExtension.swift */; }; - 4ABCAB332DE53168005A6B84 /* Secrets-JetpackIntents.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ABCAB322DE53168005A6B84 /* Secrets-JetpackIntents.swift */; }; 4ABCAB3A2DE533A5005A6B84 /* Secrets-WordPressNotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4ABCAB392DE533A5005A6B84 /* Secrets-WordPressNotificationServiceExtension.swift */; }; 4AC9545A2DE51FE40095EA51 /* Secrets-JetpackStatsWidgets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC954592DE51FE40095EA51 /* Secrets-JetpackStatsWidgets.swift */; }; 4AC9F8182DE528E40095EA51 /* Secrets-WordPressShareExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4AC9F8172DE528E40095EA51 /* Secrets-WordPressShareExtension.swift */; }; @@ -183,7 +173,6 @@ FABB203D2602FC2C00C8785C /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = E1D91454134A853D0089019C /* Localizable.strings */; }; FABB20762602FC2C00C8785C /* WordPressShare.js in Resources */ = {isa = PBXBuildFile; fileRef = E1AFA8C21E8E34230004A323 /* WordPressShare.js */; }; FABB20862602FC2C00C8785C /* n.caf in Resources */ = {isa = PBXBuildFile; fileRef = 5D69DBC3165428CA00A2D1F7 /* n.caf */; }; - FABB23A32602FC2C00C8785C /* Sites.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = 3F46AB0225BF5D6300CE2E98 /* Sites.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; }; FABB26202602FC2C00C8785C /* iAd.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E21C760202BBC8D00837CF5 /* iAd.framework */; }; FABB26212602FC2C00C8785C /* StoreKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8298F3911EEF3BA7008EB7F0 /* StoreKit.framework */; }; FABB26222602FC2C00C8785C /* CoreSpotlight.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 93F2E5431E9E5A570050D489 /* CoreSpotlight.framework */; }; @@ -225,13 +214,6 @@ remoteGlobalIDString = 0107E0B128F97D5000DE87DB; remoteInfo = JetpackStatsWidgets; }; - 0107E15628FEA03800DE87DB /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; - proxyType = 1; - remoteGlobalIDString = 0107E13828FE9DB200DE87DB; - remoteInfo = JetpackIntents; - }; 0C3313C42E0439A9000C3760 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */; @@ -319,16 +301,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - 0C2A6F142C36092B004B8022 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; 0C43FF922C3602BE0084B698 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -487,7 +459,6 @@ 8096212528E5411400940A5D /* JetpackShareExtension.appex in Embed Foundation Extensions */, 0107E0EE28F97E6900DE87DB /* JetpackStatsWidgets.appex in Embed Foundation Extensions */, 80F6D05D28EE88FC00953C1A /* JetpackNotificationServiceExtension.appex in Embed Foundation Extensions */, - 0107E15928FEB10E00DE87DB /* JetpackIntents.appex in Embed Foundation Extensions */, 8096218E28E55F8600940A5D /* JetpackDraftActionExtension.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; @@ -497,10 +468,6 @@ /* Begin PBXFileReference section */ 0107E0EA28F97D5000DE87DB /* JetpackStatsWidgets.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = JetpackStatsWidgets.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 0107E15428FE9DB200DE87DB /* JetpackIntents.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = JetpackIntents.appex; sourceTree = BUILT_PRODUCTS_DIR; }; - 0107E1812900043200DE87DB /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 0167F4AD2AAA0250005B9E42 /* JetpackIntents.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = JetpackIntents.entitlements; sourceTree = ""; }; - 0167F4AE2AAA0250005B9E42 /* JetpackIntentsRelease-Alpha.entitlements */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.entitlements; path = "JetpackIntentsRelease-Alpha.entitlements"; sourceTree = ""; }; 099D768227D14B8E00F77EDE /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 099D768427D14BAE00F77EDE /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = sq.lproj/InfoPlist.strings; sourceTree = ""; }; 099D768527D14BB300F77EDE /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -557,40 +524,6 @@ 24351059264DC1E2009BB2B6 /* Jetpack.release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Jetpack.release.xcconfig; sourceTree = ""; }; 24351253264DCA08009BB2B6 /* Secrets.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Secrets.swift; path = ../Secrets/Secrets.swift; sourceTree = BUILT_PRODUCTS_DIR; }; 2439B1DB264ECBDF00239130 /* Jetpack.alpha.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Jetpack.alpha.xcconfig; sourceTree = ""; }; - 24AD66BE25FC25FD0056102C /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Sites.strings; sourceTree = ""; }; - 24AD66C025FC25FE0056102C /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = sq.lproj/Sites.strings; sourceTree = ""; }; - 24AD66C225FC26000056102C /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Sites.strings; sourceTree = ""; }; - 24AD66C425FC26010056102C /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = bg.lproj/Sites.strings; sourceTree = ""; }; - 24AD66C625FC26020056102C /* zh-Hans */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hans"; path = "zh-Hans.lproj/Sites.strings"; sourceTree = ""; }; - 24AD66C825FC26030056102C /* zh-Hant */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-Hant"; path = "zh-Hant.lproj/Sites.strings"; sourceTree = ""; }; - 24AD66CA25FC26040056102C /* hr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hr; path = hr.lproj/Sites.strings; sourceTree = ""; }; - 24AD66CC25FC26050056102C /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Sites.strings; sourceTree = ""; }; - 24AD66CE25FC26060056102C /* da */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = da; path = da.lproj/Sites.strings; sourceTree = ""; }; - 24AD66F025FC260B0056102C /* nl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nl; path = nl.lproj/Sites.strings; sourceTree = ""; }; - 24AD66F225FC260F0056102C /* en-AU */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-AU"; path = "en-AU.lproj/Sites.strings"; sourceTree = ""; }; - 24AD66F425FC26100056102C /* en-CA */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-CA"; path = "en-CA.lproj/Sites.strings"; sourceTree = ""; }; - 24AD670625FC26150056102C /* en-GB */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "en-GB"; path = "en-GB.lproj/Sites.strings"; sourceTree = ""; }; - 24AD670825FC26170056102C /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Sites.strings; sourceTree = ""; }; - 24AD670A25FC26170056102C /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Sites.strings; sourceTree = ""; }; - 24AD670C25FC26180056102C /* he */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = he; path = he.lproj/Sites.strings; sourceTree = ""; }; - 24AD670E25FC261A0056102C /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Sites.strings; sourceTree = ""; }; - 24AD671025FC261B0056102C /* is */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = is; path = is.lproj/Sites.strings; sourceTree = ""; }; - 24AD671225FC261C0056102C /* id */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = id; path = id.lproj/Sites.strings; sourceTree = ""; }; - 24AD671425FC261D0056102C /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Sites.strings; sourceTree = ""; }; - 24AD671625FC261E0056102C /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Sites.strings; sourceTree = ""; }; - 24AD671825FC26200056102C /* ko */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ko; path = ko.lproj/Sites.strings; sourceTree = ""; }; - 24AD672A25FC26220056102C /* nb */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = nb; path = nb.lproj/Sites.strings; sourceTree = ""; }; - 24AD672C25FC26240056102C /* pl */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pl; path = pl.lproj/Sites.strings; sourceTree = ""; }; - 24AD672E25FC26250056102C /* pt */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = pt; path = pt.lproj/Sites.strings; sourceTree = ""; }; - 24AD673025FC26260056102C /* pt-BR */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "pt-BR"; path = "pt-BR.lproj/Sites.strings"; sourceTree = ""; }; - 24AD673225FC26270056102C /* ro */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ro; path = ro.lproj/Sites.strings; sourceTree = ""; }; - 24AD674425FC26280056102C /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Sites.strings; sourceTree = ""; }; - 24AD674625FC26290056102C /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Sites.strings; sourceTree = ""; }; - 24AD674825FC262B0056102C /* es */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = es; path = es.lproj/Sites.strings; sourceTree = ""; }; - 24AD674A25FC262C0056102C /* sv */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sv; path = sv.lproj/Sites.strings; sourceTree = ""; }; - 24AD674C25FC262D0056102C /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/Sites.strings; sourceTree = ""; }; - 24AD674E25FC262E0056102C /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/Sites.strings; sourceTree = ""; }; - 24AD675025FC262F0056102C /* cy */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cy; path = cy.lproj/Sites.strings; sourceTree = ""; }; 24AE9E66264B34E500AC7F15 /* Secrets-example.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Secrets-example.swift"; sourceTree = ""; }; 24B54FAE2624F8430041B18E /* JetpackRelease-Alpha.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = "JetpackRelease-Alpha.entitlements"; sourceTree = ""; }; 24B54FAF2624F84C0041B18E /* JetpackRelease.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = JetpackRelease.entitlements; sourceTree = ""; }; @@ -600,7 +533,6 @@ 296890770FE971DC00770264 /* Security.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = Security.framework; path = System/Library/Frameworks/Security.framework; sourceTree = SDKROOT; }; 374CB16115B93C0800DD0EBC /* AudioToolbox.framework */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; }; 3F1AFCC12DA3AAE900786B92 /* WebKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WebKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX15.4.sdk/System/iOSSupport/System/Library/PrivateFrameworks/WebKit.framework; sourceTree = DEVELOPER_DIR; }; - 3F46AB0125BF5D6300CE2E98 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Sites.intentdefinition; sourceTree = ""; }; 3F526C4D2538CF2A0069706C /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = System/Library/Frameworks/WidgetKit.framework; sourceTree = SDKROOT; }; 3F526C4F2538CF2A0069706C /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = System/Library/Frameworks/SwiftUI.framework; sourceTree = SDKROOT; }; 3F60D38F2D2C4BA3008ACD86 /* React.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = React.xcframework; path = Frameworks/React.xcframework; sourceTree = ""; }; @@ -615,7 +547,6 @@ 433840C622C2BA5B00CB13F8 /* AppImages.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = AppImages.xcassets; path = Resources/AppImages.xcassets; sourceTree = ""; }; 4A690C142BA790BC00A8E0C5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 4A690C172BA794C300A8E0C5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; - 4A690C1A2BA7958F00A8E0C5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 4A690C1D2BA796C500A8E0C5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 4A690C202BA7974E00A8E0C5 /* PrivacyInfo.xcprivacy */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PrivacyInfo.xcprivacy; sourceTree = ""; }; 4A8280FD2E5FE9B60037E180 /* WordPressKitTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WordPressKitTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -623,7 +554,6 @@ 4ABCAB272DE52E6B005A6B84 /* Secrets-JetpackDraftActionExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Secrets-JetpackDraftActionExtension.swift"; path = "../Secrets/Secrets-JetpackDraftActionExtension.swift"; sourceTree = BUILT_PRODUCTS_DIR; }; 4ABCAB282DE52E6B005A6B84 /* Secrets-JetpackShareExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Secrets-JetpackShareExtension.swift"; path = "../Secrets/Secrets-JetpackShareExtension.swift"; sourceTree = BUILT_PRODUCTS_DIR; }; 4ABCAB2D2DE53092005A6B84 /* Secrets-JetpackNotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Secrets-JetpackNotificationServiceExtension.swift"; path = "../Secrets/Secrets-JetpackNotificationServiceExtension.swift"; sourceTree = BUILT_PRODUCTS_DIR; }; - 4ABCAB322DE53168005A6B84 /* Secrets-JetpackIntents.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Secrets-JetpackIntents.swift"; path = "../Secrets/Secrets-JetpackIntents.swift"; sourceTree = BUILT_PRODUCTS_DIR; }; 4ABCAB392DE533A5005A6B84 /* Secrets-WordPressNotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Secrets-WordPressNotificationServiceExtension.swift"; path = "../Secrets/Secrets-WordPressNotificationServiceExtension.swift"; sourceTree = BUILT_PRODUCTS_DIR; }; 4AC954592DE51FE40095EA51 /* Secrets-JetpackStatsWidgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Secrets-JetpackStatsWidgets.swift"; path = "../Secrets/Secrets-JetpackStatsWidgets.swift"; sourceTree = BUILT_PRODUCTS_DIR; }; 4AC9F8172DE528E40095EA51 /* Secrets-WordPressShareExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "Secrets-WordPressShareExtension.swift"; path = "../Secrets/Secrets-WordPressShareExtension.swift"; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -746,12 +676,10 @@ E1E977BC17B0FA9A00AFB867 /* th */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = th; path = th.lproj/Localizable.strings; sourceTree = ""; }; F111B88B2658102700057942 /* Combine.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Combine.framework; path = System/Library/Frameworks/Combine.framework; sourceTree = SDKROOT; }; F13E7FDD2566B0AB007D420A /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; - F1482CDF2575BDA4007E4DD6 /* SitesDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SitesDataProvider.swift; sourceTree = ""; }; F14B5F70208E648200439554 /* WordPress.debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = WordPress.debug.xcconfig; sourceTree = ""; }; F14B5F71208E648200439554 /* WordPress.release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = WordPress.release.xcconfig; sourceTree = ""; }; F14B5F73208E648300439554 /* WordPress.alpha.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = WordPress.alpha.xcconfig; sourceTree = ""; }; F14B5F74208E64F900439554 /* Version.public.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Version.public.xcconfig; sourceTree = ""; }; - F1F163C025658B4D003DC13B /* IntentHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IntentHandler.swift; sourceTree = ""; }; F1F163C825658B4D003DC13B /* IntentsUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IntentsUI.framework; path = System/Library/Frameworks/IntentsUI.framework; sourceTree = SDKROOT; }; F5A34D0C25DF2F7700C9654B /* Noticons.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; path = Noticons.ttf; sourceTree = ""; }; FABB26522602FC2C00C8785C /* Jetpack.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Jetpack.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -902,13 +830,6 @@ ); target = 80F6D01F28EE866A00953C1A /* JetpackNotificationServiceExtension */; }; - 4ABCAB352DE531B6005A6B84 /* Exceptions for "Classes" folder in "JetpackIntents" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - "System/ApiCredentials+BuildSecrets.swift", - ); - target = 0107E13828FE9DB200DE87DB /* JetpackIntents */; - }; 4ABCAB382DE5333C005A6B84 /* Exceptions for "Classes" folder in "WordPressNotificationServiceExtension" target */ = { isa = PBXFileSystemSynchronizedBuildFileExceptionSet; membershipExceptions = ( @@ -1028,7 +949,6 @@ 4ABC59802DE52D23005A6B84 /* Exceptions for "Classes" folder in "JetpackDraftActionExtension" target */, 4ABCAB302DE5309F005A6B84 /* Exceptions for "Classes" folder in "JetpackNotificationServiceExtension" target */, 4AC9CF442DE5228C0095EA51 /* Exceptions for "Classes" folder in "JetpackStatsWidgets" target */, - 4ABCAB352DE531B6005A6B84 /* Exceptions for "Classes" folder in "JetpackIntents" target */, 3F1A64F82DA7ABC300786B92 /* Exceptions for "Classes" folder in "Reader" target */, 0C5C46F42D98343300F2CD55 /* Exceptions for "Classes" folder in "Keystone" target */, ); @@ -1056,14 +976,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 0107E14A28FE9DB200DE87DB /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 0C6AC6262C364A8500BF7600 /* XcodeTarget_Intents in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 0C3313B42E0439A8000C3760 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -1260,16 +1172,6 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ - 0167F4AC2AAA0250005B9E42 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 0167F4AD2AAA0250005B9E42 /* JetpackIntents.entitlements */, - 0167F4AE2AAA0250005B9E42 /* JetpackIntentsRelease-Alpha.entitlements */, - 4A690C1A2BA7958F00A8E0C5 /* PrivacyInfo.xcprivacy */, - ); - path = "Supporting Files"; - sourceTree = ""; - }; 0C5A19CB2D9B07E700C25301 /* Tests */ = { isa = PBXGroup; children = ( @@ -1308,7 +1210,6 @@ 8096218528E55C9400940A5D /* JetpackDraftActionExtension.appex */, 80F6D05428EE866A00953C1A /* JetpackNotificationServiceExtension.appex */, 0107E0EA28F97D5000DE87DB /* JetpackStatsWidgets.appex */, - 0107E15428FE9DB200DE87DB /* JetpackIntents.appex */, 0CED01702D95B897003015CF /* WordPress.framework */, 0C5A3F8C2D9B1E3700C25301 /* Reader.app */, 0C3313B72E0439A8000C3760 /* Miniature.app */, @@ -1326,7 +1227,6 @@ 4ABCAB282DE52E6B005A6B84 /* Secrets-JetpackShareExtension.swift */, 4ABCAB272DE52E6B005A6B84 /* Secrets-JetpackDraftActionExtension.swift */, 4ABCAB2D2DE53092005A6B84 /* Secrets-JetpackNotificationServiceExtension.swift */, - 4ABCAB322DE53168005A6B84 /* Secrets-JetpackIntents.swift */, 4AC9F8172DE528E40095EA51 /* Secrets-WordPressShareExtension.swift */, 4ABC59732DE52A7D005A6B84 /* Secrets-WordPressDraftActionExtension.swift */, 4ABCAB392DE533A5005A6B84 /* Secrets-WordPressNotificationServiceExtension.swift */, @@ -1348,7 +1248,6 @@ 29B97317FDCFA39411CA2CEA /* Resources */, FABB1F8E2602FC0100C8785C /* Jetpack */, 8096218728E55CB800940A5D /* JetpackDraftActionExtension */, - F1F163BF25658B4D003DC13B /* JetpackIntents */, 80F6D05628EE869900953C1A /* JetpackNotificationServiceExtension */, 8096212828E5535E00940A5D /* JetpackShareExtension */, 74576673202B558C00F42E40 /* WordPressDraftActionExtension */, @@ -1614,18 +1513,6 @@ path = ../config; sourceTree = ""; }; - F1F163BF25658B4D003DC13B /* JetpackIntents */ = { - isa = PBXGroup; - children = ( - 0107E1812900043200DE87DB /* Info.plist */, - F1F163C025658B4D003DC13B /* IntentHandler.swift */, - F1482CDF2575BDA4007E4DD6 /* SitesDataProvider.swift */, - 3F46AB0225BF5D6300CE2E98 /* Sites.intentdefinition */, - 0167F4AC2AAA0250005B9E42 /* Supporting Files */, - ); - path = JetpackIntents; - sourceTree = ""; - }; F5A34D0525DF2F7700C9654B /* Fonts */ = { isa = PBXGroup; children = ( @@ -1683,28 +1570,6 @@ productReference = 0107E0EA28F97D5000DE87DB /* JetpackStatsWidgets.appex */; productType = "com.apple.product-type.app-extension"; }; - 0107E13828FE9DB200DE87DB /* JetpackIntents */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0107E14F28FE9DB200DE87DB /* Build configuration list for PBXNativeTarget "JetpackIntents" */; - buildPhases = ( - 4ABCAB312DE530F1005A6B84 /* Generate Credentials */, - 0107E13A28FE9DB200DE87DB /* Sources */, - 0107E14A28FE9DB200DE87DB /* Frameworks */, - 0107E14C28FE9DB200DE87DB /* Resources */, - 0C2A6F142C36092B004B8022 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - ); - name = JetpackIntents; - packageProductDependencies = ( - 0C6AC6252C364A8500BF7600 /* XcodeTarget_Intents */, - ); - productName = JetpackIntents; - productReference = 0107E15428FE9DB200DE87DB /* JetpackIntents.appex */; - productType = "com.apple.product-type.app-extension"; - }; 0C3313B62E0439A8000C3760 /* Miniature */ = { isa = PBXNativeTarget; buildConfigurationList = 0C3313DE2E0439AA000C3760 /* Build configuration list for PBXNativeTarget "Miniature" */; @@ -2053,7 +1918,6 @@ ); dependencies = ( 3FCFFB002994AB25002840C9 /* PBXTargetDependency */, - 0107E15728FEA03800DE87DB /* PBXTargetDependency */, 0107E0ED28F97E6100DE87DB /* PBXTargetDependency */, 8096212728E5411400940A5D /* PBXTargetDependency */, 8096219028E55F8600940A5D /* PBXTargetDependency */, @@ -2230,7 +2094,6 @@ 8096213028E55C9400940A5D /* JetpackDraftActionExtension */, 80F6D01F28EE866A00953C1A /* JetpackNotificationServiceExtension */, 0107E0B128F97D5000DE87DB /* JetpackStatsWidgets */, - 0107E13828FE9DB200DE87DB /* JetpackIntents */, 0C5A3F8B2D9B1E3700C25301 /* Reader */, 0CED016F2D95B897003015CF /* Keystone */, 0C3313B62E0439A8000C3760 /* Miniature */, @@ -2248,15 +2111,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 0107E14C28FE9DB200DE87DB /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4A690C1B2BA7964100A8E0C5 /* PrivacyInfo.xcprivacy in Resources */, - 0107E14D28FE9DB200DE87DB /* AppImages.xcassets in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; 0C3313B52E0439A8000C3760 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -2638,26 +2492,6 @@ shellPath = /bin/sh; shellScript = "$SRCROOT/../Scripts/BuildPhases/GenerateCredentials.sh\n"; }; - 4ABCAB312DE530F1005A6B84 /* Generate Credentials */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "$(SRCROOT)/../Scripts/BuildPhases/GenerateCredentials.xcfilelist", - ); - inputPaths = ( - ); - name = "Generate Credentials"; - outputFileListPaths = ( - ); - outputPaths = ( - "$(BUILD_DIR)/Secrets/Secrets-JetpackIntents.swift", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "$SRCROOT/../Scripts/BuildPhases/GenerateCredentials.sh\n"; - }; 4ABCAB362DE532E7005A6B84 /* Generate Credentials */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -2761,18 +2595,6 @@ buildActionMask = 2147483647; files = ( 4AC9545A2DE51FE40095EA51 /* Secrets-JetpackStatsWidgets.swift in Sources */, - 0107E0D728F97D5000DE87DB /* Sites.intentdefinition in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0107E13A28FE9DB200DE87DB /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 4ABCAB332DE53168005A6B84 /* Secrets-JetpackIntents.swift in Sources */, - 0107E13B28FE9DB200DE87DB /* Sites.intentdefinition in Sources */, - 0107E13E28FE9DB200DE87DB /* SitesDataProvider.swift in Sources */, - 0107E14928FE9DB200DE87DB /* IntentHandler.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2809,7 +2631,6 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 3F46AAFE25BF5D6300CE2E98 /* Sites.intentdefinition in Sources */, 24351254264DCA08009BB2B6 /* Secrets.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -2895,7 +2716,6 @@ buildActionMask = 2147483647; files = ( 24351255264DCA08009BB2B6 /* Secrets.swift in Sources */, - FABB23A32602FC2C00C8785C /* Sites.intentdefinition in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2907,11 +2727,6 @@ target = 0107E0B128F97D5000DE87DB /* JetpackStatsWidgets */; targetProxy = 0107E0EC28F97E6100DE87DB /* PBXContainerItemProxy */; }; - 0107E15728FEA03800DE87DB /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 0107E13828FE9DB200DE87DB /* JetpackIntents */; - targetProxy = 0107E15628FEA03800DE87DB /* PBXContainerItemProxy */; - }; 0C3313C52E0439A9000C3760 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 0C3313B62E0439A8000C3760 /* Miniature */; @@ -3016,48 +2831,6 @@ name = InfoPlist.strings; sourceTree = ""; }; - 3F46AB0225BF5D6300CE2E98 /* Sites.intentdefinition */ = { - isa = PBXVariantGroup; - children = ( - 3F46AB0125BF5D6300CE2E98 /* Base */, - 24AD66BE25FC25FD0056102C /* en */, - 24AD66C025FC25FE0056102C /* sq */, - 24AD66C225FC26000056102C /* ar */, - 24AD66C425FC26010056102C /* bg */, - 24AD66C625FC26020056102C /* zh-Hans */, - 24AD66C825FC26030056102C /* zh-Hant */, - 24AD66CA25FC26040056102C /* hr */, - 24AD66CC25FC26050056102C /* cs */, - 24AD66CE25FC26060056102C /* da */, - 24AD66F025FC260B0056102C /* nl */, - 24AD66F225FC260F0056102C /* en-AU */, - 24AD66F425FC26100056102C /* en-CA */, - 24AD670625FC26150056102C /* en-GB */, - 24AD670825FC26170056102C /* fr */, - 24AD670A25FC26170056102C /* de */, - 24AD670C25FC26180056102C /* he */, - 24AD670E25FC261A0056102C /* hu */, - 24AD671025FC261B0056102C /* is */, - 24AD671225FC261C0056102C /* id */, - 24AD671425FC261D0056102C /* it */, - 24AD671625FC261E0056102C /* ja */, - 24AD671825FC26200056102C /* ko */, - 24AD672A25FC26220056102C /* nb */, - 24AD672C25FC26240056102C /* pl */, - 24AD672E25FC26250056102C /* pt */, - 24AD673025FC26260056102C /* pt-BR */, - 24AD673225FC26270056102C /* ro */, - 24AD674425FC26280056102C /* ru */, - 24AD674625FC26290056102C /* sk */, - 24AD674825FC262B0056102C /* es */, - 24AD674A25FC262C0056102C /* sv */, - 24AD674C25FC262D0056102C /* th */, - 24AD674E25FC262E0056102C /* tr */, - 24AD675025FC262F0056102C /* cy */, - ); - name = Sites.intentdefinition; - sourceTree = ""; - }; 8058730D28F7B70B00340C11 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( @@ -3280,128 +3053,6 @@ }; name = "Release-Alpha"; }; - 0107E15028FE9DB200DE87DB /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 24350E7C264DB76E009BB2B6 /* Jetpack.debug.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = "JetpackIntents/Supporting Files/JetpackIntents.entitlements"; - CODE_SIGN_STYLE = Manual; - COPY_PHASE_STRIP = NO; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = PZYM8XX95Q; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_DYNAMIC_NO_PIC = NO; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = JetpackIntents/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.automattic.jetpack.JetpackIntents; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "Jetpack iOS Development Intents Extension"; - SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 0107E15128FE9DB200DE87DB /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 24351059264DC1E2009BB2B6 /* Jetpack.release.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = "JetpackIntents/Supporting Files/JetpackIntents.entitlements"; - CODE_SIGN_IDENTITY = "Apple Distribution: Automattic, Inc. (PZYM8XX95Q)"; - CODE_SIGN_STYLE = Manual; - COPY_PHASE_STRIP = NO; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = JetpackIntents/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.automattic.jetpack.JetpackIntents; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match AppStore com.automattic.jetpack.JetpackIntents"; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 0107E15328FE9DB200DE87DB /* Release-Alpha */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 2439B1DB264ECBDF00239130 /* Jetpack.alpha.xcconfig */; - buildSettings = { - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; - CLANG_CXX_LIBRARY = "libc++"; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CODE_SIGN_ENTITLEMENTS = "JetpackIntents/Supporting Files/JetpackIntentsRelease-Alpha.entitlements"; - CODE_SIGN_IDENTITY = "iPhone Distribution: Automattic, Inc."; - CODE_SIGN_STYLE = Manual; - COPY_PHASE_STRIP = NO; - ENABLE_NS_ASSERTIONS = NO; - GCC_C_LANGUAGE_STANDARD = gnu11; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - INFOPLIST_FILE = JetpackIntents/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = com.jetpack.alpha.JetpackIntents; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = "match InHouse com.jetpack.alpha.JetpackIntents"; - SKIP_INSTALL = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = "Release-Alpha"; - }; 0C3313D52E0439AA000C3760 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 0C5A651A2D9B21CE00C25301 /* Reader.debug.xcconfig */; @@ -5553,16 +5204,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 0107E14F28FE9DB200DE87DB /* Build configuration list for PBXNativeTarget "JetpackIntents" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0107E15028FE9DB200DE87DB /* Debug */, - 0107E15128FE9DB200DE87DB /* Release */, - 0107E15328FE9DB200DE87DB /* Release-Alpha */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 0C3313DE2E0439AA000C3760 /* Build configuration list for PBXNativeTarget "Miniature" */ = { isa = XCConfigurationList; buildConfigurations = ( @@ -5774,10 +5415,6 @@ isa = XCSwiftPackageProductDependency; productName = XcodeTarget_StatsWidget; }; - 0C6AC6252C364A8500BF7600 /* XcodeTarget_Intents */ = { - isa = XCSwiftPackageProductDependency; - productName = XcodeTarget_Intents; - }; 0CECA92A2E043CEC00F4EE83 /* XcodeTarget_App */ = { isa = XCSwiftPackageProductDependency; productName = XcodeTarget_App; diff --git a/WordPress/WordPress.xcodeproj/xcshareddata/xcschemes/JetpackIntents.xcscheme b/WordPress/WordPress.xcodeproj/xcshareddata/xcschemes/JetpackIntents.xcscheme deleted file mode 100644 index 66bd1dda8d3d..000000000000 --- a/WordPress/WordPress.xcodeproj/xcshareddata/xcschemes/JetpackIntents.xcscheme +++ /dev/null @@ -1,71 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/fastlane/Fastfile b/fastlane/Fastfile index a425657bcae3..fe70397c5c5d 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -45,7 +45,6 @@ JETPACK_EXTENSIONS_BUNDLE_IDENTIFIERS = %w[ JetpackDraftAction JetpackStatsWidgets JetpackNotificationServiceExtension - JetpackIntents ].map { |suffix| "#{JETPACK_BUNDLE_IDENTIFIER}.#{suffix}" } ALL_JETPACK_BUNDLE_IDENTIFIERS = [JETPACK_BUNDLE_IDENTIFIER, *JETPACK_EXTENSIONS_BUNDLE_IDENTIFIERS].freeze diff --git a/fastlane/lanes/localization.rb b/fastlane/lanes/localization.rb index cbf1575a853b..a6897b7dc1ac 100644 --- a/fastlane/lanes/localization.rb +++ b/fastlane/lanes/localization.rb @@ -97,7 +97,7 @@ File.join('WordPress', 'Resources', 'en.lproj', 'InfoPlist.strings') => 'infoplist.', # For now WordPress and Jetpack share the same InfoPlist.strings File.join('WordPress', 'WordPressDraftActionExtension', 'en.lproj', 'InfoPlist.strings') => 'ios-sharesheet.', # CFBundleDisplayName for the "Save as Draft" share action File.join('WordPress', 'JetpackDraftActionExtension', 'en.lproj', 'InfoPlist.strings') => 'ios-jetpack-sharesheet.', # CFBundleDisplayName for the "Save to Jetpack" share action - File.join('WordPress', 'JetpackIntents', 'en.lproj', 'Sites.strings') => 'ios-widget.' # Strings from the `.intentdefinition`, used for configuring the iOS Widget + File.join('WordPress', 'JetpackStatsWidgets', 'en.lproj', 'Localizable.strings') => 'ios-widget.' # Strings for the App Intents UI used when configuring the iOS Widget; resolved at runtime via the prefixed keys in the app's Localizable.strings }.freeze # Remote Swift Packages whose localizable strings we want to extract (they're checked out under Derived Data From 278e2e037d401b0ff2894bbe92cec2d3d8d5fa36 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 7 Jul 2026 13:39:35 +1200 Subject: [PATCH 4/5] Ship the widget App Intents strings in the widget extension bundle The system resolves the widget configuration UI's strings against the app bundle on iOS 26 but against the widget extension bundle on iOS 17, and a package resource bundle is never consulted (verified on simulators). The extension therefore ships static copies of the GlotPress-maintained ios-widget. keys for the older resolution path. --- .../Resources/ar.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/bg.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/cs.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/cy.lproj/Localizable.strings | 9 +++++++++ .../Resources/da.lproj/Localizable.strings | 9 +++++++++ .../Resources/de.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/en-AU.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/en-CA.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/en-GB.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/en.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/es.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/fr.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/he.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/hr.lproj/Localizable.strings | 9 +++++++++ .../Resources/hu.lproj/Localizable.strings | 9 +++++++++ .../Resources/id.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/is.lproj/Localizable.strings | 9 +++++++++ .../Resources/it.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/ja.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/ko.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/nb.lproj/Localizable.strings | 9 +++++++++ .../Resources/nl.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/pl.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/pt-BR.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/pt.lproj/Localizable.strings | 9 +++++++++ .../Resources/ro.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/ru.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/sk.lproj/Localizable.strings | 9 +++++++++ .../Resources/sq.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/sv.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/th.lproj/Localizable.strings | 9 +++++++++ .../Resources/tr.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/zh-Hans.lproj/Localizable.strings | 12 ++++++++++++ .../Resources/zh-Hant.lproj/Localizable.strings | 12 ++++++++++++ 34 files changed, 381 insertions(+) create mode 100644 Sources/JetpackStatsWidgets/Resources/ar.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/bg.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/cs.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/cy.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/da.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/de.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/en-AU.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/en-CA.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/en-GB.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/en.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/es.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/fr.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/he.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/hr.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/hu.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/id.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/is.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/it.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/ja.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/ko.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/nb.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/nl.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/pl.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/pt-BR.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/pt.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/ro.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/ru.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/sk.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/sq.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/sv.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/th.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/tr.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/zh-Hans.lproj/Localizable.strings create mode 100644 Sources/JetpackStatsWidgets/Resources/zh-Hant.lproj/Localizable.strings diff --git a/Sources/JetpackStatsWidgets/Resources/ar.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/ar.lproj/Localizable.strings new file mode 100644 index 000000000000..a8f732c074ed --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/ar.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "تحديد موقع"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "الموقع"; diff --git a/Sources/JetpackStatsWidgets/Resources/bg.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/bg.lproj/Localizable.strings new file mode 100644 index 000000000000..552c82bf3b20 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/bg.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Сайт"; diff --git a/Sources/JetpackStatsWidgets/Resources/cs.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/cs.lproj/Localizable.strings new file mode 100644 index 000000000000..325ea1843745 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/cs.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Vybrat web"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Web"; diff --git a/Sources/JetpackStatsWidgets/Resources/cy.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/cy.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/cy.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/da.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/da.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/da.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/de.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/de.lproj/Localizable.strings new file mode 100644 index 000000000000..c5767a6451cf --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/de.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Website auswählen"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Website"; diff --git a/Sources/JetpackStatsWidgets/Resources/en-AU.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/en-AU.lproj/Localizable.strings new file mode 100644 index 000000000000..6e01cd7104f1 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/en-AU.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/en-CA.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/en-CA.lproj/Localizable.strings new file mode 100644 index 000000000000..6e01cd7104f1 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/en-CA.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/en-GB.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/en-GB.lproj/Localizable.strings new file mode 100644 index 000000000000..6e01cd7104f1 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/en-GB.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/en.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/en.lproj/Localizable.strings new file mode 100644 index 000000000000..6e01cd7104f1 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/en.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/es.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/es.lproj/Localizable.strings new file mode 100644 index 000000000000..527eaa94847a --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/es.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Seleccionar sitio"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Sitio"; diff --git a/Sources/JetpackStatsWidgets/Resources/fr.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/fr.lproj/Localizable.strings new file mode 100644 index 000000000000..e6080f30a845 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/fr.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Sélectionnez le site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/he.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/he.lproj/Localizable.strings new file mode 100644 index 000000000000..ee7bf6f59ebf --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/he.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "יש לבחור אתר"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "אתר"; diff --git a/Sources/JetpackStatsWidgets/Resources/hr.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/hr.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/hr.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/hu.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/hu.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/hu.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/id.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/id.lproj/Localizable.strings new file mode 100644 index 000000000000..c62842496db1 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/id.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Pilih Situs"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Situs"; diff --git a/Sources/JetpackStatsWidgets/Resources/is.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/is.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/is.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/it.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/it.lproj/Localizable.strings new file mode 100644 index 000000000000..c5104f566177 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/it.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Seleziona sito"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Sito"; diff --git a/Sources/JetpackStatsWidgets/Resources/ja.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/ja.lproj/Localizable.strings new file mode 100644 index 000000000000..90f0604bfdb2 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/ja.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "サイトを選択"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "サイト"; diff --git a/Sources/JetpackStatsWidgets/Resources/ko.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/ko.lproj/Localizable.strings new file mode 100644 index 000000000000..b81570c41edb --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/ko.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "사이트 선택"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "사이트"; diff --git a/Sources/JetpackStatsWidgets/Resources/nb.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/nb.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/nb.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/nl.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/nl.lproj/Localizable.strings new file mode 100644 index 000000000000..81677301fb0c --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/nl.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Selecteer site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/pl.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/pl.lproj/Localizable.strings new file mode 100644 index 000000000000..5e6e647d8cca --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/pl.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Witryna"; diff --git a/Sources/JetpackStatsWidgets/Resources/pt-BR.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/pt-BR.lproj/Localizable.strings new file mode 100644 index 000000000000..b2b742328c8d --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/pt-BR.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Selecionar site"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/pt.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/pt.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/pt.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/ro.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/ro.lproj/Localizable.strings new file mode 100644 index 000000000000..bd59551e5426 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/ro.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Selectează site-ul"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/ru.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/ru.lproj/Localizable.strings new file mode 100644 index 000000000000..4be547f037ce --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/ru.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Выбрать сайт"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Сайт"; diff --git a/Sources/JetpackStatsWidgets/Resources/sk.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/sk.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/sk.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/sq.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/sq.lproj/Localizable.strings new file mode 100644 index 000000000000..746a1090d5d8 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/sq.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Përzgjidhni Sajt"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Sajt"; diff --git a/Sources/JetpackStatsWidgets/Resources/sv.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/sv.lproj/Localizable.strings new file mode 100644 index 000000000000..6ffe3cc51457 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/sv.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Välj webbplats"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Webbplats"; diff --git a/Sources/JetpackStatsWidgets/Resources/th.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/th.lproj/Localizable.strings new file mode 100644 index 000000000000..d196ac9d5a8f --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/th.lproj/Localizable.strings @@ -0,0 +1,9 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Select Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/tr.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/tr.lproj/Localizable.strings new file mode 100644 index 000000000000..997c8668b402 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/tr.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "Site seçin"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "Site"; diff --git a/Sources/JetpackStatsWidgets/Resources/zh-Hans.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/zh-Hans.lproj/Localizable.strings new file mode 100644 index 000000000000..1882a074f760 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/zh-Hans.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "选择站点"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "站点"; diff --git a/Sources/JetpackStatsWidgets/Resources/zh-Hant.lproj/Localizable.strings b/Sources/JetpackStatsWidgets/Resources/zh-Hant.lproj/Localizable.strings new file mode 100644 index 000000000000..ede8667b35b2 --- /dev/null +++ b/Sources/JetpackStatsWidgets/Resources/zh-Hant.lproj/Localizable.strings @@ -0,0 +1,12 @@ +/* Static copies of the widget configuration strings, under the same `ios-widget.`-prefixed + keys that GlotPress maintains in the app's Localizable.strings. iOS 17 resolves the widget + configuration UI's App Intents strings against this extension bundle (newer iOS versions + use the app bundle), so these files must ship here. To refresh after translations change, + copy the `ios-widget.gpCwrM` / `ios-widget.ILcGmf` entries from + WordPress/Resources/.lproj/Localizable.strings. */ + +/* This text is used when the user is configuring the iOS widget to suggest them to select the site to configure the widget for */ +"ios-widget.gpCwrM" = "選取網站"; + +/* This text is used when the user is configuring the iOS widget, as a label for the dropdown to select the site to configure it for */ +"ios-widget.ILcGmf" = "網站"; From fa8a9edac417ea3dd68b2093408fce1ba35672c6 Mon Sep 17 00:00:00 2001 From: Tony Li Date: Tue, 7 Jul 2026 15:59:11 +1200 Subject: [PATCH 5/5] Add a release note for the widget site picker migration --- RELEASE-NOTES.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/RELEASE-NOTES.txt b/RELEASE-NOTES.txt index 9ffe34b4fe16..423368e006f3 100644 --- a/RELEASE-NOTES.txt +++ b/RELEASE-NOTES.txt @@ -2,6 +2,7 @@ ----- * [*] [internal] In-app updates: guard the flexible update notice against double-posting when two update checks race [#25666] * [*] [build tooling] Add a String Catalog localization pipeline (plurals + build-free catalog generation) with a CI coverage gate [#25688] +* [*] [internal] Stats widgets: migrate the site picker from SiriKit to App Intents [#25753] 27.0