Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Scripts/check_fork_identity.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,8 @@ readonly app_id="dev.jacobcx.Xcodes"
readonly tests_id="dev.jacobcx.Xcodes.Tests"
readonly helper_id="dev.jacobcx.Xcodes.Helper"
readonly team_id="K2648T24P4"
readonly marketing_version="4.1.2"
readonly build_number="50"
readonly marketing_version="4.1.3"
readonly build_number="51"
readonly app_copyright="Fork contributions © 2026 JacobCXDev. Upstream contributors retain their copyrights."
# shellcheck disable=SC2016 # Xcode expands this build-setting literal, not the shell.
readonly app_requirement='identifier "dev.jacobcx.Xcodes" and info [CFBundleShortVersionString] >= "1.0.0" and anchor apple generic and certificate leaf[subject.OU] = "$(CODE_SIGNING_SUBJECT_ORGANIZATIONAL_UNIT)"'
Expand Down
27 changes: 3 additions & 24 deletions Scripts/check_localizations.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,25 +5,6 @@
catalog_path = ARGV.fetch(0, File.expand_path("../Xcodes/Resources/Localizable.xcstrings", __dir__))
catalog = JSON.parse(File.read(catalog_path))
languages = %w[ar ca de el es fi fr hi it ja ko nl pl pt-BR ru th tr uk zh-Hans zh-Hant].freeze
established_languages = languages - %w[ar th]
baseline_keys = %w[AutomaticallyCreateBetaSymbolicLink AutomaticallyCreateBetaSymbolicLinkDescription].freeze
arabic_thai_baseline_keys = [
"An error occurred",
"Architecture",
"AutomaticallyCreateBetaSymbolicLink",
"AutomaticallyCreateBetaSymbolicLinkDescription",
"Category",
"Dismiss",
"FilterArchitecturesDescription",
"Installed Only",
"Open Browser",
"Paste redirected URL",
"Signing out...",
].freeze
allowed_missing = (
baseline_keys.product(established_languages) +
arabic_thai_baseline_keys.product(%w[ar th])
).map { |key, language| "#{key}:#{language}" }.sort.freeze

translated = lambda do |localization|
if localization.key?("stringUnit")
Expand Down Expand Up @@ -118,11 +99,9 @@
"GroupXcodeVersionsInList:#{language} expected #{expected_value.inspect}, got #{actual_value.inspect}" unless actual_value == expected_value
end

unexpected = missing - allowed_missing
resolved = allowed_missing - missing
errors = []
errors << "New missing or unreviewed translations:\n #{unexpected.join("\n ")}" unless unexpected.empty?
errors << "Localization baseline is stale; remove resolved entries:\n #{resolved.join("\n ")}" unless resolved.empty?
errors << "Supported localization languages do not match the grouping contract" unless languages.sort == (required_grouping_values.keys - ["en"]).sort
errors << "Missing or unreviewed translations:\n #{missing.join("\n ")}" unless missing.empty?
errors << "Legacy Apple ID terminology remains:\n #{legacy_terminology.join("\n ")}" unless legacy_terminology.empty?
errors << "Legacy localization keys remain:\n #{forbidden_keys.join("\n ")}" unless forbidden_keys.empty?
errors << "Required localization keys are missing:\n #{required_keys.join("\n ")}" unless required_keys.empty?
Expand All @@ -133,4 +112,4 @@
exit 1
end

puts "Localization contract passed with #{allowed_missing.length} explicitly tracked gaps"
puts "Localization contract passed with no missing translations"
6 changes: 5 additions & 1 deletion Scripts/test_fork_identity_guard.sh
Original file line number Diff line number Diff line change
Expand Up @@ -108,11 +108,15 @@ if "$fixture_root/Scripts/check_fork_identity.sh" >/dev/null 2>&1; then
exit 1
fi

cp "$repo_root/Xcodes/Resources/Info.plist" "$fixture_root/Xcodes/Resources/Info.plist"
cp "$repo_root/Xcodes/Frontend/Preferences/UpdatesPreferencePane.swift" "$fixture_root/Xcodes/Frontend/Preferences/"
"$fixture_root/Scripts/check_fork_identity.sh" >/dev/null

cp \
"$repo_root/Xcodes.xcodeproj/project.pbxproj" \
"$fixture_root/Xcodes.xcodeproj/project.pbxproj"
perl -0pi -e \
's/MARKETING_VERSION = 4\.0\.5;/MARKETING_VERSION = 4.0.4;/g' \
's/MARKETING_VERSION = [^;]+;/MARKETING_VERSION = 0.0.0;/g or die "No marketing version found to mutate\n"' \
"$fixture_root/Xcodes.xcodeproj/project.pbxproj"

if "$fixture_root/Scripts/check_fork_identity.sh" >/dev/null 2>&1; then
Expand Down
4 changes: 2 additions & 2 deletions Scripts/test_localization_contract.sh
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,8 @@ expect_failure new_arabic_gap \
'path = ARGV.fetch(0); data = JSON.parse(File.read(path)); data["strings"]["AutomaticallyCreateSymbolicLink"]["localizations"].delete("ar"); File.write(path, JSON.pretty_generate(data))'
expect_failure new_thai_gap \
'path = ARGV.fetch(0); data = JSON.parse(File.read(path)); data["strings"]["AutomaticallyCreateSymbolicLink"]["localizations"].delete("th"); File.write(path, JSON.pretty_generate(data))'
expect_failure stale_baseline \
'path = ARGV.fetch(0); data = JSON.parse(File.read(path)); data["strings"]["AutomaticallyCreateBetaSymbolicLink"]["localizations"]["de"] = { "stringUnit" => { "state" => "translated", "value" => "Beta-Link" } }; File.write(path, JSON.pretty_generate(data))'
expect_failure removed_beta_translation \
'path = ARGV.fetch(0); data = JSON.parse(File.read(path)); data["strings"]["AutomaticallyCreateBetaSymbolicLink"]["localizations"].delete("de"); File.write(path, JSON.pretty_generate(data))'
expect_failure legacy_apple_id_copy \
'path = ARGV.fetch(0); data = JSON.parse(File.read(path)); data["strings"]["AccessGranted"]["localizations"]["en"]["stringUnit"]["value"] = "Signed in with your Apple ID."; File.write(path, JSON.pretty_generate(data))'
expect_failure shifted_grouping_translation \
Expand Down
12 changes: 6 additions & 6 deletions Xcodes.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1094,7 +1094,7 @@
CODE_SIGN_IDENTITY = "-";
CODE_SIGN_STYLE = Manual;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 50;
CURRENT_PROJECT_VERSION = 51;
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
DEVELOPMENT_TEAM = K2648T24P4;
ENABLE_HARDENED_RUNTIME = NO;
Expand All @@ -1106,7 +1106,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 4.1.2;
MARKETING_VERSION = 4.1.3;
PRODUCT_BUNDLE_IDENTIFIER = dev.jacobcx.Xcodes;
PRODUCT_NAME = Xcodes;
PROVISIONING_PROFILE_SPECIFIER = "";
Expand Down Expand Up @@ -1347,7 +1347,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 50;
CURRENT_PROJECT_VERSION = 51;
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
DEVELOPMENT_TEAM = K2648T24P4;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -1359,7 +1359,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 4.1.2;
MARKETING_VERSION = 4.1.3;
PRODUCT_BUNDLE_IDENTIFIER = dev.jacobcx.Xcodes;
PRODUCT_NAME = Xcodes;
SWIFT_VERSION = 6.0;
Expand All @@ -1376,7 +1376,7 @@
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
CODE_SIGN_STYLE = Automatic;
COMBINE_HIDPI_IMAGES = YES;
CURRENT_PROJECT_VERSION = 50;
CURRENT_PROJECT_VERSION = 51;
DEVELOPMENT_ASSET_PATHS = "\"Xcodes/Preview Content\"";
DEVELOPMENT_TEAM = K2648T24P4;
ENABLE_HARDENED_RUNTIME = YES;
Expand All @@ -1388,7 +1388,7 @@
"@executable_path/../Frameworks",
);
MACOSX_DEPLOYMENT_TARGET = 14.6;
MARKETING_VERSION = 4.1.2;
MARKETING_VERSION = 4.1.3;
PRODUCT_BUNDLE_IDENTIFIER = dev.jacobcx.Xcodes;
PRODUCT_NAME = Xcodes;
SWIFT_VERSION = 6.0;
Expand Down
11 changes: 10 additions & 1 deletion Xcodes/Backend/XcodeCommands.swift
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ struct InstallButton: View {
Text("Install")
.help("InstallDescription")
}
.accessibilityValue(xcode?.description ?? "")
}

private func install() {
Expand All @@ -60,9 +61,12 @@ struct CancelInstallButton: View {
var body: some View {
Button(action: cancelInstall) {
Label("Cancel", systemImage: "xmark")
.frame(minWidth: 20, minHeight: 20)
.contentShape(Rectangle())
}
.help(localizeString("StopInstallation"))
.buttonStyle(.plain)
.accessibilityValue(xcode?.description ?? "")
}

private func cancelInstall() {
Expand All @@ -78,10 +82,13 @@ struct CancelRuntimeInstallButton: View {
var body: some View {
Button(action: cancelInstall) {
Label("StopInstallation", systemImage: "xmark.circle.fill")
.frame(minWidth: 20, minHeight: 20)
.contentShape(Rectangle())
}
.labelStyle(.iconOnly)
.help(localizeString("StopInstallation"))
.buttonStyle(.plain)
.accessibilityValue(runtime?.visibleIdentifier ?? "")
}

private func cancelInstall() {
Expand All @@ -103,7 +110,8 @@ struct SelectButton: View {
}
}
.disabled(xcode?.selected != false)
.help("Select")
.accessibilityValue(xcode?.description ?? "")
.help(xcode?.selected == true ? Text("ActiveVersionDescription") : Text("MakeActiveVersionDescription"))
}

private func select() {
Expand Down Expand Up @@ -246,6 +254,7 @@ struct DownloadRuntimeButton: View {
Text("Install")
.help("Install")
}
.accessibilityValue(runtime?.visibleIdentifier ?? "")
}

private func install() {
Expand Down
3 changes: 2 additions & 1 deletion Xcodes/Frontend/InfoPane/InstalledStateButtons.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ struct InstalledStateButtons: View {
Text(xcode.installedPath?.string ?? "")
Button(action: { appState.reveal(xcode.installedPath) }) {
Label("RevealInFinder", systemImage: "arrow.right.circle.fill")
.frame(minWidth: 20, minHeight: 20)
.contentShape(Rectangle())
}
.labelStyle(.iconOnly)
.buttonStyle(PlainButtonStyle())
Expand All @@ -31,7 +33,6 @@ struct InstalledStateButtons: View {
HStack {
SelectButton(xcode: xcode)
.disabled(xcode.selected)
.help("Selected")

OpenButton(xcode: xcode)
.help("Open")
Expand Down
2 changes: 2 additions & 0 deletions Xcodes/Frontend/InfoPane/PlatformsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,8 @@ struct PlatformsView: View {
if let path = appState.runtimeInstallPath(xcode: xcode, runtime: runtime) {
Button(action: { appState.reveal(path: path.string) }) {
Label("RevealInFinder", systemImage: "arrow.right.circle.fill")
.frame(minWidth: 20, minHeight: 20)
.contentShape(Rectangle())
}
.labelStyle(.iconOnly)
.buttonStyle(PlainButtonStyle())
Expand Down
4 changes: 4 additions & 0 deletions Xcodes/Frontend/Preferences/AdvancedPreferencePane.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ struct AdvancedPreferencePane: View {
.lineLimit(2)
Button(action: { appState.reveal(path: appState.installPath) }) {
Label("RevealInFinder", systemImage: "arrow.right.circle.fill")
.frame(minWidth: 20, minHeight: 20)
.contentShape(Rectangle())
}
.labelStyle(.iconOnly)
.buttonStyle(PlainButtonStyle())
Expand Down Expand Up @@ -54,6 +56,8 @@ struct AdvancedPreferencePane: View {
.lineLimit(2)
Button(action: { appState.reveal(path: appState.localPath) }) {
Label("RevealInFinder", systemImage: "arrow.right.circle.fill")
.frame(minWidth: 20, minHeight: 20)
.contentShape(Rectangle())
}
.labelStyle(.iconOnly)
.buttonStyle(PlainButtonStyle())
Expand Down
2 changes: 2 additions & 0 deletions Xcodes/Frontend/Preferences/PlatformsListView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ struct PlatformsListView: View {
deleteRuntime(runtime: installedRuntime)
} label: {
Label("Alert.DeletePlatform.PrimaryButton", systemImage: "trash")
.frame(minWidth: 20, minHeight: 20)
.contentShape(Rectangle())
}
.labelStyle(.iconOnly)
.accessibilityValue(runtime.name)
Expand Down
1 change: 1 addition & 0 deletions Xcodes/Frontend/SignIn/PinCodeTextView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ final class PinCodeTextView: NSControl, NSTextFieldDelegate {
inputField.delegate = self
inputField.setAccessibilityLabel(accessibilityLabel)
addSubview(inputField)
setAccessibilityChildren([inputField.cell].compactMap { $0 })

NSLayoutConstraint.activate([
stackView.topAnchor.constraint(equalTo: topAnchor),
Expand Down
12 changes: 3 additions & 9 deletions Xcodes/Frontend/XcodeList/InstallationStepRowView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import XcodesKit

struct InstallationStepRowView: View {
let installationStep: XcodeInstallationStep
let highlighted: Bool
let cancel: () -> Void

var body: some View {
Expand All @@ -29,9 +28,11 @@ struct InstallationStepRowView: View {
Button(action: cancel) {
Label("Cancel", systemImage: "xmark.circle.fill")
.labelStyle(IconOnlyLabelStyle())
.frame(minWidth: 20, minHeight: 20)
.contentShape(Rectangle())
}
.buttonStyle(PlainButtonStyle())
.foregroundColor(highlighted ? .white : .secondary)
.foregroundStyle(.primary)
.help("StopInstallation")
}
.frame(minWidth: 80)
Expand All @@ -47,37 +48,31 @@ struct InstallView_Previews: PreviewProvider {
installationStep: .downloading(
progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40 }
),
highlighted: false,
cancel: {}
)

InstallationStepRowView(
installationStep: .unarchiving,
highlighted: false,
cancel: {}
)

InstallationStepRowView(
installationStep: .moving(destination: "/Applications"),
highlighted: false,
cancel: {}
)

InstallationStepRowView(
installationStep: .trashingArchive,
highlighted: false,
cancel: {}
)

InstallationStepRowView(
installationStep: .checkingSecurity,
highlighted: false,
cancel: {}
)

InstallationStepRowView(
installationStep: .finishing,
highlighted: false,
cancel: {}
)
}
Expand All @@ -92,7 +87,6 @@ struct InstallView_Previews: PreviewProvider {
installationStep: .downloading(
progress: configure(Progress(totalUnitCount: 100)) { $0.completedUnitCount = 40 }
),
highlighted: true,
cancel: {}
)
}
Expand Down
1 change: 1 addition & 0 deletions Xcodes/Frontend/XcodeList/MainToolbar.swift
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ struct MainToolbarModifier: ViewModifier {
}
.pickerStyle(.inline)
.symbolVariant(isFiltering ? .fill : .none)
.accessibilityLabel(Text("Filter"))
}
}

Expand Down
Loading