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
3 changes: 3 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,9 @@ approaches. Don't re-litigate a recorded decision without new facts.
doc.
- `design-conventions.md` — TALLY tokens, appearance system, type scaling,
platform splits. Color is state, never decoration.
- `i18n.md` — String Catalogs (zh-Hant, ja), the A/B/C string tiers (TALLY
chrome stays English), glossary, `./Tools/build.sh strings`. Wrap new
user-visible prose in `String(localized:)`.

## Known limits (v1)

Expand Down
14 changes: 14 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@ opinionated (see `DESIGN.md` and `docs/agents/`), and agreeing on the shape up
front avoids work that can't be merged. Feature PRs without a linked issue may
be closed.

## Language support

Translation PRs are welcome without prior discussion — a new language, or
corrections to an existing one (currently Traditional Chinese and Japanese).
It's recommended that you be a native speaker or a learner of the language,
though this isn't a hard requirement.

Read [`docs/agents/i18n.md`](docs/agents/i18n.md) first. In short: strings
live in the String Catalogs (`Multiplex/Localizable.xcstrings`,
`MultiplexWidgets/Localizable.xcstrings`); the glossary and string tiers
there apply (the TALLY micro chrome deliberately stays English); a new
locale should also mirror `fastlane/metadata/en-US` for the App Store
listing. `./Tools/build.sh strings` syncs the catalogs after code changes.

## Before you send a PR

- Edit `project.yml`, never the `.xcodeproj`; run `xcodegen generate`.
Expand Down
6 changes: 3 additions & 3 deletions Multiplex/AppIntents/OpenHostIntents.swift
Original file line number Diff line number Diff line change
Expand Up @@ -396,19 +396,19 @@ enum ShortcutSetupScriptOptions {
var choices = [
Choice(
value: ExternalSetupScriptSelection.rememberedToken,
title: "New Session Default"
title: String(localized: "New Session Default")
),
Choice(
value: ExternalSetupScriptSelection.noneToken,
title: "None"
title: String(localized: "None")
),
]
var seen = Set<UUID>()
for script in configured where seen.insert(script.id).inserted {
let name = script.displayName.trimmingCharacters(in: .whitespacesAndNewlines)
choices.append(Choice(
value: script.id.uuidString,
title: name.isEmpty ? "Script" : name
title: name.isEmpty ? String(localized: "Script") : name
))
}
return choices
Expand Down
16 changes: 9 additions & 7 deletions Multiplex/Design/TallyEditorControls.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ final class TallyEditorSwitch: UIControl {
private func render(animated: Bool = false) {
track.setOn(isOn, animated: animated)
caption.setInk(isOn ? UIKitChassis.signal : UIKitChassis.signal2)
accessibilityValue = isOn ? "On" : "Off"
accessibilityValue = isOn ? String(localized: "On") : String(localized: "Off")
if isOn {
accessibilityTraits.insert(.selected)
} else {
Expand Down Expand Up @@ -238,23 +238,23 @@ enum TallyEditorRowActions {
) -> Trio {
let up = TallyEditorRowActionButton(
systemImage: "arrow.up",
accessibilityLabel: "Move command up",
accessibilityLabel: String(localized: "Move command up"),
enabled: index > 0,
scale: scale,
action: { move(-1) }
)
up.accessibilityIdentifier = "\(identifierPrefix).moveUp.\(rowID.uuidString)"
let down = TallyEditorRowActionButton(
systemImage: "arrow.down",
accessibilityLabel: "Move command down",
accessibilityLabel: String(localized: "Move command down"),
enabled: index < count - 1,
scale: scale,
action: { move(1) }
)
down.accessibilityIdentifier = "\(identifierPrefix).moveDown.\(rowID.uuidString)"
let trash = TallyEditorRowActionButton(
systemImage: "trash",
accessibilityLabel: "Delete command",
accessibilityLabel: String(localized: "Delete command"),
enabled: true,
scale: scale,
action: delete
Expand Down Expand Up @@ -334,7 +334,9 @@ enum TallyEditorFooter {
addState == .upgrade ? "ADD COMMAND · PRO" : "ADD COMMAND",
systemImage: "plus",
prominent: addState == .upgrade,
accessibilityLabel: addState == .upgrade ? "Add command with Multiplex Pro" : "Add command",
accessibilityLabel: addState == .upgrade
? String(localized: "Add command with Multiplex Pro")
: String(localized: "Add command"),
action: add
)
addChip.accessibilityIdentifier = "\(identifierPrefix).add"
Expand All @@ -344,14 +346,14 @@ enum TallyEditorFooter {
spacer.setContentHuggingPriority(.defaultLow, for: .horizontal)
let cancelChip = UIKitChassisChip(
"CANCEL",
accessibilityLabel: "Cancel",
accessibilityLabel: String(localized: "Cancel"),
action: cancel
)
cancelChip.accessibilityIdentifier = "\(identifierPrefix).cancel"
let doneChip = UIKitChassisChip(
"DONE",
prominent: true,
accessibilityLabel: "Done",
accessibilityLabel: String(localized: "Done"),
action: done
)
doneChip.accessibilityIdentifier = "\(identifierPrefix).done"
Expand Down
121 changes: 121 additions & 0 deletions Multiplex/InfoPlist.xcstrings
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
{
"sourceLanguage" : "en",
"strings" : {
"NSCameraUsageDescription" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex uses the camera when you take a photo to send to your remote SSH session, and when you scan the code that binds a machine to the app."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex は、リモートの SSH セッションへ送る写真を撮るときと、マシンをこの App にバインドするコードをスキャンするときにカメラを使用します。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex 會在你拍照傳送到遠端 SSH 工作階段,以及掃描綁定機器的條碼時使用相機。"
}
}
}
},
"NSFaceIDUsageDescription" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex unlocks with Face ID when the optional App Lock setting is turned on."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "オプションの「App ロック」設定をオンにすると、Multiplex は Face ID でロックを解除します。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "開啟選用的「App 鎖定」設定後,Multiplex 會使用 Face ID 解鎖。"
}
}
}
},
"NSLocalNetworkUsageDescription" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex connects to SSH hosts on your local network, and finds machines offering to bind themselves to the app."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex はローカルネットワーク上の SSH ホストに接続し、この App へのバインドを申し出ているマシンを見つけます。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex 會連接區域網路上的 SSH 主機,並尋找正在提供綁定的機器。"
}
}
}
},
"NSMicrophoneUsageDescription" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex listens only while you hold a dictation going from the terminal key bar."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex がマイクを使うのは、ターミナルのキーバーから音声入力を押し続けている間だけです。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "只有在你從終端機按鍵列按住聽寫時,Multiplex 才會使用麥克風。"
}
}
}
},
"NSSpeechRecognitionUsageDescription" : {
"extractionState" : "manual",
"localizations" : {
"en" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex transcribes your dictation so the words can be typed into the terminal session you are attached to. Recognition stays on device wherever your language supports it."
}
},
"ja" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex は音声入力を文字に起こし、接続中のターミナルセッションに入力します。お使いの言語が対応していれば、認識はデバイス上で行われます。"
}
},
"zh-Hant" : {
"stringUnit" : {
"state" : "translated",
"value" : "Multiplex 會轉寫你的聽寫內容,好把文字輸入到你目前連接的終端機工作階段。只要你的語言支援,辨識就會在裝置上完成。"
}
}
}
}
},
"version" : "1.0"
}
Loading
Loading