Signed-off-by: Matt Bruce <mbrucedogs@gmail.com>
This commit is contained in:
parent
ac8501ff8c
commit
01fcaa9731
@ -880,7 +880,6 @@
|
||||
}
|
||||
},
|
||||
"alarm.row.sound_prefix" : {
|
||||
"extractionState": "extracted_with_value",
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
@ -904,7 +903,6 @@
|
||||
},
|
||||
"alarm.snooze.duration_minutes" : {
|
||||
"comment" : "A localized string that formats the snooze duration as a number of minutes.",
|
||||
"extractionState": "extracted_with_value",
|
||||
"isCommentAutoGenerated" : true,
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -1467,7 +1465,6 @@
|
||||
},
|
||||
"clock.debug.orientation" : {
|
||||
"comment" : "A label for the orientation of the device.",
|
||||
"extractionState": "extracted_with_value",
|
||||
"isCommentAutoGenerated" : true,
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -1490,6 +1487,50 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"clock.debug.orientation.landscape" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Landscape"
|
||||
}
|
||||
},
|
||||
"es-MX" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Horizontal"
|
||||
}
|
||||
},
|
||||
"fr-CA" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Paysage"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"clock.debug.orientation.portrait" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Portrait"
|
||||
}
|
||||
},
|
||||
"es-MX" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Vertical"
|
||||
}
|
||||
},
|
||||
"fr-CA" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Mode portrait"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"clock.debug.portrait" : {
|
||||
"comment" : "A key for a localized string that describes whether the view is currently in portrait mode.",
|
||||
"extractionState" : "extracted_with_value",
|
||||
@ -5030,50 +5071,6 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"clock.debug.orientation.landscape": {
|
||||
"localizations": {
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Landscape"
|
||||
}
|
||||
},
|
||||
"es-MX": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Horizontal"
|
||||
}
|
||||
},
|
||||
"fr-CA": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Paysage"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"clock.debug.orientation.portrait": {
|
||||
"localizations": {
|
||||
"en": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Portrait"
|
||||
}
|
||||
},
|
||||
"es-MX": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Vertical"
|
||||
}
|
||||
},
|
||||
"fr-CA": {
|
||||
"stringUnit": {
|
||||
"state": "translated",
|
||||
"value": "Mode portrait"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"version" : "1.1"
|
||||
|
||||
174
scripts/run-screenshot-matrix.sh
Executable file
174
scripts/run-screenshot-matrix.sh
Executable file
@ -0,0 +1,174 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
|
||||
WORKSPACE_ROOT="$(cd "${PROJECT_ROOT}/.." && pwd)"
|
||||
|
||||
PROJECT_PATH="${PROJECT_ROOT}/TheNoiseClock.xcodeproj"
|
||||
SCHEME="${SCHEME:-TheNoiseClock}"
|
||||
TEST_IDENTIFIER="${TEST_IDENTIFIER:-TheNoiseClockUITests/TheNoiseClockUITests/testAppStoreScreenshots_iPhone69}"
|
||||
RUNTIME_ID="${RUNTIME_ID:-com.apple.CoreSimulator.SimRuntime.iOS-26-2}"
|
||||
OUTPUT_ROOT="${OUTPUT_ROOT:-${WORKSPACE_ROOT}/Screenshots}"
|
||||
EXPECTED_COUNT=5
|
||||
|
||||
expected_files=(
|
||||
"01-clock-view-portrait.png"
|
||||
"02-clock-view-landscape.png"
|
||||
"03-alarms-view-portrait.png"
|
||||
"04-noise-view-portrait.png"
|
||||
"05-clock-settings-portrait.png"
|
||||
)
|
||||
|
||||
locales=(
|
||||
"fr-CA|fr|CA"
|
||||
"es-MX|es|MX"
|
||||
)
|
||||
|
||||
devices=(
|
||||
"iPhone-6.3|AppStore iPhone 17 Pro 26.2|com.apple.CoreSimulator.SimDeviceType.iPhone-17-Pro"
|
||||
"iPhone-6.5|AppStore iPhone 11 Pro Max 26.2|com.apple.CoreSimulator.SimDeviceType.iPhone-11-Pro-Max"
|
||||
"iPhone-6.9|AppStore iPhone 17 Pro Max 26.2|com.apple.CoreSimulator.SimDeviceType.iPhone-17-Pro-Max"
|
||||
"iPad-13|AppStore iPad Pro 13-inch (M5) 26.2|com.apple.CoreSimulator.SimDeviceType.iPad-Pro-13-inch-M5-12GB"
|
||||
)
|
||||
|
||||
simctl_json() {
|
||||
xcrun simctl list devices available -j
|
||||
}
|
||||
|
||||
find_sim_udid() {
|
||||
local runtime_id="$1"
|
||||
local name="$2"
|
||||
simctl_json | jq -r --arg runtime_id "$runtime_id" --arg name "$name" '
|
||||
.devices[$runtime_id][]? | select(.isAvailable == true and .name == $name) | .udid
|
||||
' | head -n1
|
||||
}
|
||||
|
||||
ensure_simulator() {
|
||||
local name="$1"
|
||||
local device_type="$2"
|
||||
local runtime_id="$3"
|
||||
local udid
|
||||
|
||||
udid="$(find_sim_udid "$runtime_id" "$name")"
|
||||
if [[ -n "$udid" ]]; then
|
||||
echo "$udid"
|
||||
return 0
|
||||
fi
|
||||
|
||||
udid="$(xcrun simctl create "$name" "$device_type" "$runtime_id")"
|
||||
echo "$udid"
|
||||
}
|
||||
|
||||
validate_output_folder() {
|
||||
local folder="$1"
|
||||
|
||||
local png_count
|
||||
png_count="$(find "$folder" -maxdepth 1 -name '*.png' | wc -l | tr -d ' ')"
|
||||
if [[ "$png_count" -ne "$EXPECTED_COUNT" ]]; then
|
||||
echo "Expected ${EXPECTED_COUNT} screenshots in ${folder}, found ${png_count}." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
local missing=0
|
||||
for file_name in "${expected_files[@]}"; do
|
||||
if [[ ! -f "${folder}/${file_name}" ]]; then
|
||||
echo "Missing ${folder}/${file_name}" >&2
|
||||
missing=1
|
||||
fi
|
||||
done
|
||||
if [[ "$missing" -ne 0 ]]; then
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
export_attachments_to_output_folder() {
|
||||
local result_bundle="$1"
|
||||
local folder="$2"
|
||||
local attachments_tmp
|
||||
attachments_tmp="$(mktemp -d "/tmp/noiseclock-attachments.XXXXXX")"
|
||||
|
||||
xcrun xcresulttool export attachments \
|
||||
--path "$result_bundle" \
|
||||
--output-path "$attachments_tmp" >/dev/null
|
||||
|
||||
local manifest_path="${attachments_tmp}/manifest.json"
|
||||
if [[ ! -f "$manifest_path" ]]; then
|
||||
echo "Missing attachment manifest at ${manifest_path}" >&2
|
||||
rm -rf "$attachments_tmp"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local missing=0
|
||||
for file_name in "${expected_files[@]}"; do
|
||||
local base_name="${file_name%.png}"
|
||||
local exported_name
|
||||
exported_name="$(jq -r --arg base_name "$base_name" '
|
||||
[.[].attachments[]?
|
||||
| select((.suggestedHumanReadableName // "") | startswith($base_name + "_"))
|
||||
| .exportedFileName][0] // empty
|
||||
' "$manifest_path")"
|
||||
|
||||
if [[ -z "$exported_name" || ! -f "${attachments_tmp}/${exported_name}" ]]; then
|
||||
echo "Missing exported attachment for ${file_name} in ${result_bundle}" >&2
|
||||
missing=1
|
||||
continue
|
||||
fi
|
||||
|
||||
cp "${attachments_tmp}/${exported_name}" "${folder}/${file_name}"
|
||||
done
|
||||
|
||||
if [[ "$missing" -ne 0 ]]; then
|
||||
rm -rf "$attachments_tmp"
|
||||
return 1
|
||||
fi
|
||||
|
||||
rm -rf "$attachments_tmp"
|
||||
}
|
||||
|
||||
echo "Using project: ${PROJECT_PATH}"
|
||||
echo "Using scheme: ${SCHEME}"
|
||||
echo "Output root: ${OUTPUT_ROOT}"
|
||||
echo "Runtime: ${RUNTIME_ID}"
|
||||
|
||||
mkdir -p "$OUTPUT_ROOT"
|
||||
|
||||
for locale_entry in "${locales[@]}"; do
|
||||
IFS='|' read -r locale_folder language_code region_code <<< "$locale_entry"
|
||||
echo ""
|
||||
echo "=== Locale ${locale_folder} (${language_code}-${region_code}) ==="
|
||||
|
||||
for device_entry in "${devices[@]}"; do
|
||||
IFS='|' read -r device_folder sim_name device_type <<< "$device_entry"
|
||||
echo "--- Device ${device_folder} (${sim_name}) ---"
|
||||
|
||||
udid="$(ensure_simulator "$sim_name" "$device_type" "$RUNTIME_ID")"
|
||||
output_dir="${OUTPUT_ROOT}/${locale_folder}/${device_folder}"
|
||||
result_bundle="/tmp/TheNoiseClock-${locale_folder}-${device_folder}.xcresult"
|
||||
|
||||
rm -rf "$result_bundle"
|
||||
mkdir -p "$output_dir"
|
||||
rm -f "${output_dir}"/*.png
|
||||
|
||||
xcrun simctl shutdown "$udid" >/dev/null 2>&1 || true
|
||||
xcrun simctl erase "$udid" >/dev/null 2>&1 || true
|
||||
|
||||
SCREENSHOT_OUTPUT_DIR="$output_dir" xcodebuild \
|
||||
-project "$PROJECT_PATH" \
|
||||
-scheme "$SCHEME" \
|
||||
-destination "platform=iOS Simulator,id=${udid}" \
|
||||
-testLanguage "$language_code" \
|
||||
-testRegion "$region_code" \
|
||||
-only-testing:"${TEST_IDENTIFIER}" \
|
||||
-parallel-testing-enabled NO \
|
||||
-resultBundlePath "$result_bundle" \
|
||||
test
|
||||
|
||||
export_attachments_to_output_folder "$result_bundle" "$output_dir"
|
||||
validate_output_folder "$output_dir"
|
||||
echo "Saved ${EXPECTED_COUNT} screenshots to ${output_dir}"
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "Screenshot matrix completed successfully."
|
||||
51
scripts/validate-localization-keys.sh
Executable file
51
scripts/validate-localization-keys.sh
Executable file
@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Validates that .xcstrings keys follow key-only convention:
|
||||
# lower_snake segments separated by dots
|
||||
# e.g. "settings.display.section_title"
|
||||
#
|
||||
# Usage:
|
||||
# scripts/validate-localization-keys.sh
|
||||
# scripts/validate-localization-keys.sh path/to/Localizable.xcstrings [...]
|
||||
|
||||
if ! command -v jq >/dev/null 2>&1; then
|
||||
echo "error: 'jq' is required but not installed." >&2
|
||||
exit 2
|
||||
fi
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
|
||||
if [[ $# -gt 0 ]]; then
|
||||
files=("$@")
|
||||
else
|
||||
files=("$repo_root/TheNoiseClock/Localizable.xcstrings")
|
||||
fi
|
||||
|
||||
key_regex='^[a-z0-9_]+(\.[a-z0-9_]+)+$'
|
||||
had_error=0
|
||||
|
||||
for file in "${files[@]}"; do
|
||||
if [[ ! -f "$file" ]]; then
|
||||
echo "error: file not found: $file" >&2
|
||||
had_error=1
|
||||
continue
|
||||
fi
|
||||
|
||||
invalid_keys="$(
|
||||
jq -r '.strings | keys[]' "$file" | rg -v "$key_regex" || true
|
||||
)"
|
||||
|
||||
if [[ -n "$invalid_keys" ]]; then
|
||||
echo "error: invalid localization keys in $file" >&2
|
||||
echo "$invalid_keys" | sed 's/^/ - /' >&2
|
||||
had_error=1
|
||||
else
|
||||
echo "ok: $file"
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $had_error -ne 0 ]]; then
|
||||
exit 1
|
||||
fi
|
||||
|
||||
Loading…
Reference in New Issue
Block a user