diff --git a/.buildkite/pipeline.yml b/.buildkite/pipeline.yml
index 5129853c..5beb00c1 100644
--- a/.buildkite/pipeline.yml
+++ b/.buildkite/pipeline.yml
@@ -5,35 +5,19 @@ env:
IMAGE_ID: $IMAGE_ID
steps:
- - label: ':react: Build React App'
- command: make build
- plugins: &plugins
- - $CI_TOOLKIT_PLUGIN
- - $NVM_PLUGIN
-
- - label: ':eslint: Lint React App'
- command: make lint-js
- plugins: *plugins
-
- label: ':javascript: Test JavaScript'
command: make test-js
- plugins: *plugins
-
- - label: ':android: Publish Android Library'
- command: |
- make build
- echo "--- :android: Publishing Android Library"
- ./android/gradlew -p ./android :gutenberg:prepareToPublishToS3 $(prepare_to_publish_to_s3_params) :gutenberg:publish
- agents:
- queue: android
- plugins: *plugins
+ plugins: &plugins
+ - $CI_TOOLKIT_PLUGIN
+ - $NVM_PLUGIN
- - label: ':android: Test Android Library'
- command: make test-android
- agents:
- queue: android
+ - label: ':swift: Test Swift Package'
+ command: GUTENBERGKIT_SWIFT_USE_LOCAL_RESOURCES=1 make test-swift-package
plugins: *plugins
- - label: ':swift: Test Swift Package'
- command: make test-swift-package
+ - label: ':xcode: Publish XCFramework'
+ command: make publish-resources-xcframework
plugins: *plugins
+ artifact_paths:
+ - 'build/*.xcframework.zip'
+ - 'build/*.checksum.txt'
diff --git a/.bundle/config b/.bundle/config
new file mode 100644
index 00000000..724931e2
--- /dev/null
+++ b/.bundle/config
@@ -0,0 +1,3 @@
+---
+BUNDLE_PATH: "vendor/bundle"
+BUNDLE_SPECIFIC_PLATFORM: "false"
diff --git a/.gitignore b/.gitignore
index 210dc00a..ca0fbc8a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@
## Build generated
build/
DerivedData
-.swiftpm/
UserInterfaceState.xcuserstate
## Various settings
@@ -37,9 +36,12 @@ playground.xcworkspace
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
-
.build/
-.swiftpm
+.swiftpm/*
+# To track xcshareddata, we also need rules for its parent folder
+!.swiftpm/xcode/
+.swiftpm/xcode/*
+!.swiftpm/xcode/xcshareddata/
# Logs
logs
@@ -189,14 +191,16 @@ local.properties
/android/Gutenberg/src/main/assets/assets
/android/Gutenberg/src/main/assets/index.html
/android/Gutenberg/src/main/assets/remote.html
-
-# Disabled removing these files until this is published like Android in CI.
-# /ios/Sources/GutenbergKit/Gutenberg/assets
-# /ios/Sources/GutenbergKit/Gutenberg/index.html
-# /ios/Sources/GutenbergKit/Gutenberg/remote.html
+/ios/Sources/GutenbergKitResources/Resources/assets
+/ios/Sources/GutenbergKitResources/Resources/index.html
+/ios/Sources/GutenbergKitResources/Resources/remote.html
# Translation files
src/translations/
# Claude
.claude/settings.local.json
+
+# Ruby tooling
+vendor/bundle
+fastlane/report.xml
diff --git a/.ruby-version b/.ruby-version
new file mode 100644
index 00000000..a0891f56
--- /dev/null
+++ b/.ruby-version
@@ -0,0 +1 @@
+3.3.4
diff --git a/.swiftpm/xcode/xcshareddata/xcschemes/GutenbergKit.xcscheme b/.swiftpm/xcode/xcshareddata/xcschemes/GutenbergKit.xcscheme
new file mode 100644
index 00000000..3948d79c
--- /dev/null
+++ b/.swiftpm/xcode/xcshareddata/xcschemes/GutenbergKit.xcscheme
@@ -0,0 +1,104 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 00000000..51505cfa
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,6 @@
+# frozen_string_literal: true
+
+source 'https://rubygems.org'
+
+gem 'fastlane-plugin-wpmreleasetoolkit', '~> 13.7'
+gem 'openssl'
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 00000000..f1879bef
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,311 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ CFPropertyList (3.0.8)
+ activesupport (8.1.1)
+ base64
+ bigdecimal
+ concurrent-ruby (~> 1.0, >= 1.3.1)
+ connection_pool (>= 2.2.5)
+ drb
+ i18n (>= 1.6, < 2)
+ json
+ logger (>= 1.4.2)
+ minitest (>= 5.1)
+ securerandom (>= 0.3)
+ tzinfo (~> 2.0, >= 2.0.5)
+ uri (>= 0.13.1)
+ addressable (2.8.8)
+ public_suffix (>= 2.0.2, < 8.0)
+ artifactory (3.0.17)
+ atomos (0.1.3)
+ aws-eventstream (1.4.0)
+ aws-partitions (1.1203.0)
+ aws-sdk-core (3.241.3)
+ aws-eventstream (~> 1, >= 1.3.0)
+ aws-partitions (~> 1, >= 1.992.0)
+ aws-sigv4 (~> 1.9)
+ base64
+ bigdecimal
+ jmespath (~> 1, >= 1.6.1)
+ logger
+ aws-sdk-kms (1.120.0)
+ aws-sdk-core (~> 3, >= 3.241.3)
+ aws-sigv4 (~> 1.5)
+ aws-sdk-s3 (1.211.0)
+ aws-sdk-core (~> 3, >= 3.241.3)
+ aws-sdk-kms (~> 1)
+ aws-sigv4 (~> 1.5)
+ aws-sigv4 (1.12.1)
+ aws-eventstream (~> 1, >= 1.0.2)
+ babosa (1.0.4)
+ base64 (0.3.0)
+ bigdecimal (4.0.1)
+ buildkit (1.6.1)
+ sawyer (>= 0.6)
+ chroma (0.2.0)
+ claide (1.1.0)
+ colored (1.2)
+ colored2 (3.1.2)
+ commander (4.6.0)
+ highline (~> 2.0.0)
+ concurrent-ruby (1.3.5)
+ connection_pool (2.5.5)
+ declarative (0.0.20)
+ diffy (3.4.4)
+ digest-crc (0.7.0)
+ rake (>= 12.0.0, < 14.0.0)
+ domain_name (0.6.20240107)
+ dotenv (2.8.1)
+ drb (2.2.3)
+ emoji_regex (3.2.3)
+ excon (0.112.0)
+ faraday (1.10.4)
+ faraday-em_http (~> 1.0)
+ faraday-em_synchrony (~> 1.0)
+ faraday-excon (~> 1.1)
+ faraday-httpclient (~> 1.0)
+ faraday-multipart (~> 1.0)
+ faraday-net_http (~> 1.0)
+ faraday-net_http_persistent (~> 1.0)
+ faraday-patron (~> 1.0)
+ faraday-rack (~> 1.0)
+ faraday-retry (~> 1.0)
+ ruby2_keywords (>= 0.0.4)
+ faraday-cookie_jar (0.0.8)
+ faraday (>= 0.8.0)
+ http-cookie (>= 1.0.0)
+ faraday-em_http (1.0.0)
+ faraday-em_synchrony (1.0.1)
+ faraday-excon (1.1.0)
+ faraday-httpclient (1.0.1)
+ faraday-multipart (1.2.0)
+ multipart-post (~> 2.0)
+ faraday-net_http (1.0.2)
+ faraday-net_http_persistent (1.2.0)
+ faraday-patron (1.0.0)
+ faraday-rack (1.0.0)
+ faraday-retry (1.0.3)
+ faraday_middleware (1.2.1)
+ faraday (~> 1.0)
+ fastimage (2.4.0)
+ fastlane (2.214.0)
+ CFPropertyList (>= 2.3, < 4.0.0)
+ addressable (>= 2.8, < 3.0.0)
+ artifactory (~> 3.0)
+ aws-sdk-s3 (~> 1.0)
+ babosa (>= 1.0.3, < 2.0.0)
+ bundler (>= 1.12.0, < 3.0.0)
+ colored
+ commander (~> 4.6)
+ dotenv (>= 2.1.1, < 3.0.0)
+ emoji_regex (>= 0.1, < 4.0)
+ excon (>= 0.71.0, < 1.0.0)
+ faraday (~> 1.0)
+ faraday-cookie_jar (~> 0.0.6)
+ faraday_middleware (~> 1.0)
+ fastimage (>= 2.1.0, < 3.0.0)
+ gh_inspector (>= 1.1.2, < 2.0.0)
+ google-apis-androidpublisher_v3 (~> 0.3)
+ google-apis-playcustomapp_v1 (~> 0.1)
+ google-cloud-storage (~> 1.31)
+ highline (~> 2.0)
+ json (< 3.0.0)
+ jwt (>= 2.1.0, < 3)
+ mini_magick (>= 4.9.4, < 5.0.0)
+ multipart-post (>= 2.0.0, < 3.0.0)
+ naturally (~> 2.2)
+ optparse (~> 0.1.1)
+ plist (>= 3.1.0, < 4.0.0)
+ rubyzip (>= 2.0.0, < 3.0.0)
+ security (= 0.1.3)
+ simctl (~> 1.6.3)
+ terminal-notifier (>= 2.0.0, < 3.0.0)
+ terminal-table (>= 1.4.5, < 2.0.0)
+ tty-screen (>= 0.6.3, < 1.0.0)
+ tty-spinner (>= 0.8.0, < 1.0.0)
+ word_wrap (~> 1.0.0)
+ xcodeproj (>= 1.13.0, < 2.0.0)
+ xcpretty (~> 0.3.0)
+ xcpretty-travis-formatter (>= 0.0.3)
+ fastlane-plugin-wpmreleasetoolkit (13.7.0)
+ activesupport (>= 6.1.7.1)
+ buildkit (~> 1.5)
+ chroma (= 0.2.0)
+ diffy (~> 3.3)
+ fastlane (~> 2.213)
+ git (~> 1.3)
+ google-cloud-storage (~> 1.31)
+ java-properties (~> 0.3.0)
+ nokogiri (~> 1.11)
+ octokit (~> 6.1)
+ parallel (~> 1.14)
+ plist (~> 3.1)
+ progress_bar (~> 1.3)
+ rake (>= 12.3, < 14.0)
+ rake-compiler (~> 1.0)
+ xcodeproj (~> 1.22)
+ gh_inspector (1.1.3)
+ git (1.19.1)
+ addressable (~> 2.8)
+ rchardet (~> 1.8)
+ google-apis-androidpublisher_v3 (0.94.0)
+ google-apis-core (>= 0.15.0, < 2.a)
+ google-apis-core (0.18.0)
+ addressable (~> 2.5, >= 2.5.1)
+ googleauth (~> 1.9)
+ httpclient (>= 2.8.3, < 3.a)
+ mini_mime (~> 1.0)
+ mutex_m
+ representable (~> 3.0)
+ retriable (>= 2.0, < 4.a)
+ google-apis-iamcredentials_v1 (0.26.0)
+ google-apis-core (>= 0.15.0, < 2.a)
+ google-apis-playcustomapp_v1 (0.17.0)
+ google-apis-core (>= 0.15.0, < 2.a)
+ google-apis-storage_v1 (0.58.0)
+ google-apis-core (>= 0.15.0, < 2.a)
+ google-cloud-core (1.8.0)
+ google-cloud-env (>= 1.0, < 3.a)
+ google-cloud-errors (~> 1.0)
+ google-cloud-env (2.3.1)
+ base64 (~> 0.2)
+ faraday (>= 1.0, < 3.a)
+ google-cloud-errors (1.5.0)
+ google-cloud-storage (1.58.0)
+ addressable (~> 2.8)
+ digest-crc (~> 0.4)
+ google-apis-core (>= 0.18, < 2)
+ google-apis-iamcredentials_v1 (~> 0.18)
+ google-apis-storage_v1 (>= 0.42)
+ google-cloud-core (~> 1.6)
+ googleauth (~> 1.9)
+ mini_mime (~> 1.0)
+ google-logging-utils (0.2.0)
+ googleauth (1.16.0)
+ faraday (>= 1.0, < 3.a)
+ google-cloud-env (~> 2.2)
+ google-logging-utils (~> 0.1)
+ jwt (>= 1.4, < 4.0)
+ multi_json (~> 1.11)
+ os (>= 0.9, < 2.0)
+ signet (>= 0.16, < 2.a)
+ highline (2.0.3)
+ http-cookie (1.1.0)
+ domain_name (~> 0.5)
+ httpclient (2.9.0)
+ mutex_m
+ i18n (1.14.7)
+ concurrent-ruby (~> 1.0)
+ java-properties (0.3.0)
+ jmespath (1.6.2)
+ json (2.18.0)
+ jwt (2.10.2)
+ base64
+ logger (1.7.0)
+ mini_magick (4.13.2)
+ mini_mime (1.1.5)
+ minitest (5.26.2)
+ multi_json (1.19.1)
+ multipart-post (2.4.1)
+ mutex_m (0.3.0)
+ nanaimo (0.4.0)
+ naturally (2.3.0)
+ nokogiri (1.18.10-aarch64-linux-gnu)
+ racc (~> 1.4)
+ nokogiri (1.18.10-aarch64-linux-musl)
+ racc (~> 1.4)
+ nokogiri (1.18.10-arm-linux-gnu)
+ racc (~> 1.4)
+ nokogiri (1.18.10-arm-linux-musl)
+ racc (~> 1.4)
+ nokogiri (1.18.10-arm64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.18.10-x86_64-darwin)
+ racc (~> 1.4)
+ nokogiri (1.18.10-x86_64-linux-gnu)
+ racc (~> 1.4)
+ nokogiri (1.18.10-x86_64-linux-musl)
+ racc (~> 1.4)
+ octokit (6.1.1)
+ faraday (>= 1, < 3)
+ sawyer (~> 0.9)
+ openssl (4.0.0)
+ options (2.3.2)
+ optparse (0.1.1)
+ os (1.1.4)
+ parallel (1.27.0)
+ plist (3.7.2)
+ progress_bar (1.3.4)
+ highline (>= 1.6)
+ options (~> 2.3.0)
+ public_suffix (7.0.2)
+ racc (1.8.1)
+ rake (13.3.1)
+ rake-compiler (1.3.0)
+ rake
+ rchardet (1.10.0)
+ representable (3.2.0)
+ declarative (< 0.1.0)
+ trailblazer-option (>= 0.1.1, < 0.2.0)
+ uber (< 0.2.0)
+ retriable (3.1.2)
+ rexml (3.4.4)
+ rouge (2.0.7)
+ ruby2_keywords (0.0.5)
+ rubyzip (2.4.1)
+ sawyer (0.9.3)
+ addressable (>= 2.3.5)
+ faraday (>= 0.17.3, < 3)
+ securerandom (0.4.1)
+ security (0.1.3)
+ signet (0.21.0)
+ addressable (~> 2.8)
+ faraday (>= 0.17.5, < 3.a)
+ jwt (>= 1.5, < 4.0)
+ multi_json (~> 1.10)
+ simctl (1.6.10)
+ CFPropertyList
+ naturally
+ terminal-notifier (2.0.0)
+ terminal-table (1.8.0)
+ unicode-display_width (~> 1.1, >= 1.1.1)
+ trailblazer-option (0.1.2)
+ tty-cursor (0.7.1)
+ tty-screen (0.8.2)
+ tty-spinner (0.9.3)
+ tty-cursor (~> 0.7)
+ tzinfo (2.0.6)
+ concurrent-ruby (~> 1.0)
+ uber (0.1.0)
+ unicode-display_width (1.8.0)
+ uri (1.1.1)
+ word_wrap (1.0.0)
+ xcodeproj (1.27.0)
+ CFPropertyList (>= 2.3.3, < 4.0)
+ atomos (~> 0.1.3)
+ claide (>= 1.0.2, < 2.0)
+ colored2 (~> 3.1)
+ nanaimo (~> 0.4.0)
+ rexml (>= 3.3.6, < 4.0)
+ xcpretty (0.3.0)
+ rouge (~> 2.0.7)
+ xcpretty-travis-formatter (1.0.1)
+ xcpretty (~> 0.2, >= 0.0.7)
+
+PLATFORMS
+ aarch64-linux-gnu
+ aarch64-linux-musl
+ arm-linux-gnu
+ arm-linux-musl
+ arm64-darwin
+ x86_64-darwin
+ x86_64-linux-gnu
+ x86_64-linux-musl
+
+DEPENDENCIES
+ fastlane-plugin-wpmreleasetoolkit (~> 13.7)
+ openssl
+
+BUNDLED WITH
+ 2.6.5
diff --git a/Makefile b/Makefile
index 31151bc4..b6025118 100644
--- a/Makefile
+++ b/Makefile
@@ -1,4 +1,9 @@
SIMULATOR_DESTINATION := OS=26.0,name=iPhone 17
+GUTENBERG_RESOURCES_XCFRAMEWORK_NAME := GutenbergKitResources
+
+# Use local resources instead of pre-built XCFramework for Swift package.
+# After all, this is the automation that builds the XCFramework, among others.
+export GUTENBERGKIT_SWIFT_USE_LOCAL_RESOURCES := 1
define XCODEBUILD_CMD
@set -o pipefail && \
@@ -6,6 +11,9 @@ define XCODEBUILD_CMD
-scheme GutenbergKit \
-sdk iphonesimulator \
-destination '${SIMULATOR_DESTINATION}' \
+ CODE_SIGN_IDENTITY="-" \
+ CODE_SIGNING_REQUIRED=NO \
+ CODE_SIGNING_ALLOWED=NO \
| xcbeautify
endef
@@ -15,6 +23,14 @@ npm-dependencies:
npm ci; \
fi
+ruby-dependencies:
+ @if [ "$(BUILDKITE)" == "true" ]; then \
+ echo "--- :ruby: Installing Ruby Dependencies"; \
+ install_gems; \
+ else \
+ bundle install; \
+ fi
+
prep-translations:
@if [ "$(SKIP_L10N)" != "true" ] && [ "$(SKIP_L10N)" != "1" ]; then \
echo "--- :npm: Preparing Translations"; \
@@ -28,9 +44,11 @@ build: npm-dependencies prep-translations
# Copy build products into place
echo "--- :open_file_folder: Copying Build Products into place"
- rm -rf ./ios/Sources/GutenbergKit/Gutenberg/ ./android/Gutenberg/src/main/assets/
- cp -r ./dist/. ./ios/Sources/GutenbergKit/Gutenberg/
+ rm -rf ./android/Gutenberg/src/main/assets/
cp -r ./dist/. ./android/Gutenberg/src/main/assets
+ rm -rf "./ios/Sources/${GUTENBERG_RESOURCES_XCFRAMEWORK_NAME}/Resources/"
+ cp -r ./dist/. "./ios/Sources/${GUTENBERG_RESOURCES_XCFRAMEWORK_NAME}/Resources/"
+ touch "./ios/Sources/${GUTENBERG_RESOURCES_XCFRAMEWORK_NAME}/Resources/.gitkeep"
dev-server: npm-dependencies
npm run dev
@@ -58,12 +76,25 @@ test-android:
echo "--- :android: Running Android Tests"
./android/gradlew -p ./android :gutenberg:test
-build-swift-package: build
+.PHONY: build-swift-package
+build-swift-package: build-resources-xcframework ## Build the Swift package for iOS
$(call XCODEBUILD_CMD, build)
+.PHONY: build-resources-xcframework
+build-resources-xcframework: build # Build the resources XCFramework
+ @echo "--- :package: Building Gutenberg resources XCFramework"
+ @SWIFT_OPTIMIZATION_LEVEL="${SWIFT_OPTIMIZATION_LEVEL:--O}" ./build_xcframework.sh ${GUTENBERG_RESOURCES_XCFRAMEWORK_NAME}
+
test-swift-package: build
$(call XCODEBUILD_CMD, test)
+REVISION ?= $(or $(BUILDKITE_COMMIT),$(shell git rev-parse HEAD))
+
+.PHONY: publish-resources-xcframework
+publish-resources-xcframework: ruby-dependencies build-resources-xcframework
+ @echo "--- :s3: Uploading XCFramework to S3"
+ @bundle exec fastlane publish_to_s3 version:$(REVISION)
+
release:
@echo "--- :rocket: Starting GutenbergKit Release Process"
@echo "Usage: make release VERSION_TYPE=[ | major | minor | patch | premajor | preminor | prepatch | prerelease | from-git] [DRY_RUN=true]"
diff --git a/Package.swift b/Package.swift
index 39214b9a..b2f122dc 100644
--- a/Package.swift
+++ b/Package.swift
@@ -2,13 +2,50 @@
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
+import Foundation
+
+// Set GUTENBERGKIT_SWIFT_USE_LOCAL_RESOURCES=1 to build resources from source instead of using the pre-built XCFramework
+let useLocalResources = ProcessInfo.processInfo.environment["GUTENBERGKIT_SWIFT_USE_LOCAL_RESOURCES"] == "1"
+
+// TODO: This has been manually uploaded, we'll need automation to both upload and update the URL and checksum
+let revision = "1a5dfde9799536ac9f107faf78145aeceff574f7"
+let xcframeworkChecksum = "5d57b063c1458b9aa858f8830586d78ccb55341eba9e512c7d1409336a3e6f34"
+let xcframeworkURL = "https://cdn.a8c-ci.services/gutenbergkit/\(revision)/GutenbergKitResources.xcframework.zip"
+
+// Only expose GutenbergKitResources as a product when building from source (needed for XCFramework generation)
+let resourcesProducts: [Product] = useLocalResources
+ ? [
+ .library(
+ name: "GutenbergKitResources",
+ // Required for XCFramework generation
+ type: .dynamic,
+ targets: ["GutenbergKitResources"]
+ )
+ ]
+ : []
+
+let resourcesTargets: [Target] = useLocalResources
+ ? [
+ .target(
+ name: "GutenbergKitResources",
+ path: "ios/Sources/GutenbergKitResources",
+ resources: [.copy("Resources")]
+ )
+ ]
+ : [
+ .binaryTarget(
+ name: "GutenbergKitResources",
+ url: xcframeworkURL,
+ checksum: xcframeworkChecksum
+ )
+ ]
let package = Package(
name: "GutenbergKit",
platforms: [.iOS(.v17), .macOS(.v14)],
products: [
- .library(name: "GutenbergKit", targets: ["GutenbergKit"])
- ],
+ .library(name: "GutenbergKit", targets: ["GutenbergKit"]),
+ ] + resourcesProducts,
dependencies: [
.package(url: "https://github.com/scinfu/SwiftSoup.git", from: "2.7.5"),
.package(url: "https://github.com/exyte/SVGView.git", from: "1.0.6"),
@@ -16,19 +53,33 @@ let package = Package(
targets: [
.target(
name: "GutenbergKit",
- dependencies: ["SwiftSoup", "SVGView"],
+ dependencies: [
+ "SwiftSoup",
+ "SVGView",
+ "GutenbergKitResources"
+ ],
path: "ios/Sources/GutenbergKit",
exclude: [],
- resources: [.copy("Gutenberg")]
+ // Required to allow importing GutenbergKitResources when it's a binary target (XCFramework).
+ // Without this, Swift fails with "module was built from a non-package interface" because
+ // it treats both targets as same-package but the XCFramework was built for distribution.
+ // Note: This means GutenbergKit source cannot use the `package` access modifier.
+ // See: https://developer.apple.com/documentation/packagedescription/target/packageaccess
+ packageAccess: false
),
.testTarget(
name: "GutenbergKitTests",
dependencies: ["GutenbergKit"],
- path: "ios/Tests",
+ path: "ios/Tests/GutenbergKitTests",
exclude: [],
resources: [
- .copy("GutenbergKitTests/Resources/manifest-test-case-1.json")
+ .copy("Resources/manifest-test-case-1.json")
]
),
- ]
+ .testTarget(
+ name: "GutenbergKitResourcesTests",
+ dependencies: ["GutenbergKitResources"],
+ path: "ios/Tests/GutenbergKitResourcesTests",
+ ),
+ ] + resourcesTargets
)
diff --git a/build_xcframework.sh b/build_xcframework.sh
new file mode 100755
index 00000000..02c48918
--- /dev/null
+++ b/build_xcframework.sh
@@ -0,0 +1,160 @@
+#!/usr/bin/env bash
+
+set -euo pipefail
+
+# Colors for output
+GREEN='\033[0;32m'
+NC='\033[0m' # No Color
+
+# Originally sourced from:
+# https://github.com/OpenSwiftUIProject/ProtobufKit/blob/937eae5426277bec040c7f99bc8e1498c30ed467/Scripts/build_xcframework.sh
+#
+# Found it via:
+# https://forums.swift.org/t/how-on-earth-can-i-create-a-framework-from-a-swift-package/76797/6
+#
+# Related:
+# https://forums.swift.org/t/how-to-build-swift-package-as-xcframework/41414/57
+
+# Script modified from https://docs.emergetools.com/docs/analyzing-a-spm-framework-ios
+
+PACKAGE_NAME=${1-}
+if [ -z "$PACKAGE_NAME" ]; then
+ echo "No package name provided. Using the first scheme found in the Package.swift."
+ PACKAGE_NAME=$(xcodebuild -list | awk 'schemes && NF>0 { print $1; exit } /Schemes:$/ { schemes = 1 }')
+ echo "Using: $PACKAGE_NAME"
+fi
+
+# Swift optimization level: -Onone (no optimization), -O (optimize for speed), -Osize (optimize for size)
+# Default to -O for release builds, can be overridden with SWIFT_OPTIMIZATION_LEVEL environment variable
+SWIFT_OPTIMIZATION_LEVEL="${SWIFT_OPTIMIZATION_LEVEL:--O}"
+echo "Swift optimization level: $SWIFT_OPTIMIZATION_LEVEL"
+
+# FIXME: Original script was in subfolder, this is in repo root for the time being.
+#
+# SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd -P)"
+# PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
+PROJECT_ROOT=$(pwd)
+
+PROJECT_BUILD_DIR="${PROJECT_BUILD_DIR:-"${PROJECT_ROOT}/build"}"
+XCODEBUILD_BUILD_DIR="$PROJECT_BUILD_DIR/xcodebuild"
+XCODEBUILD_DERIVED_DATA_PATH="$XCODEBUILD_BUILD_DIR/DerivedData"
+
+echo "PROJECT_BUILD_DIR is $PROJECT_BUILD_DIR"
+
+build_framework() {
+ local sdk="$1"
+ local destination="$2"
+ local scheme="$3"
+
+ echo "--- Build framework for $scheme $sdk $destination"
+
+ local XCODEBUILD_ARCHIVE_PATH="./build/$scheme-$sdk.xcarchive"
+
+ rm -rf "$XCODEBUILD_ARCHIVE_PATH"
+
+ # TODO: Consider using this env var to switch between static (default)
+ # and dynamic (required for XCFramework)
+ #
+ # See:
+ # https://github.com/OpenSwiftUIProject/ProtobufKit/blob/937eae5426277bec040c7f99bc8e1498c30ed467/Package.swift#L30
+ # LIBRARY_TYPE=dynamic xcodebuild archive \
+ xcodebuild archive \
+ -scheme "$scheme" \
+ -archivePath "$XCODEBUILD_ARCHIVE_PATH" \
+ -derivedDataPath "$XCODEBUILD_DERIVED_DATA_PATH" \
+ -sdk "$sdk" \
+ -destination "$destination" \
+ BUILD_LIBRARY_FOR_DISTRIBUTION=YES \
+ INSTALL_PATH='Library/Frameworks' \
+ SWIFT_OPTIMIZATION_LEVEL="$SWIFT_OPTIMIZATION_LEVEL" \
+ OTHER_SWIFT_FLAGS=-no-verify-emitted-module-interface \
+ CODE_SIGN_IDENTITY="-" \
+ CODE_SIGNING_REQUIRED=NO \
+ CODE_SIGNING_ALLOWED=NO \
+ | xcbeautify
+
+ if [ "$sdk" = "macosx" ]; then
+ FRAMEWORK_MODULES_PATH="$XCODEBUILD_ARCHIVE_PATH/Products/Library/Frameworks/$scheme.framework/Versions/Current/Modules"
+ mkdir -p "$FRAMEWORK_MODULES_PATH"
+ cp -r \
+ "$XCODEBUILD_DERIVED_DATA_PATH/Build/Intermediates.noindex/ArchiveIntermediates/$scheme/BuildProductsPath/Release/$scheme.swiftmodule" \
+ "$FRAMEWORK_MODULES_PATH/$scheme.swiftmodule"
+ rm -rf "$XCODEBUILD_ARCHIVE_PATH/Products/Library/Frameworks/$scheme.framework/Modules"
+ ln -s Versions/Current/Modules "$XCODEBUILD_ARCHIVE_PATH/Products/Library/Frameworks/$scheme.framework/Modules"
+ else
+ FRAMEWORK_MODULES_PATH="$XCODEBUILD_ARCHIVE_PATH/Products/Library/Frameworks/$scheme.framework/Modules"
+ mkdir -p "$FRAMEWORK_MODULES_PATH"
+ cp -r \
+ "$XCODEBUILD_DERIVED_DATA_PATH/Build/Intermediates.noindex/ArchiveIntermediates/$scheme/BuildProductsPath/Release-$sdk/$scheme.swiftmodule" \
+ "$FRAMEWORK_MODULES_PATH/$scheme.swiftmodule"
+ fi
+
+ # Delete private and package swiftinterface
+ rm -f "$FRAMEWORK_MODULES_PATH/$scheme.swiftmodule/*.package.swiftinterface"
+ rm -f "$FRAMEWORK_MODULES_PATH/$scheme.swiftmodule/*.private.swiftinterface"
+}
+
+copy_resource_bundles() {
+ local sdk="$1"
+ local scheme="$2"
+
+ echo "--- Copy resource bundles for $scheme $sdk"
+
+ local XCODEBUILD_ARCHIVE_PATH="./build/$scheme-$sdk.xcarchive"
+ local FRAMEWORK_PATH="$XCODEBUILD_ARCHIVE_PATH/Products/Library/Frameworks/$scheme.framework"
+
+ # Find all resource bundles in DerivedData
+ local BUNDLE_PATH="$XCODEBUILD_DERIVED_DATA_PATH/Build/Intermediates.noindex/ArchiveIntermediates/$scheme/IntermediateBuildFilesPath/UninstalledProducts/$sdk"
+
+ # Copy all .bundle files found
+ if [ -d "$BUNDLE_PATH" ]; then
+ find "$BUNDLE_PATH" -name "*.bundle" -maxdepth 1 -type d -print0 | while IFS= read -r -d '' bundle; do
+ bundle_name=$(basename "$bundle")
+ echo "Copying resource bundle: $bundle_name to $FRAMEWORK_PATH"
+ # Remove symlink if it exists and copy the actual bundle
+ rm -rf "${FRAMEWORK_PATH:?}/$bundle_name"
+ cp -R "$bundle" "$FRAMEWORK_PATH/"
+ done
+ else
+ echo "Warning: Bundle path not found: $BUNDLE_PATH"
+ fi
+}
+
+build_framework "iphonesimulator" "generic/platform=iOS Simulator" "$PACKAGE_NAME"
+copy_resource_bundles "iphonesimulator" "$PACKAGE_NAME"
+
+build_framework "iphoneos" "generic/platform=iOS" "$PACKAGE_NAME"
+copy_resource_bundles "iphoneos" "$PACKAGE_NAME"
+
+# No macOS support because of UIKit in the dependencies
+#
+# build_framework "macosx" "generic/platform=macOS" "$PACKAGE_NAME"
+# copy_resource_bundles "macosx" "$PACKAGE_NAME"
+
+echo "Builds completed successfully."
+
+pushd "$PROJECT_BUILD_DIR" > /dev/null
+
+rm -rf "$PACKAGE_NAME.xcframework"
+xcodebuild -create-xcframework \
+ -framework "$PACKAGE_NAME-iphonesimulator.xcarchive/Products/Library/Frameworks/$PACKAGE_NAME.framework" \
+ -framework "$PACKAGE_NAME-iphoneos.xcarchive/Products/Library/Frameworks/$PACKAGE_NAME.framework" \
+ -output "$PACKAGE_NAME.xcframework"
+
+cp -r "$PACKAGE_NAME-iphonesimulator.xcarchive/dSYMs" "$PACKAGE_NAME.xcframework/ios-arm64_x86_64-simulator"
+cp -r "$PACKAGE_NAME-iphoneos.xcarchive/dSYMs" "$PACKAGE_NAME.xcframework/ios-arm64"
+
+ZIP_NAME="$PACKAGE_NAME.xcframework.zip"
+zip -r "$ZIP_NAME" "$PACKAGE_NAME.xcframework" > /dev/null
+
+CHECKSUM=$(swift package compute-checksum "$ZIP_NAME")
+
+echo "$CHECKSUM" > "$ZIP_NAME.checksum.txt"
+
+echo -e "${GREEN}XCFramework generated at $(pwd)/$PACKAGE_NAME.xcframework${NC}"
+echo -e "${GREEN}Zip archive: $(pwd)/$ZIP_NAME${NC}"
+
+echo "+++ :swift: XCFramework checksum"
+echo "$CHECKSUM"
+
+popd > /dev/null
diff --git a/fastlane/Fastfile b/fastlane/Fastfile
new file mode 100644
index 00000000..77081a53
--- /dev/null
+++ b/fastlane/Fastfile
@@ -0,0 +1,25 @@
+# frozen_string_literal: true
+
+PROJECT_ROOT = File.expand_path('..', __dir__)
+
+lane :publish_to_s3 do |version: nil|
+ identifier = version || last_git_commit[:commit_hash]
+
+ UI.message("Uploading XCFramework to S3 with identifier #{identifier}")
+
+ key_root = File.join('gutenbergkit', identifier)
+
+ xcframework_name = 'GutenbergKitResources.xcframework.zip'
+
+ files = [xcframework_name, "#{xcframework_name}.checksum.txt"]
+
+ files.each do |file_name|
+ upload_to_s3(
+ bucket: 'a8c-apps-public-artifacts',
+ key: File.join(key_root, file_name),
+ file: File.join(PROJECT_ROOT, 'build', file_name),
+ auto_prefix: false,
+ if_exists: :fail
+ )
+ end
+end
diff --git a/ios/Sources/GutenbergKit/Gutenberg/assets/api-fetch-B54dsrci.js b/ios/Sources/GutenbergKit/Gutenberg/assets/api-fetch-B54dsrci.js
deleted file mode 100644
index 4fe11f59..00000000
--- a/ios/Sources/GutenbergKit/Gutenberg/assets/api-fetch-B54dsrci.js
+++ /dev/null
@@ -1 +0,0 @@
-import{g as o}from"./remote-dB-0pQby.js";const a=window.wp.apiFetch,{getQueryArg:u}=window.wp.url;function y(){const{siteApiRoot:e=""}=o();a.use(a.createRootURLMiddleware(e)),a.use(m),a.use(h),a.use(f),a.use(w),a.use(b),a.use(g),a.use(a.createPreloadingMiddleware(_))}function m(e,t){return e.mode="cors",delete e.headers["x-wp-api-fetch-from-editor"],t(e)}function h(e,t){const{siteApiNamespace:s,namespaceExcludedPaths:n}=o(),c=new RegExp(`(${s.join("|")})`);return e.path&&!n.some(i=>e.path.startsWith(i))&&!c.test(e.path)&&(e.path=e.path.replace(/^(?\/?(?:[\w.-]+\/){2})/,`$${s[0]}`)),t(e)}function f(e,t){const{authHeader:s}=o();return e.headers=e.headers||{},s&&(e.headers.Authorization=s,e.credentials="omit"),t(e)}function w(e,t){return[/^\/wp\/v2\/posts\/-?\d+/,/^\/wp\/v2\/pages\/-?\d+/].some(c=>c.test(e.path))?Promise.resolve([]):t(e)}function b(e,t){return e.path&&e.path.startsWith("/wp/v2/media")&&e.method==="POST"&&e.body instanceof FormData&&e.body.get("post")==="-1"&&e.body.delete("post"),t(e)}function g(e,t){if(e.path&&e.path.indexOf("oembed")!==-1){let c=function(){const r=document.createElement("a");return r.href=s,r.innerText=s,{html:r.outerHTML,type:"rich",provider_name:"Embed"}};const s=u(e.path,"url"),n=t(e,t);return new Promise(r=>{n.then(i=>{if(i.html){const l=document.implementation.createHTMLDocument("");l.body.innerHTML=i.html;const p=['[class="embed-youtube"]','[class="embed-vimeo"]','[class="embed-dailymotion"]','[class="embed-ted"]'].join(","),d=l.querySelector(p);i.html=d?d.innerHTML:i.html}r(i)}).catch(()=>{r(c())})})}return t(e,t)}const _={"/wp/v2/types?context=view":{body:{post:{description:"",hierarchical:!1,has_archive:!1,name:"Posts",slug:"post",taxonomies:["category","post_tag"],rest_base:"posts",rest_namespace:"wp/v2",template:[],template_lock:!1,_links:{}},page:{description:"",hierarchical:!0,has_archive:!1,name:"Pages",slug:"page",taxonomies:[],rest_base:"pages",rest_namespace:"wp/v2",template:[],template_lock:!1,_links:{}}}},"/wp/v2/types/post?context=edit":{body:{name:"Posts",slug:"post",supports:{title:!0,editor:!0,author:!0,thumbnail:!0,excerpt:!0,trackbacks:!0,"custom-fields":!0,comments:!0,revisions:!0,"post-formats":!0,autosave:!0},taxonomies:["category","post_tag"],rest_base:"posts",rest_namespace:"wp/v2",template:[],template_lock:!1}}};export{y as initializeApiFetch};
diff --git a/ios/Sources/GutenbergKit/Gutenberg/assets/api-fetch-ysXJCM4q.js b/ios/Sources/GutenbergKit/Gutenberg/assets/api-fetch-ysXJCM4q.js
deleted file mode 100644
index 5b870457..00000000
--- a/ios/Sources/GutenbergKit/Gutenberg/assets/api-fetch-ysXJCM4q.js
+++ /dev/null
@@ -1 +0,0 @@
-import{g as o}from"./index-C5imUel5.js";const a=window.wp.apiFetch,{getQueryArg:u}=window.wp.url;function y(){const{siteApiRoot:e=""}=o();a.use(a.createRootURLMiddleware(e)),a.use(m),a.use(h),a.use(f),a.use(w),a.use(b),a.use(g),a.use(a.createPreloadingMiddleware(_))}function m(e,t){return e.mode="cors",delete e.headers["x-wp-api-fetch-from-editor"],t(e)}function h(e,t){const{siteApiNamespace:s,namespaceExcludedPaths:n}=o(),c=new RegExp(`(${s.join("|")})`);return e.path&&!n.some(i=>e.path.startsWith(i))&&!c.test(e.path)&&(e.path=e.path.replace(/^(?\/?(?:[\w.-]+\/){2})/,`$${s[0]}`)),t(e)}function f(e,t){const{authHeader:s}=o();return e.headers=e.headers||{},s&&(e.headers.Authorization=s,e.credentials="omit"),t(e)}function w(e,t){return[/^\/wp\/v2\/posts\/-?\d+/,/^\/wp\/v2\/pages\/-?\d+/].some(c=>c.test(e.path))?Promise.resolve([]):t(e)}function b(e,t){return e.path&&e.path.startsWith("/wp/v2/media")&&e.method==="POST"&&e.body instanceof FormData&&e.body.get("post")==="-1"&&e.body.delete("post"),t(e)}function g(e,t){if(e.path&&e.path.indexOf("oembed")!==-1){let c=function(){const r=document.createElement("a");return r.href=s,r.innerText=s,{html:r.outerHTML,type:"rich",provider_name:"Embed"}};const s=u(e.path,"url"),n=t(e,t);return new Promise(r=>{n.then(i=>{if(i.html){const l=document.implementation.createHTMLDocument("");l.body.innerHTML=i.html;const p=['[class="embed-youtube"]','[class="embed-vimeo"]','[class="embed-dailymotion"]','[class="embed-ted"]'].join(","),d=l.querySelector(p);i.html=d?d.innerHTML:i.html}r(i)}).catch(()=>{r(c())})})}return t(e,t)}const _={"/wp/v2/types?context=view":{body:{post:{description:"",hierarchical:!1,has_archive:!1,name:"Posts",slug:"post",taxonomies:["category","post_tag"],rest_base:"posts",rest_namespace:"wp/v2",template:[],template_lock:!1,_links:{}},page:{description:"",hierarchical:!0,has_archive:!1,name:"Pages",slug:"page",taxonomies:[],rest_base:"pages",rest_namespace:"wp/v2",template:[],template_lock:!1,_links:{}}}},"/wp/v2/types/post?context=edit":{body:{name:"Posts",slug:"post",supports:{title:!0,editor:!0,author:!0,thumbnail:!0,excerpt:!0,trackbacks:!0,"custom-fields":!0,comments:!0,revisions:!0,"post-formats":!0,autosave:!0},taxonomies:["category","post_tag"],rest_base:"posts",rest_namespace:"wp/v2",template:[],template_lock:!1}}};export{y as initializeApiFetch};
diff --git a/ios/Sources/GutenbergKit/Gutenberg/assets/ar-B48uZRT7.js b/ios/Sources/GutenbergKit/Gutenberg/assets/ar-B48uZRT7.js
deleted file mode 100644
index bc465756..00000000
--- a/ios/Sources/GutenbergKit/Gutenberg/assets/ar-B48uZRT7.js
+++ /dev/null
@@ -1,12 +0,0 @@
-const e=[],t=[],o=[],s=[],a=[],i=[],n=[],r=[],l=[],c=[],d=[],u=[],p=[],h=[],m=[],b=[],g=[],y=[],k=[],f=[],w=[],v=[],S=[],C=[],T=[],A=[],P=[],x=[],$=[],D=[],L=[],N=[],M=["قطع"],E=["تجاهل"],I=[],R=[],B=[],F=[],z=["تعليقات"],U=[],V=["عرض"],W=[],H=[],G=[],O=["الصفحة الرئيسية"],Y=[],q=[],j=[],J=[],Q=[],X=[],K=[],_=[],Z=[],ee=[],te=[],oe=[],se=[],ae=[],ie=[],ne=["صفوف"],re=[],le=[],ce=[],de=[],ue=[],pe=[],he=[],me=[],be=[],ge=[],ye=[],ke=[],fe=[],we=[],ve=[],Se=[],Ce=[],Te=[],Ae=["البريد الإلكتروني"],Pe=["المصدر"],xe=["الخطوط"],$e=[],De=[],Le=[],Ne=[],Me=[],Ee=["فصل"],Ie=["كلمة المرور"],Re=["هامش"],Be=["الأعداد"],Fe=[],ze=[],Ue=[],Ve=["بإنتظار المراجعة"],We=["اقتراحات"],He=["اللغة"],Ge=["تفعيل"],Oe=["الدقة"],Ye=["إدراج"],qe=["Openverse"],je=["الظل"],Je=["وسط"],Qe=["الموضع"],Xe=["مثتبة"],Ke=["التلده"],_e=["CSS"],Ze=["مقاطع فيديو"],et=[],tt=["إنقاص"],ot=["زيادة"],st=["كلمات توضيحية"],at=["نمط"],it=["مقبض"],nt=["XXL"],rt=["الخط"],lt=["مقيده"],ct=["ع6"],dt=["ع5"],ut=["ع4"],pt=["ع3"],ht=["ع2"],mt=["ع1"],bt=["الفئات"],gt=["تمرير المؤشر"],yt=["إلغاء تعيين"],kt=["الآن"],ft=["الآباء"],wt=["اللاحقة"],vt=["البادئة"],St=["يقول"],Ct=["استجابة"],Tt=["الردود"],At=["كُدس"],Pt=["أسبوع"],xt=["غير صالح"],$t=["قفل"],Dt=["الغاء القفل"],Lt=["معاينة"],Nt=["تمّ التنفيذ"],Mt=["أيقونة"],Et=["حذف"],It=["إجراءات"],Rt=["إعادة تسمية"],Bt=["Aa"],Ft=["الأنماط"],zt=["قوائم"],Ut=["رد"],Vt=["العناصر"],Wt=["القوائم الفرعية"],Ht=["دائمًا"],Gt=["العرض"],Ot=["إشارة مرجعية"],Yt=["تمييز"],qt=["طبق الألوان"],jt=["الألوان"],Jt=["السهم"],Qt=["صف"],Xt=["ضبط"],Kt=["انسياب"],_t=["الثني"],Zt=["النشر"],eo=["النمط"],to=["نصف القطر"],oo=["الهامش"],so=["التراكُب اللوني (Duotone)"],ao=["الشعار"],io=["التمييز"],no=["الظِلال"],ro=["التخطيط"],lo=["منقط"],co=["متقطع"],uo=["تخصيص"],po=["إطار"],ho=["شبكة"],mo=["المنطقة"],bo=["إضافة إقتباس/زيادة المسافة البادئة"],go=["إزالة إقتباس/إنقاص المسافة البادئة"],yo=["مرتب"],ko=["غير مرتب"],fo=["سحب"],wo=["محاذاة"],vo=["الكتابة بأحرف كبيرة"],So=["أحرف صغيرة"],Co=["أحرف كبيرة"],To=["عمودي"],Ao=["أفقي"],Po=["القوالب"],xo=["الكلمة المفتاحية"],$o=["عوامل التصفية"],Do=["زخرفة"],Lo=["فقط"],No=["استثناء"],Mo=["تضمين"],Eo=["المظهر"],Io=["التفضيلات"],Ro=["النوع"],Bo=["التسمية"],Fo=["فصول"],zo=["أوصاف"],Uo=["كلمات توضيحية"],Vo=["ترجمات"],Wo=["الوسوم"],Ho=["التفاصيل"],Go=["شعاعي"],Oo=["خطي"],Yo=["غير معروف"],qo=["أحرف"],jo=["الوصف"],Jo=["الأساس"],Qo=["كاتب"],Xo=["الأصل"],Ko=["الاسم"],_o=["صورة"],Zo=["منظر أفقي"],es=["مختلط"],ts=["يمين"],os=["يسار"],ss=["أسفل"],as=["أعلى"],is=["الحشو"],ns=["مسافة التباعد"],rs=["الإتجاه"],ls=["قص"],cs=["تدوير"],ds=["تكبير"],us=["تصميم"],ps=["نصّ"],hs=["الإشعارات"],ms=["صفحة","صفحة واحدة","صفحتان","صفحات","صفحة","صفحة"],bs=["إزاحة"],gs=["مقالات"],ys=["صفحات"],ks=["غير مصنف"],fs=["أبيض"],ws=["أسود"],vs=["أحرف علوية"],Ss=["أحرف سفلية"],Cs=["الأنماط"],Ts=["الخطوط"],As=["المحتوى "],Ps=["القائمة"],xs=["الاتصال"],$s=["حول"],Ds=["الرئيسية"],Ls=["المستخدم"],Ns=["الموقع"],Ms=["إنشاء"],Es=["سطح المكتب"],Is=["الجوال"],Rs=["الأجهزة اللوحية"],Bs=["استطلاع رأي"],Fs=["اجتماعي"],zs=["لون كامل"],Us=["النوع"],Vs=["زاوية"],Ws=["اختيار"],Hs=["قالب"],Gs=["فارغ"],Os=["الأزرار"],Ys=["الخلفية"],qs=["مساعدة"],js=["بدون عنوان"],Js=["التالي"],Qs=["السابق"],Xs=["إنهاء"],Ks=["استبدال"],_s=["أداة الإدراج"],Zs=["بودكاست"],ea=["التنقّل"],ta=["القالب"],oa=["التدرّج"],sa=["أزرق منتصف الليل"],aa=["النسخة"],ia=["الأبعاد"],na=["القوالب"],ra=["أضف"],la=["اللون"],ca=["مُخصص"],da=["مسودة"],ua=["تخطي"],pa=["الروابط"],ha=["القائمة"],ma=["تذييل"],ba=["مجموعة"],ga=["فئة"],ya=["افتراضي"],ka=["بحث"],fa=["التقويم"],wa=["رجوع"],va=["كتاب إلكتروني"],Sa=["تحته خط"],Ca=["صورة مصغرة"],Ta=["تعليقات توضيحية"],Aa=["وسائط"],Pa=["وسائط"],xa=["الأنماط"],$a=["عام"],Da=["الخيارات"],La=["دقائق"],Na=["ساعات"],Ma=["الوقت"],Ea=["السنة"],Ia=["اليوم"],Ra=["ديسمبر"],Ba=["نوفمبر"],Fa=["أكتوبر"],za=["سبتمبر"],Ua=["أغسطس"],Va=["يوليو"],Wa=["يونيو"],Ha=["مايو"],Ga=["أبريل"],Oa=["مارس"],Ya=["فبراير"],qa=["يناير"],ja=["الشهر"],Ja=["غلاف"],Qa=["ضخم"],Xa=["متوسط"],Ka=["عادي"],_a=["العناصر"],Za=["الصورة الرمزية Avatar"],ei=["عرض"],ti=["HTML"],oi=["غِشاء"],si=["فاصلة علوية مائلة Backtick"],ai=["فترة"],ii=["فاصلة"],ni=["الحالي"],ri=["العنوان"],li=["إنشاء"],ci=["معارض"],di=["XL"],ui=["L"],pi=["M"],hi=["S"],mi=["صغير"],bi=["تم التجاهل"],gi=["تلقائي"],yi=["تحميل مسبق"],ki=["الدعم"],fi=["الأرشيف"],wi=["كبير"],vi=["ملف"],Si=["عمود"],Ci=["حلقة"],Ti=["تشغيل تلقائي"],Ai=["حفظ تلقائي"],Pi=["عنوان فرعي"],xi=["موافق"],$i=["إزالة الربط"],Di=["تعدد الصفحات"],Li=["الارتفاع"],Ni=["العرض"],Mi=["متقدم"],Ei=["مجدول"],Ii=["الإضافات"],Ri=["فقرات"],Bi=["عناوين"],Fi=["كلمات"],zi=["عام"],Ui=["خاص"],Vi=["عنصر"],Wi=["وسم"],Hi=["فوراً"],Gi=["جاري الحفظ"],Oi=["منشور"],Yi=["جدولة"],qi=["تحديث"],ji=["نسخ"],Ji=["محادثة"],Qi=["الحالة"],Xi=["قياسي"],Ki=["الجانب"],_i=["ترتيب"],Zi=["تم الحفظ"],en=["التضمينات"],tn=["مكوّنات"],on=["تراجع"],sn=["إعادة"],an=["تكرار"],nn=["إزالة"],rn=["الظهور"],ln=["المكوّن"],cn=["المستند"],dn=["أدوات"],un=["المُحرر"],pn=["الإعدادات"],hn=["إعادة تعيين"],mn=["إيقاف"],bn=[],gn=["مساءً"],yn=["صباحًا"],kn=["رابط الـ"],fn=["إرسال"],wn=["إغلاق"],vn=["رابط"],Sn=["نصّ مشطوب"],Cn=["مائل"],Tn=["عريض"],An=["تصنيف"],Pn=["تحديد"],xn=["فيديو"],$n=["جدول"],Dn=["كود قصير"],Ln=["فاصل"],Nn=["اقتباس"],Mn=["فقرة"],En=["قائمة"],In=["صورة"],Rn=["الحجم"],Bn=["صورة"],Fn=["معاينة"],zn=["عنوان"],Un=["صور"],Vn=["بدون"],Wn=["معرض"],Hn=["المزيد"],Gn=["تقليدي"],On=["فيديو"],Yn=["صوتيات"],qn=["موسيقى"],jn=["صورة"],Jn=["مدونة"],Qn=["المقالة"],Xn=["أعمدة"],Kn=["التجارب"],_n=["كود"],Zn=["تصنيفات"],er=["زر"],tr=["تطبيق"],or=["إلغاء"],sr=["تحرير"],ar=["صوت"],ir=["مسح"],nr=["ودجات"],rr=["الكُتّاب"],lr=["الاسم اللطيف"],cr=["التعليق"],dr=["مناقشة"],ur=["المقتطف"],pr=["نشر"],hr=["البيانات الوصفية"],mr=["حفظ"],br=["المراجعات"],gr=["وثائق المساعدة"],yr=["Gutenberg"],kr=["عرض توضيحي"],fr={100:["100"],"block descriptionDisplay a custom date.":[],"block descriptionDisplays a foldable layout that groups content in collapsible sections.":[],"block descriptionContains the hidden or revealed content beneath the heading.":[],"block descriptionWraps the heading and panel in one unit.":[],"block descriptionDisplays a heading that toggles the accordion panel.":[],"Media items":[],"Search media":[],"Select Media":[],"Are you sure you want to delete this note? This will also delete all of this note's replies.":[],"Revisions (%d)":[],"paging%1$d of %2$d":[],"%d item":[],"Color Variations":[],"Shadow Type":[],"Font family to uninstall is not defined.":[],"Select Featured Image":[],"Active when used":[],"Registered Templates":[],"Failed to create page. Please try again.":[],"%s page created successfully.":[],"Full content":[],"No content":[],"Display content":[],"The exact type of breadcrumbs shown will vary automatically depending on the page in which this block is displayed. In the specific case of a hierarchical post type with taxonomies, the breadcrumbs can either reflect its post hierarchy (default) or the hierarchy of its assigned taxonomy terms.":[],"Prefer taxonomy terms":[],"The text will resize to fit its container, resetting other font size settings.":[],"Enables a new media modal experience powered by Data Views for improved media library management.":[],"Data Views: new media modal":[],"block keywordterm title":[],"block descriptionDisplays the name of a taxonomy term.":[],"block titleTerm Name":[],"block descriptionDisplays the post count of a taxonomy term.":[],"block titleTerm Count":[],"block keywordmathematics":[],"block keywordlatex":[],"block keywordformula":[],"block descriptionDisplay mathematical notation using LaTeX.":[],"block titleMath":[],"block descriptionDisplay a breadcrumb trail for hierarchical post types or based on taxonomy terms.":[],"block titleBreadcrumbs":[],"Overrides currently don't support image links. Remove the link first before enabling overrides.":[],Math:[],"CSS classes":[],"Close Notes":[],Notes:e,"View notes":[],"New note":[],"Add note":[],Reopened:t,"Marked as resolved":[],"Edit note %1$s by %2$s":[],"Reopen noteReopen":[],"Back to block":[],"Add new note":[],"Note: %s":[],"Only logged in users can see Notes.":[],"No notes available.":[],"Note deleted.":[],"Note reopened.":[],"Note added.":[],"Reply added.":[],Note:o,"You are about to duplicate a bundled template. Changes will not be live until you activate the new template.":[],'Do you want to activate this "%s" template?':[],"template typeCustom":[],"Created templates":[],"Reset view":[],"Unknown error when running custom validation.":[],"No elements found":[],"Term template block display settingGrid view":[],"Term template block display settingList view":[],"Display the terms' names and number of posts assigned to each term.":[],"Name & Count":[],"Display the terms' names.":[],"When specific terms are selected, only those are displayed.":[],"When specific terms are selected, the order is based on their selection order.":[],"Selected terms":[],"Show nested terms":[],"Display terms based on specific criteria.":[],"Display terms based on the current taxonomy archive. For hierarchical taxonomies, shows children of the current term. For non-hierarchical taxonomies, shows all terms.":[],"Make term name a link":[],"Change bracket type":[],"Angle brackets":[],"Curly brackets":[],"Square brackets":[],"Round brackets":[],"No brackets":[],"e.g., x^2, \\frac{a}{b}":[],"LaTeX math syntax":[],"Set a consistent aspect ratio for all images in the gallery.":[],"All gallery images updated to aspect ratio: %s":[],"Comments block: You’re currently using the legacy version of the block. The following is just a placeholder - the final styling will likely look different. For a better representation and more customization options, switch the block to its editable mode.":[],"Show home link":[],Ancestor:s,"Source not registered":[],"Not connected":[],"No sources available":[],"Text will resize to fit its container.":[],"Fit text":[],"Allowed Blocks":[],"Specify which blocks are allowed inside this container.":[],"Select which blocks can be added inside this container.":[],"Manage allowed blocks":[],"Block hidden. You can access it via the List View (%s).":[],"Blocks hidden. You can access them via the List View (%s).":[],"Show or hide the selected block(s).":[],"Type of the comment.":[],"Creating comment failed.":[],"Comment field exceeds maximum length allowed.":[],"Creating a comment requires valid author name and email values.":[],"Invalid comment content.":[],"Cannot create a comment with that type.":[],"Sorry, you are not allowed to read this comment.":[],"Query parameter not permitted: %s":[],"Sorry, you are not allowed to read comments without a post.":[],"Sorry, this post type does not support notes.":[],"Note resolution status":[],Breadcrumbs:a,"block descriptionShow minutes required to finish reading the post. Can also show a word count.":[],"Reply to note %1$s by %2$s":[],"Reopen & Reply":[],"Original block deleted.":[],"Original block deleted. Note: %s":[],"Note date full date formatF j, Y g:i a":[],"Don't allow link notifications from other blogs (pingbacks and trackbacks) on new articles.":[],"Don't allow":[],"Allow link notifications from other blogs (pingbacks and trackbacks) on new articles.":[],Allow:i,"Trackbacks & Pingbacks":[],"Template activation failed.":[],"Template activated.":[],"Activating template…":[],"Template Type":[],"Compatible Theme":[],Inactive:n,Active:r,"Active templates":[],Deactivate:l,"Value must be a number.":[],"Show the number of words in the post.":[],"Word Count":[],"Show minutes required to finish reading the post.":[],"Time to Read":[],"Display as range":[],"Turns reading time range display on or offDisplay as range":[],item:c,term:d,tag:u,category:p,"Suspendisse commodo lacus, interdum et.":[],"Lorem ipsum dolor sit amet, consectetur.":[],"Block is hidden.":[],Visible:h,"Unsync and edit":[],"Synced with the selected %s.":[],"%s character":[],"Range of minutes to read%1$s–%2$s minutes":[],"block keywordtags":[],"block keywordtaxonomy":[],"block keywordterms":[],"block titleTerms Query":[],"block descriptionContains the block elements used to render a taxonomy term, like the name, description, and more.":[],"block titleTerm Template":[],Count:m,"Parent ID":[],"Term ID":[],"An error occurred while performing an update.":[],"+%s more participant":[],"100+ participants":[],"+%s":[],"100+":[],"%s more reply":[],"Show password":[],"Hide password":[],"Date time":[],"Value must be a valid color.":[],"Open custom CSS":[],"Go to: Patterns":[],"Go to: Templates":[],"Go to: Navigation":[],"Go to: Styles":[],"Go to: Template parts":[],"Go to: %s":[],"No terms found.":[],"Term Name":[],"Limit the number of terms you want to show. To show all terms, use 0 (zero).":[],"Max terms":[],"Count, low to high":[],"Count, high to low":[],"Name: Z → A":[],"Name: A → Z":[],"If unchecked, the page will be created as a draft.":[],"Publish immediately":[],"Create a new page to add to your Navigation.":[],"Create page":[],"Edit contents":[],"The Link Relation attribute defines the relationship between a linked resource and the current document.":[],"Link relation":[],"Blog home":[],Attachment:b,Post:g,"When patterns are inserted, default to a simplified content only mode for editing pattern content.":[],"contentOnly: Make patterns contentOnly by default upon insertion":[],"block bindings sourceTerm Data":[],"Updating failed because you were offline.":[],"Scheduling failed because you were offline.":[],"Publishing failed because you were offline.":[],"Choose pattern":[],"Could not get a valid response from the server.":[],"Unable to connect. Please check your Internet connection.":[],"block titleAccordion":[],"block titleAccordion Panel":[],"block titleAccordion Heading":[],"block titleAccordion Item":[],"Automatically load more content as you scroll, instead of showing pagination links.":[],"Enable infinite scroll":[],"Play inline enabled because of Autoplay.":[],"Display the post type label based on the queried object.":[],"Post Type Label":[],"Show post type label":[],"Post Type: Name":[],"Accordion title":[],"Accordion content will be displayed by default.":[],"Icon Position":[],"Display a plus icon next to the accordion header.":[],"Automatically close accordions when a new one is opened.":[],"Auto-close":[],"Set custom border radius":[],"Use border radius preset":[],'Post Type: "%s"':[],"Add Category":[],"Add Term":[],"Add Tag":[],"Click item: %s":[],To:y,From:k,"Year to date":[],"Last year":[],"Month to date":[],"Last 30 days":[],"Last 7 days":[],"Past month":[],"Past week":[],Yesterday:f,Today:w,"Every value must be a string.":[],"Value must be an array.":[],"Value must be true, false, or undefined":[],"Value must be an integer.":[],"Value must be a valid email address.":[],"Add page":[],Optional:v,"social link block variation nameSoundCloud":[],"Display a post's publish date.":[],"Publish Date":[],'"Read more" text':[],"Poster image preview":[],"Edit or replace the poster image.":[],"Set poster image":[],"social link block variation nameYouTube":[],"social link block variation nameYelp":[],"social link block variation nameX":[],"social link block variation nameWhatsApp":[],"social link block variation nameWordPress":[],"social link block variation nameVK":[],"social link block variation nameVimeo":[],"social link block variation nameTwitter":[],"social link block variation nameTwitch":[],"social link block variation nameTumblr":[],"social link block variation nameTikTok":[],"social link block variation nameThreads":[],"social link block variation nameTelegram":[],"social link block variation nameSpotify":[],"social link block variation nameSnapchat":[],"social link block variation nameSkype":[],"social link block variation nameShare Icon":[],"social link block variation nameReddit":[],"social link block variation namePocket":[],"social link block variation namePinterest":[],"social link block variation namePatreon":[],"social link block variation nameMedium":[],"social link block variation nameMeetup":[],"social link block variation nameMastodon":[],"social link block variation nameMail":[],"social link block variation nameLinkedIn":[],"social link block variation nameLast.fm":[],"social link block variation nameInstagram":[],"social link block variation nameGravatar":[],"social link block variation nameGitHub":[],"social link block variation nameGoogle":[],"social link block variation nameGoodreads":[],"social link block variation nameFoursquare":[],"social link block variation nameFlickr":[],"social link block variation nameRSS Feed":[],"social link block variation nameFacebook":[],"social link block variation nameEtsy":[],"social link block variation nameDropbox":[],"social link block variation nameDribbble":[],"social link block variation nameDiscord":[],"social link block variation nameDeviantArt":[],"social link block variation nameCodePen":[],"social link block variation nameLink":[],"social link block variation nameBluesky":[],"social link block variation nameBehance":[],"social link block variation nameBandcamp":[],"social link block variation nameAmazon":[],"social link block variation name500px":[],"block descriptionDescribe in a few words what this site is about. This is important for search results, sharing on social media, and gives overall clarity to visitors.":[],"There is no poster image currently selected.":[],"The current poster image url is %s.":[],"Comments pagination":[],"paging
Page
%1$s
of %2$d
":[],"%1$s is over: %2$s ago":[],"%1$s is in the past: %2$s":[],"%1$s between (inc): %2$s and %3$s":[],"%1$s is on or after: %2$s":[],"%1$s is on or before: %2$s":[],"%1$s is after: %2$s":[],"%1$s is before: %2$s":[],"%1$s starts with: %2$s":[],"%1$s doesn't contain: %2$s":[],"%1$s contains: %2$s":[],"%1$s is greater than or equal to: %2$s":[],"%1$s is less than or equal to: %2$s":[],"%1$s is greater than: %2$s":[],"%1$s is less than: %2$s":[],"Max.":[],"Min.":[],"The max. value must be greater than the min. value.":[],Unit:S,"Years ago":[],"Months ago":[],"Weeks ago":[],"Days ago":[],Years:C,Months:T,Weeks:A,Days:P,False:x,True:$,Over:D,"In the past":[],"Not on":[],"Between (inc)":[],"Starts with":[],"Doesn't contain":[],"After (inc)":[],"Before (inc)":[],After:L,Before:N,"Greater than or equal":[],"Less than or equal":[],"Greater than":[],"Less than":[],"%s, selected":[],"Go to the Previous Month":[],"Go to the Next Month":[],"Today, %s":[],"Date range calendar":[],"Date calendar":[],"Interactivity API: Full-page client-side navigation":[],"Set as default track":[],"Icon Size":[],"Icon size":[],"Only select if the separator conveys important information and should be announced by screen readers.":[],"Sort and filter":[],"Write summary. Press Enter to expand or collapse the details.":[],"Default ()":[],"The