mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-10-24 15:49:39 +00:00
Groundwork for #1219. The menubar app hardcoded ~530 English strings across Views/, the presentation structs, the status-item menu and the update alerts, so there was nothing for a translator to translate. Every user-facing literal now goes through `L(_:)` / `L(_:_:)`, which look the string up in `Localizable.strings` in the SwiftPM target resource bundle. The key *is* the English copy, so English stays the development language and a missing translation degrades to correct English instead of a dotted identifier. `en.lproj` is therefore an identity table; it exists so the bundle advertises `en` and so a translation can be diffed against it. Why the lookups are explicit rather than relying on SwiftUI's implicit `LocalizedStringKey`: SwiftPM emits target resources into a sibling bundle (`CodeBurnMenubar_CodeBurnMenubar.bundle`) that the packaging scripts copy into `Contents/Resources`. `Bundle.main` has no `.lproj` at all, so `Text("literal")` would always miss. Naming `Bundle.module` is the one form that resolves the same way in `swift run`, in `swift test` and in the packaged `.app`. Enum raw values that double as identity (`Period`, `MenubarScope`, `InsightMode`, `AccentPreset`, `ProviderFilter`) keep their raw value and gain a `displayLabel`, so persistence and cache keys are untouched by translation. Three display-only date formatters that were pinned to `en_US_POSIX` with fixed patterns now use `setLocalizedDateFormatFromTemplate`, and the calendar popover's weekday row comes from the locale's own symbols. The `yyyy-MM-dd` formatter stays POSIX: it parses and builds data keys, not display text. Not extracted, deliberately: provider, model and plan names; units; currency codes; shell commands and paths; quota window labels that policy code matches on by English substring (`QuotaSummary.headlineWindow`); and anything the `codeburn` CLI produces. Also copies the SwiftPM resource bundle into the app in build-local.sh, using the named-bundle + `[[ -d ]]` pattern package-app.sh already uses. Without it the assembled app finds no strings table (and already trapped on first icon load, the resource-bundle half of #1262).
43 lines
1.6 KiB
Swift
43 lines
1.6 KiB
Swift
import Foundation
|
|
|
|
/// User-configurable cadence for the usage payload refresh loop (#647).
|
|
/// `auto` keeps the adaptive default: 30s while active, 120s while closed on AC,
|
|
/// backed off further on battery, in Low Power Mode, and while the displays sleep.
|
|
/// `manual = 0` never
|
|
/// auto-spawns; usage refreshes only on popover open, Refresh Now, and first
|
|
/// launch. Stored as raw seconds in UserDefaults (auto = -1), mirroring
|
|
/// SubscriptionRefreshCadence.
|
|
enum UsageRefreshCadence: Int, CaseIterable, Identifiable {
|
|
case auto = -1
|
|
case manual = 0
|
|
case oneMinute = 60
|
|
case fiveMinutes = 300
|
|
case fifteenMinutes = 900
|
|
|
|
var id: Int { rawValue }
|
|
|
|
var label: String {
|
|
switch self {
|
|
case .auto: return L("Auto (2m, less on battery)")
|
|
case .manual: return L("Manual")
|
|
case .oneMinute: return L("1 minute")
|
|
case .fiveMinutes: return L("5 minutes")
|
|
case .fifteenMinutes: return L("15 minutes")
|
|
}
|
|
}
|
|
|
|
static let defaultsKey = "CodeBurnMenubarRefreshSeconds"
|
|
static let `default`: UsageRefreshCadence = .auto
|
|
|
|
static var current: UsageRefreshCadence {
|
|
get {
|
|
// integer(forKey:) returns 0 for a missing key, which aliases
|
|
// `manual`; probe object(forKey:) to seed the default instead.
|
|
if UserDefaults.standard.object(forKey: defaultsKey) == nil {
|
|
return .default
|
|
}
|
|
return UsageRefreshCadence(rawValue: UserDefaults.standard.integer(forKey: defaultsKey)) ?? .default
|
|
}
|
|
set { UserDefaults.standard.set(newValue.rawValue, forKey: defaultsKey) }
|
|
}
|
|
}
|