diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 73cc63840..5509e6a40 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,6 +19,13 @@ jobs: - uses: actions/checkout@v4 - uses: jdx/mise-action@v3 - run: ./swiftformat --lint + # Catalogs drift out of Xcode's serialization the moment one is written by + # anything but Xcode, and the cost lands on whoever next builds in the IDE + # (see "Formatting" in AGENTS.md). This rides along in the format job + # rather than a job of its own because branch protection pins the two + # check names. + - name: String Catalog lint + run: ./xcstrings --lint test: name: Build & Test (iOS) diff --git a/AGENTS.md b/AGENTS.md index b90764e2e..5823e9c40 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -47,8 +47,8 @@ Xcode project](#generating-the-xcode-project)). A fresh machine needs `./ide generating; plain `./ide` fails fast pointing at it. The executables in the repo root are the dev scripts — `ide`, `swiftformat`, -`sync-agents`, `profile`, `icons`, `flaky`, `simulator` — and each takes -`--help`. Reach for one rather than hand-rolling its job: `icons` and +`sync-agents`, `profile`, `icons`, `flaky`, `simulator`, `xcstrings` — and each +takes `--help`. Reach for one rather than hand-rolling its job: `icons` and `simulator` in particular own state that is easy to corrupt by hand (see [Managing app icons](#managing-app-icons) and [Selecting a simulator](#selecting-a-simulator--address-it-by-udid-not-name)). @@ -66,6 +66,14 @@ Run `./ide --no-open` after adding one. format the tree, or `./swiftformat --lint` to check only (as in CI). - The pre-commit hook (enabled by `./ide` via `core.hooksPath`) formats staged `*.swift` files in place and re-stages them. +- **String Catalogs are stored exactly as Xcode serializes them**, and + `./xcstrings` (`--lint` in CI) enforces it. Xcode rewrites a `.xcstrings` in + place during an *IDE* build whenever extraction finds a key the catalog + lacks — writing the entire file with its own serializer — so a catalog + written by anything else (a migration script's `json.dump`, a hand edit) + parses fine but turns the next build into thousands of lines of whitespace + churn around the one real entry. Write a catalog through Xcode, or normalize + it afterwards; the script only touches formatting, never content. ## Agent instructions sync diff --git a/Shared/LifecycleKit/Sources/Resources/Localizable.xcstrings b/Shared/LifecycleKit/Sources/Resources/Localizable.xcstrings index c67990272..6a93d9136 100644 --- a/Shared/LifecycleKit/Sources/Resources/Localizable.xcstrings +++ b/Shared/LifecycleKit/Sources/Resources/Localizable.xcstrings @@ -1,6 +1,9 @@ { "sourceLanguage" : "en", "strings" : { + "App content" : { + + }, "failure.launch.retry" : { "extractionState" : "manual", "localizations" : { @@ -25,4 +28,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/Where/AGENTS.md b/Where/AGENTS.md index a9dec034a..bf59c192a 100644 --- a/Where/AGENTS.md +++ b/Where/AGENTS.md @@ -139,6 +139,16 @@ Add the key to the catalog as a **manual** entry first (so its symbol generates), then reference `.thatSymbol` — never ship English literals in SwiftUI `Text` or `errorDescription`, and never reintroduce a raw-key facade. +The catalogs also carry a few **auto-extracted** entries with no +`extractionState` and no value — `""`, `%lld`, an English literal from a +`#Preview`. Those are Xcode's, not ours: extraction picks up every string +literal that could be a key (`Marker("", …)`, `Text("\(count)")`), and an IDE +build re-adds any that's missing, so deleting one by hand just brings it back +with a full reserialization behind it. Remove the *source* literal if you want +the entry gone — interpolating an `Int` into `Text` is worth fixing anyway (it +skips `WhereFormat`'s number styling). Catalog files stay byte-identical to +Xcode's own serialization; see [Formatting](../AGENTS.md#formatting). + ## Dates & presentation - **A logical day is a `CalendarDay` (Y-M-D), not a `Date`.** It is the diff --git a/Where/RegionKit/Sources/Resources/Localizable.xcstrings b/Where/RegionKit/Sources/Resources/Localizable.xcstrings index 826da5c00..062c220ab 100644 --- a/Where/RegionKit/Sources/Resources/Localizable.xcstrings +++ b/Where/RegionKit/Sources/Resources/Localizable.xcstrings @@ -58,4 +58,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/Where/TODOs.md b/Where/TODOs.md index c1fbc5c8b..ef897b29d 100644 --- a/Where/TODOs.md +++ b/Where/TODOs.md @@ -51,6 +51,7 @@ This feels like it might result in a cleaner "pipeline-esque" code layout, and a - Move `let calendar = Calendar.current` into a var on the controller? There’s a few of these - Move test only code behind @_spi - Add comments to strings in xcstrings files +- fix: Four literals in source get auto-extracted into the catalogs as value-less entries, which is why an IDE build had anything to write back at all (see the serialization normalization PR). They're committed as Xcode writes them; removing an entry for good means removing the literal. `Marker("", coordinate:)` in `RecordedPointsMap` produces the empty `""` key (an unlabeled dev-map pin — `Annotation` with an explicit accessibility label would say what it means); `Text("\(group.outlineCount)")` in `RegionMapView` and `Text("\(day.dayOfMonth)")` in `CalendarContentView` produce `%lld` and bypass `WhereFormat`'s number styling; and a `Button("Log today here")` in an `IntentSnippets` `#Preview` hardcodes copy the `snippet.logTodayHere` symbol already owns. `App content` comes from a `LifecycleContainer` `#Preview` in LifecycleKit. # Completed issues diff --git a/Where/WhereCore/Sources/Resources/Localizable.xcstrings b/Where/WhereCore/Sources/Resources/Localizable.xcstrings index 2d1818696..be757567b 100644 --- a/Where/WhereCore/Sources/Resources/Localizable.xcstrings +++ b/Where/WhereCore/Sources/Resources/Localizable.xcstrings @@ -137,4 +137,4 @@ } }, "version" : "1.0" -} +} \ No newline at end of file diff --git a/Where/WhereIntents/Sources/Resources/Localizable.xcstrings b/Where/WhereIntents/Sources/Resources/Localizable.xcstrings index 16879f671..8a8be3f34 100644 --- a/Where/WhereIntents/Sources/Resources/Localizable.xcstrings +++ b/Where/WhereIntents/Sources/Resources/Localizable.xcstrings @@ -1,366 +1,372 @@ { - "sourceLanguage": "en", - "strings": { - "%@": { - "comment": "A spoken dialog response for the \"Count days in a region\" intent. The argument is the region name, the second is the number of days, and the third is the year.", - "isCommentAutoGenerated": true - }, - "Backfill a range of days with the regions you were in.": { - "comment": "Description of the Log Trip intent.", - "isCommentAutoGenerated": true - }, - "Count Days in a Region": { - "comment": "Intent name for the \"Count Days in a Region\" action.", - "isCommentAutoGenerated": true - }, - "Date": { - "comment": "Label for the date parameter in the RegionOnDateIntent.", - "isCommentAutoGenerated": true - }, - "Day": { - "comment": "The name of the parameter for the day of the week.", - "isCommentAutoGenerated": true - }, - "Days in a Region": { - "comment": "Title of the Days in a Region snippet.", - "isCommentAutoGenerated": true - }, - "End Date": { - "comment": "Label for the end date parameter in the Log a Trip intent.", - "isCommentAutoGenerated": true - }, - "Find Regions on a Date": { - "comment": "Title of the intent.", - "isCommentAutoGenerated": true - }, - "Find out how many days you've spent in a region so far this year.": { - "comment": "Description of the \"Count Days in a Region\" intent.", - "isCommentAutoGenerated": true - }, - "Get an on-device summary of where you've been over a recent window.": { - "comment": "Description of the intent to get an on-device summary of where the user has been over a recent window.", - "isCommentAutoGenerated": true - }, - "Last 24 Hours": { - "comment": "Display name for the \"Last 24 Hours\" option in the Siri-resolved menu.", - "isCommentAutoGenerated": true - }, - "Log a Day's Regions": { - "comment": "Intent title.", - "isCommentAutoGenerated": true - }, - "Log a Trip": {}, - "Look up which regions a particular day counted for.": { - "comment": "Description of the \"Find Regions on a Date\" intent.", - "isCommentAutoGenerated": true - }, - "Past Month": { - "comment": "Display name for the past month option in the recent-activity summary intent.", - "isCommentAutoGenerated": true - }, - "Past Week": { - "comment": "Displayed title for the \"Past Week\" option in the Siri-resolved menu.", - "isCommentAutoGenerated": true - }, - "Record which regions you were in on a day.": { - "comment": "Description of the \"Log a Day's Regions\" intent.", - "isCommentAutoGenerated": true - }, - "Region": { - "comment": "The parameter name for the region parameter in the DaysInRegionIntent.", - "isCommentAutoGenerated": true - }, - "Regions": { - "comment": "The parameter title for the regions parameter in the Log Day intent.", - "isCommentAutoGenerated": true - }, - "See which regions today counts for so far.": { - "comment": "Description of the \"Show Today's Regions\" intent.", - "isCommentAutoGenerated": true - }, - "Show Today's Regions": { - "comment": "Title of the \"Where am I today?\" intent.", - "isCommentAutoGenerated": true - }, - "Start Date": {}, - "Summarize Recent Activity": { - "comment": "Intent to summarize recent activity.", - "isCommentAutoGenerated": true - }, - "Time Range": {}, - "Year": { - "comment": "Label for the year parameter in the \"Count Days in a Region\" intent.", - "isCommentAutoGenerated": true - }, - "Year So Far": { - "comment": "Display name for the \"Year So Far\" option in the", - "isCommentAutoGenerated": true - }, - "audit.note.siri": { - "comment": "Note stored on a manual day entry made through an intent.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Logged with Siri" + "sourceLanguage" : "en", + "strings" : { + "%@" : { + "comment" : "A spoken dialog response for the \"Count days in a region\" intent. The argument is the region name, the second is the number of days, and the third is the year.", + "isCommentAutoGenerated" : true + }, + "Backfill a range of days with the regions you were in." : { + "comment" : "Description of the Log Trip intent.", + "isCommentAutoGenerated" : true + }, + "Count Days in a Region" : { + "comment" : "Intent name for the \"Count Days in a Region\" action.", + "isCommentAutoGenerated" : true + }, + "Date" : { + "comment" : "Label for the date parameter in the RegionOnDateIntent.", + "isCommentAutoGenerated" : true + }, + "Day" : { + "comment" : "The name of the parameter for the day of the week.", + "isCommentAutoGenerated" : true + }, + "Days in a Region" : { + "comment" : "Title of the Days in a Region snippet.", + "isCommentAutoGenerated" : true + }, + "End Date" : { + "comment" : "Label for the end date parameter in the Log a Trip intent.", + "isCommentAutoGenerated" : true + }, + "Find Regions on a Date" : { + "comment" : "Title of the intent.", + "isCommentAutoGenerated" : true + }, + "Find out how many days you've spent in a region so far this year." : { + "comment" : "Description of the \"Count Days in a Region\" intent.", + "isCommentAutoGenerated" : true + }, + "Get an on-device summary of where you've been over a recent window." : { + "comment" : "Description of the intent to get an on-device summary of where the user has been over a recent window.", + "isCommentAutoGenerated" : true + }, + "Last 24 Hours" : { + "comment" : "Display name for the \"Last 24 Hours\" option in the Siri-resolved menu.", + "isCommentAutoGenerated" : true + }, + "Log a Day's Regions" : { + "comment" : "Intent title.", + "isCommentAutoGenerated" : true + }, + "Log a Trip" : { + + }, + "Look up which regions a particular day counted for." : { + "comment" : "Description of the \"Find Regions on a Date\" intent.", + "isCommentAutoGenerated" : true + }, + "Past Month" : { + "comment" : "Display name for the past month option in the recent-activity summary intent.", + "isCommentAutoGenerated" : true + }, + "Past Week" : { + "comment" : "Displayed title for the \"Past Week\" option in the Siri-resolved menu.", + "isCommentAutoGenerated" : true + }, + "Record which regions you were in on a day." : { + "comment" : "Description of the \"Log a Day's Regions\" intent.", + "isCommentAutoGenerated" : true + }, + "Region" : { + "comment" : "The parameter name for the region parameter in the DaysInRegionIntent.", + "isCommentAutoGenerated" : true + }, + "Regions" : { + "comment" : "The parameter title for the regions parameter in the Log Day intent.", + "isCommentAutoGenerated" : true + }, + "See which regions today counts for so far." : { + "comment" : "Description of the \"Show Today's Regions\" intent.", + "isCommentAutoGenerated" : true + }, + "Show Today's Regions" : { + "comment" : "Title of the \"Where am I today?\" intent.", + "isCommentAutoGenerated" : true + }, + "Start Date" : { + + }, + "Summarize Recent Activity" : { + "comment" : "Intent to summarize recent activity.", + "isCommentAutoGenerated" : true + }, + "Time Range" : { + + }, + "Year" : { + "comment" : "Label for the year parameter in the \"Count Days in a Region\" intent.", + "isCommentAutoGenerated" : true + }, + "Year So Far" : { + "comment" : "Display name for the \"Year So Far\" option in the", + "isCommentAutoGenerated" : true + }, + "audit.note.siri" : { + "comment" : "Note stored on a manual day entry made through an intent.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logged with Siri" } } } }, - "dialog.daysInRegion.none": { - "comment": "Spoken result when a region has no logged days this year. %1$@ region name, %2$@ year.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "You have no days logged in %1$@ so far in %2$@." + "dialog.daysInRegion.none" : { + "comment" : "Spoken result when a region has no logged days this year. %1$@ region name, %2$@ year.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You have no days logged in %1$@ so far in %2$@." } } } }, - "dialog.daysInRegion.one": { - "comment": "Spoken result for exactly one day in a region. %1$@ region name, %2$@ year.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "You have 1 day in %1$@ so far in %2$@." + "dialog.daysInRegion.one" : { + "comment" : "Spoken result for exactly one day in a region. %1$@ region name, %2$@ year.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You have 1 day in %1$@ so far in %2$@." } } } }, - "dialog.daysInRegion.other": { - "comment": "Spoken result for a day count in a region. %1$lld count, %2$@ region name, %3$@ year.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "You have %1$lld days in %2$@ so far in %3$@." + "dialog.daysInRegion.other" : { + "comment" : "Spoken result for a day count in a region. %1$lld count, %2$@ region name, %3$@ year.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "You have %1$lld days in %2$@ so far in %3$@." } } } }, - "dialog.logged.chooseRegions": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Tell me which regions to log." + "dialog.logged.chooseRegions" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tell me which regions to log." } } } }, - "dialog.logged.day": { - "comment": "Confirmation after logging a day. %1$@ region list, %2$@ date.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Logged %1$@ for %2$@." + "dialog.logged.day" : { + "comment" : "Confirmation after logging a day. %1$@ region list, %2$@ date.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logged %1$@ for %2$@." } } } }, - "dialog.logged.emptyRange": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "That date range doesn't include any days." + "dialog.logged.emptyRange" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "That date range doesn't include any days." } } } }, - "dialog.logged.trip.one": { - "comment": "Confirmation after backfilling exactly one day. %1$@ region list.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Logged %1$@ for 1 day." + "dialog.logged.trip.one" : { + "comment" : "Confirmation after backfilling exactly one day. %1$@ region list.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logged %1$@ for 1 day." } } } }, - "dialog.logged.trip.other": { - "comment": "Confirmation after backfilling a trip. %1$@ region list, %2$lld day count.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Logged %1$@ for %2$lld days." + "dialog.logged.trip.other" : { + "comment" : "Confirmation after backfilling a trip. %1$@ region list, %2$lld day count.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logged %1$@ for %2$lld days." } } } }, - "dialog.recentActivity.empty": { - "comment": "Spoken result when a window has no tracked activity. %1$@ window phrase.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Nothing was tracked in %1$@." + "dialog.recentActivity.empty" : { + "comment" : "Spoken result when a window has no tracked activity. %1$@ window phrase.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nothing was tracked in %1$@." } } } }, - "dialog.recentActivity.unavailable.appleIntelligenceNotEnabled": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Turn on Apple Intelligence in Settings to summarize where you've been." + "dialog.recentActivity.unavailable.appleIntelligenceNotEnabled" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Turn on Apple Intelligence in Settings to summarize where you've been." } } } }, - "dialog.recentActivity.unavailable.deviceNotEligible": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "This device doesn't support on-device summaries." + "dialog.recentActivity.unavailable.deviceNotEligible" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This device doesn't support on-device summaries." } } } }, - "dialog.recentActivity.unavailable.modelNotReady": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "The on-device model is still getting ready. Try again shortly." + "dialog.recentActivity.unavailable.modelNotReady" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The on-device model is still getting ready. Try again shortly." } } } }, - "dialog.recentActivity.unavailable.unknown": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "On-device summaries aren't available right now." + "dialog.recentActivity.unavailable.unknown" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "On-device summaries aren't available right now." } } } }, - "dialog.regionOnDate.none": { - "comment": "Spoken result when a date has nothing logged. %1$@ formatted date.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Nothing is logged for %1$@." + "dialog.regionOnDate.none" : { + "comment" : "Spoken result when a date has nothing logged. %1$@ formatted date.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nothing is logged for %1$@." } } } }, - "dialog.regionOnDate.some": { - "comment": "Spoken result naming the regions a date counted for. %1$@ date, %2$@ region list.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "On %1$@ you were in %2$@." + "dialog.regionOnDate.some" : { + "comment" : "Spoken result naming the regions a date counted for. %1$@ date, %2$@ region list.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "On %1$@ you were in %2$@." } } } }, - "dialog.today.none": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Nothing is logged for today yet." + "dialog.today.none" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nothing is logged for today yet." } } } }, - "dialog.today.some": { - "comment": "Spoken result naming today's regions. %1$@ region list.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Today you've been in %1$@." + "dialog.today.some" : { + "comment" : "Spoken result naming today's regions. %1$@ region list.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Today you've been in %1$@." } } } }, - "dialog.window.day": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "the last 24 hours" + "dialog.window.day" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "the last 24 hours" } } } }, - "dialog.window.month": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "the past month" + "dialog.window.month" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "the past month" } } } }, - "dialog.window.week": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "the past week" + "dialog.window.week" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "the past week" } } } }, - "dialog.window.yearToDate": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "the year so far" + "dialog.window.yearToDate" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "the year so far" } } } }, - "snippet.logTodayHere": { - "comment": "Button in the day-count snippet that logs today for the shown region.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Log today here" + "snippet.logTodayHere" : { + "comment" : "Button in the day-count snippet that logs today for the shown region.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Log today here" } } } } }, - "version": "1.1" -} + "version" : "1.1" +} \ No newline at end of file diff --git a/Where/WhereShareExtension/Resources/Localizable.xcstrings b/Where/WhereShareExtension/Resources/Localizable.xcstrings index b4ec91b81..553e0edac 100644 --- a/Where/WhereShareExtension/Resources/Localizable.xcstrings +++ b/Where/WhereShareExtension/Resources/Localizable.xcstrings @@ -1,186 +1,186 @@ { - "sourceLanguage": "en", - "strings": { - "share.attachment.fallbackName": { - "comment": "Stand-in name for a shared attachment the provider gave no filename for.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Attachment" + "sourceLanguage" : "en", + "strings" : { + "share.attachment.fallbackName" : { + "comment" : "Stand-in name for a shared attachment the provider gave no filename for.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attachment" } } } }, - "share.attachment.header": { - "comment": "Section header above the shared attachment summary (one item).", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Attachment" + "share.attachment.header" : { + "comment" : "Section header above the shared attachment summary (one item).", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attachment" } } } }, - "share.attachment.headerPlural": { - "comment": "Section header above the shared attachments (more than one item).", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Attachments" + "share.attachment.headerPlural" : { + "comment" : "Section header above the shared attachments (more than one item).", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attachments" } } } }, - "share.attachment.none": { - "comment": "Shown when the share carried nothing loadable, so only metadata is saved.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No attachment — this will save a note only." + "share.attachment.none" : { + "comment" : "Shown when the share carried nothing loadable, so only metadata is saved.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No attachment — this will save a note only." } } } }, - "share.cancel": { - "comment": "Cancel button dismissing the share sheet without saving.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Cancel" + "share.cancel" : { + "comment" : "Cancel button dismissing the share sheet without saving.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancel" } } } }, - "share.form.date": { - "comment": "Date picker label for when the evidence was captured.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Date" + "share.form.date" : { + "comment" : "Date picker label for when the evidence was captured.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Date" } } } }, - "share.form.kind": { - "comment": "Picker label for the evidence kind.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Kind" + "share.form.kind" : { + "comment" : "Picker label for the evidence kind.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Kind" } } } }, - "share.form.noteHeader": { - "comment": "Section header above the optional note field.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Note" + "share.form.noteHeader" : { + "comment" : "Section header above the optional note field.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Note" } } } }, - "share.form.notePlaceholder": { - "comment": "Placeholder for the optional note text field.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Add a note (optional)" + "share.form.notePlaceholder" : { + "comment" : "Placeholder for the optional note text field.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add a note (optional)" } } } }, - "share.form.otherLabel": { - "comment": "Placeholder for the free-text label shown when the kind is Other.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Label" + "share.form.otherLabel" : { + "comment" : "Placeholder for the free-text label shown when the kind is Other.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Label" } } } }, - "share.loading": { - "comment": "Progress label while the shared attachment is being read.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Preparing…" + "share.loading" : { + "comment" : "Progress label while the shared attachment is being read.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Preparing…" } } } }, - "share.ok": { - "comment": "Dismiss button on the save-failure alert.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "OK" + "share.ok" : { + "comment" : "Dismiss button on the save-failure alert.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" } } } }, - "share.save": { - "comment": "Save button persisting the shared evidence.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Save" + "share.save" : { + "comment" : "Save button persisting the shared evidence.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save" } } } }, - "share.saveError.title": { - "comment": "Title of the alert shown when saving the shared evidence fails.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Couldn't save" + "share.saveError.title" : { + "comment" : "Title of the alert shown when saving the shared evidence fails.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Couldn't save" } } } }, - "share.title": { - "comment": "Navigation title of the share compose sheet.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Save to Where" + "share.title" : { + "comment" : "Navigation title of the share compose sheet.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save to Where" } } } } }, - "version": "1.0" -} + "version" : "1.0" +} \ No newline at end of file diff --git a/Where/WhereUI/Sources/Resources/Localizable.xcstrings b/Where/WhereUI/Sources/Resources/Localizable.xcstrings index 61058231a..55786dd36 100644 --- a/Where/WhereUI/Sources/Resources/Localizable.xcstrings +++ b/Where/WhereUI/Sources/Resources/Localizable.xcstrings @@ -1,267 +1,276 @@ { - "sourceLanguage": "en", - "strings": { - "appIcon.appearance.dark": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Dark" + "sourceLanguage" : "en", + "strings" : { + "" : { + + }, + "%lld" : { + + }, + "Log today here" : { + + }, + "appIcon.appearance.dark" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Dark" } } } }, - "appIcon.appearance.hint": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Tap the icon to preview light and dark." + "appIcon.appearance.hint" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tap the icon to preview light and dark." } } } }, - "appIcon.appearance.light": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Light" + "appIcon.appearance.light" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Light" } } } }, - "appIcon.current": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Current" + "appIcon.current" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Current" } } } }, - "appIcon.error.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Couldn't Change Icon" + "appIcon.error.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Couldn't Change Icon" } } } }, - "appIcon.set": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Set as App Icon" + "appIcon.set" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Set as App Icon" } } } }, - "appIcon.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "App Icon" + "appIcon.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "App Icon" } } } }, - "audit.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Entry record" + "audit.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entry record" } } } }, - "audit.location": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Made at" + "audit.location" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Made at" } } } }, - "audit.location.unavailable": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Not captured" + "audit.location.unavailable" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Not captured" } } } }, - "audit.note": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Note" + "audit.note" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Note" } } } }, - "audit.recordedAt": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Recorded" + "audit.recordedAt" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recorded" } } } }, - "calendar.day.accessibility": { - "comment": "Accessibility label for a calendar day, including the day of the week and the names of the regions that day.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%1$@, %2$@" + "calendar.day.accessibility" : { + "comment" : "Accessibility label for a calendar day, including the day of the week and the names of the regions that day.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@, %2$@" } } } }, - "calendar.day.empty.accessibility": { - "comment": "Accessibility label for a calendar day when no regions have been logged.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%@, nothing logged" + "calendar.day.empty.accessibility" : { + "comment" : "Accessibility label for a calendar day when no regions have been logged.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%@, nothing logged" } } } }, - "calendar.day.hasEvidence.accessibility": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%@, has evidence" + "calendar.day.hasEvidence.accessibility" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%@, has evidence" } } } }, - "calendar.day.needsAttention.accessibility": { - "comment": "Accessibility label for a calendar day that needs attention.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%@, needs a location" + "calendar.day.needsAttention.accessibility" : { + "comment" : "Accessibility label for a calendar day that needs attention.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%@, needs a location" } } } }, - "calendar.region.title": { - "comment": "Title for the calendar when it's focused on a single region, e.g. \"California · 2026\".", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%1$@ · %2$@" + "calendar.region.title" : { + "comment" : "Title for the calendar when it's focused on a single region, e.g. \"California · 2026\".", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ · %2$@" } } } }, - "calendar.title": { - "comment": "Title of the calendar screen, including the year.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Calendar · %@" + "calendar.title" : { + "comment" : "Title of the calendar screen, including the year.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Calendar · %@" } } } }, - "calendar.unavailable.description": { - "comment": "Description of the calendar when the user's year data isn't available.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Your year data isn't available right now." + "calendar.unavailable.description" : { + "comment" : "Description of the calendar when the user's year data isn't available.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Your year data isn't available right now." } } } }, - "common.cancel": { - "comment": "Cancel button text.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Cancel" + "common.cancel" : { + "comment" : "Cancel button text.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Cancel" } } } }, - "common.day": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "day" + "common.day" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "day" } } } }, - "common.dayCount": { - "extractionState": "manual", - "localizations": { - "en": { - "variations": { - "plural": { - "one": { - "stringUnit": { - "state": "translated", - "value": "%lld day" + "common.dayCount" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld day" } }, - "other": { - "stringUnit": { - "state": "translated", - "value": "%lld days" + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld days" } } } @@ -269,973 +278,973 @@ } } }, - "common.days": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "days" + "common.days" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "days" } } } }, - "common.done": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Done" + "common.done" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Done" } } } }, - "common.loadError.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Couldn't load your year" + "common.loadError.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Couldn't load your year" } } } }, - "common.ok": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "OK" + "common.ok" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "OK" } } } }, - "common.regionDays.accessibility": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "%1$@: %2$@" + "common.regionDays.accessibility" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@: %2$@" } } } }, - "common.save": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Save" + "common.save" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Save" } } } }, - "developer.button.label": { - "comment": "Accessibility label for the floating developer button.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Developer tools" + "developer.button.label" : { + "comment" : "Accessibility label for the floating developer button.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Developer tools" } } } }, - "developer.close": { - "comment": "Accessibility label for closing the developer panel.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Close" + "developer.close" : { + "comment" : "Accessibility label for closing the developer panel.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Close" } } } }, - "developer.collapse": { - "comment": "Accessibility label for shrinking the developer panel back to a floating window.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Exit full screen" + "developer.collapse" : { + "comment" : "Accessibility label for shrinking the developer panel back to a floating window.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exit full screen" } } } }, - "developer.dragHandle": { - "comment": "Accessibility label for the handle that drags the floating developer window.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Move developer window" + "developer.dragHandle" : { + "comment" : "Accessibility label for the handle that drags the floating developer window.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Move developer window" } } } }, - "developer.expand": { - "comment": "Accessibility label for growing the developer panel to full screen.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Enter full screen" + "developer.expand" : { + "comment" : "Accessibility label for growing the developer panel to full screen.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Enter full screen" } } } }, - "developer.footer": { - "comment": "Footer for the developer tools list.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "On-device logs and data tools. Debug builds only." + "developer.footer" : { + "comment" : "Footer for the developer tools list.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "On-device logs and data tools. Debug builds only." } } } }, - "developer.inspectorLink": { - "comment": "Label for the navigation link that opens the SwiftData inspector.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "SwiftData Inspector" + "developer.inspectorLink" : { + "comment" : "Label for the navigation link that opens the SwiftData inspector.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "SwiftData Inspector" } } } }, - "developer.inspectorTitle": { - "comment": "Navigation title for the SwiftData inspector screen.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "SwiftData" + "developer.inspectorTitle" : { + "comment" : "Navigation title for the SwiftData inspector screen.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "SwiftData" } } } }, - "developer.logViewMode": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Log View Mode" + "developer.logViewMode" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Log View Mode" } } } }, - "developer.logViewMode.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Reveal an inspect badge on tagged views to open their recent logs." + "developer.logViewMode.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Reveal an inspect badge on tagged views to open their recent logs." } } } }, - "developer.logsLink": { - "comment": "Label for the button that opens the logs screen.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Logs" + "developer.logsLink" : { + "comment" : "Label for the button that opens the logs screen.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logs" } } } }, - "developer.logsTitle": { - "comment": "Title of the screen that shows the user's logs.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Logs" + "developer.logsTitle" : { + "comment" : "Title of the screen that shows the user's logs.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logs" } } } }, - "developer.openSpansLink": { - "comment": "Label for a button that opens the developer's spans.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Open spans" + "developer.openSpansLink" : { + "comment" : "Label for a button that opens the developer's spans.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Open spans" } } } }, - "developer.regionMapLink": { - "comment": "Label for the navigation link that opens the region map.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Region map" + "developer.regionMapLink" : { + "comment" : "Label for the navigation link that opens the region map.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Region map" } } } }, - "developer.resizeHandle": { - "comment": "Accessibility label for the grip that resizes the floating developer window.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Resize developer window" + "developer.resizeHandle" : { + "comment" : "Accessibility label for the grip that resizes the floating developer window.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Resize developer window" } } } }, - "developer.title": { - "comment": "Navigation title of the developer tools list.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Developer" + "developer.title" : { + "comment" : "Navigation title of the developer tools list.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Developer" } } } }, - "evidence.add": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Add evidence" + "evidence.add" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Add evidence" } } } }, - "evidence.detail.noAttachment": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No attachment" + "evidence.detail.noAttachment" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No attachment" } } } }, - "evidence.detail.noPreview.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "This attachment can't be previewed here." + "evidence.detail.noPreview.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "This attachment can't be previewed here." } } } }, - "evidence.detail.noPreview.title": { - "comment": "Title of an alert when an evidence doesn't have a preview.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No preview" + "evidence.detail.noPreview.title" : { + "comment" : "Title of an alert when an evidence doesn't have a preview.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No preview" } } } }, - "evidence.detail.noteHeader": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Note" + "evidence.detail.noteHeader" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Note" } } } }, - "evidence.detail.previewFailed": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Couldn't load this attachment." + "evidence.detail.previewFailed" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Couldn't load this attachment." } } } }, - "evidence.empty.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Attach a boarding pass, receipt, or screenshot to back up where you were. Add one here, or share it into Where from another app." + "evidence.empty.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Attach a boarding pass, receipt, or screenshot to back up where you were. Add one here, or share it into Where from another app." } } } }, - "evidence.empty.title": { - "comment": "Title of the empty state when there is no evidence.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No evidence yet" + "evidence.empty.title" : { + "comment" : "Title of the empty state when there is no evidence.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No evidence yet" } } } }, - "evidence.failed.title": { - "comment": "Title of an alert when loading evidence fails.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Couldn't load evidence" + "evidence.failed.title" : { + "comment" : "Title of an alert when loading evidence fails.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Couldn't load evidence" } } } }, - "evidence.form.attachmentHeader": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Attachment" + "evidence.form.attachmentHeader" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Attachment" } } } }, - "evidence.form.chooseFile": { - "comment": "Label for choosing a file from the file picker in the evidence form.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Choose file" + "evidence.form.chooseFile" : { + "comment" : "Label for choosing a file from the file picker in the evidence form.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Choose file" } } } }, - "evidence.form.choosePhoto": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Choose photo" + "evidence.form.choosePhoto" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Choose photo" } } } }, - "evidence.form.date": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Date" + "evidence.form.date" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Date" } } } }, - "evidence.form.kind": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Kind" + "evidence.form.kind" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Kind" } } } }, - "evidence.form.note": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Note" + "evidence.form.note" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Note" } } } }, - "evidence.form.notePlaceholder": { - "comment": "Placeholder text for the note field in the evidence form.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Add a note (optional)" + "evidence.form.notePlaceholder" : { + "comment" : "Placeholder text for the note field in the evidence form.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Add a note (optional)" } } } }, - "evidence.form.otherLabel": { - "comment": "Label for the \"Other\" field in the evidence form.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Label" + "evidence.form.otherLabel" : { + "comment" : "Label for the \"Other\" field in the evidence form.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Label" } } } }, - "evidence.form.remove": { - "comment": "Label for removing an attached file or photo.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Remove attachment" + "evidence.form.remove" : { + "comment" : "Label for removing an attached file or photo.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Remove attachment" } } } }, - "evidence.form.save": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Save" + "evidence.form.save" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Save" } } } }, - "evidence.form.saveError.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Couldn't save evidence" + "evidence.form.saveError.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Couldn't save evidence" } } } }, - "evidence.kind.boardingPass": { - "comment": "\"Boarding pass\" is a generic term for a travel document that shows a passenger's name, destination, and departure/arrival times.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Boarding pass" + "evidence.kind.boardingPass" : { + "comment" : "\"Boarding pass\" is a generic term for a travel document that shows a passenger's name, destination, and departure/arrival times.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Boarding pass" } } } }, - "evidence.kind.carRental": { - "comment": "The display name for a \"car rental\" evidence kind.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Car rental" + "evidence.kind.carRental" : { + "comment" : "The display name for a \"car rental\" evidence kind.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Car rental" } } } }, - "evidence.kind.document": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Document" + "evidence.kind.document" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Document" } } } }, - "evidence.kind.email": { - "comment": "\"Email\" is a generic term for an", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Email" + "evidence.kind.email" : { + "comment" : "\"Email\" is a generic term for an", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Email" } } } }, - "evidence.kind.hotelReceipt": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Hotel receipt" + "evidence.kind.hotelReceipt" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Hotel receipt" } } } }, - "evidence.kind.other": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Other" + "evidence.kind.other" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Other" } } } }, - "evidence.kind.photo": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Photo" + "evidence.kind.photo" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Photo" } } } }, - "evidence.kind.planeTicket": { - "comment": "\"Plane ticket\"", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Plane ticket" + "evidence.kind.planeTicket" : { + "comment" : "\"Plane ticket\"", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Plane ticket" } } } }, - "evidence.kind.rideshare": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Rideshare" + "evidence.kind.rideshare" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Rideshare" } } } }, - "evidence.list.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Evidence · %@" + "evidence.list.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Evidence · %@" } } } }, - "evidence.row.accessibility": { - "comment": "Accessibility summary for a single evidence row: its kind and captured date, e.g. \"Plane ticket, March 4, 2026\".", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%1$@, %2$@" + "evidence.row.accessibility" : { + "comment" : "Accessibility summary for a single evidence row: its kind and captured date, e.g. \"Plane ticket, March 4, 2026\".", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@, %2$@" } } } }, - "launch.accessibilityLabel": { - "comment": "Spoken by VoiceOver while the launch splash is on screen (the icon and radar animation are decorative and hidden from accessibility).", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Loading" + "launch.accessibilityLabel" : { + "comment" : "Spoken by VoiceOver while the launch splash is on screen (the icon and radar animation are decorative and hidden from accessibility).", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Loading" } } } }, - "launch.caption.subtitle": { - "comment": "Subtitle of the splash's slow-launch caption.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "This only takes a moment." + "launch.caption.subtitle" : { + "comment" : "Subtitle of the splash's slow-launch caption.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "This only takes a moment." } } } }, - "launch.caption.title": { - "comment": "Title of the splash's slow-launch caption; deliberately launch-neutral (a migration, a first install's store creation, or plain slowness).", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Getting things ready…" + "launch.caption.title" : { + "comment" : "Title of the splash's slow-launch caption; deliberately launch-neutral (a migration, a first install's store creation, or plain slowness).", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Getting things ready…" } } } }, - "locations.elsewhere.subtitle": { - "comment": "Subtitle on the Locations tab's Elsewhere entry card: region count.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "^[%lld region](inflect: true)" + "locations.elsewhere.subtitle" : { + "comment" : "Subtitle on the Locations tab's Elsewhere entry card: region count.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "^[%lld region](inflect: true)" } } } }, - "loggedDays.add": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Log a day" + "loggedDays.add" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Log a day" } } } }, - "loggedDays.delete": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Delete entry" + "loggedDays.delete" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Delete entry" } } } }, - "loggedDays.delete.footer": { - "comment": "Explanation of what deleting a logged day does.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Removes this manual entry and restores the day's GPS-detected location." + "loggedDays.delete.footer" : { + "comment" : "Explanation of what deleting a logged day does.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Removes this manual entry and restores the day's GPS-detected location." } } } }, - "loggedDays.deleteError.title": { - "comment": "Title of an alert when a logged-day deletion fails.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Couldn't delete entry" + "loggedDays.deleteError.title" : { + "comment" : "Title of an alert when a logged-day deletion fails.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Couldn't delete entry" } } } }, - "loggedDays.edit.date": { - "comment": "Label for the date row in the logged-day editor.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Day" + "loggedDays.edit.date" : { + "comment" : "Label for the date row in the logged-day editor.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Day" } } } }, - "loggedDays.edit.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Edit day" + "loggedDays.edit.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Edit day" } } } }, - "loggedDays.empty.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Backfill a trip the GPS missed, or correct a day by hand — your manual entries for this year show up here." + "loggedDays.empty.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Backfill a trip the GPS missed, or correct a day by hand — your manual entries for this year show up here." } } } }, - "loggedDays.empty.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No logged days" + "loggedDays.empty.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No logged days" } } } }, - "loggedDays.failed.title": { - "comment": "Title of the alert when loading logged days fails.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Couldn't load logged days" + "loggedDays.failed.title" : { + "comment" : "Title of the alert when loading logged days fails.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Couldn't load logged days" } } } }, - "loggedDays.filter.all": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "All" + "loggedDays.filter.all" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "All" } } } }, - "loggedDays.filter.label": { - "comment": "Accessibility label for the Logged/Overridden/All segmented filter.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Filter" + "loggedDays.filter.label" : { + "comment" : "Accessibility label for the Logged/Overridden/All segmented filter.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Filter" } } } }, - "loggedDays.kind.logged": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Logged" + "loggedDays.kind.logged" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Logged" } } } }, - "loggedDays.kind.overridden": { - "comment": "Label for a logged-day row that's been manually overridden.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Overridden" + "loggedDays.kind.overridden" : { + "comment" : "Label for a logged-day row that's been manually overridden.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Overridden" } } } }, - "loggedDays.noMatches.description": { - "comment": "Description of a message that appears when there are no logged days that match the current filter.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No days match this filter." + "loggedDays.noMatches.description" : { + "comment" : "Description of a message that appears when there are no logged days that match the current filter.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No days match this filter." } } } }, - "loggedDays.noMatches.title": { - "comment": "Title of a screen that shows when there are no logged days that match the filter.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No matching days" + "loggedDays.noMatches.title" : { + "comment" : "Title of a screen that shows when there are no logged days that match the filter.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No matching days" } } } }, - "loggedDays.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Logged Days · %@" + "loggedDays.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Logged Days · %@" } } } }, - "manual.day": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Day" + "manual.day" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Day" } } } }, - "manual.entry.pickerLabel": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Entry" + "manual.entry.pickerLabel" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Entry" } } } }, - "manual.from": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "From" + "manual.from" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "From" } } } }, - "manual.mode.range": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Date range" + "manual.mode.range" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Date range" } } } }, - "manual.mode.singleDay": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Single day" + "manual.mode.singleDay" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Single day" } } } }, - "manual.note.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Saved with this entry for auditing — explain why you made this change." + "manual.note.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Saved with this entry for auditing — explain why you made this change." } } } }, - "manual.note.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Reason" + "manual.note.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reason" } } } }, - "manual.note.placeholder": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Add a note (optional)" + "manual.note.placeholder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Add a note (optional)" } } } }, - "manual.range.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "variations": { - "plural": { - "one": { - "stringUnit": { - "state": "translated", - "value": "Backfilling %lld day." + "manual.range.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "Backfilling %lld day." } }, - "other": { - "stringUnit": { - "state": "translated", - "value": "Backfilling %lld days." + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "Backfilling %lld days." } } } @@ -1243,444 +1252,444 @@ } } }, - "manual.regions.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Saving replaces any manual regions you previously set for those days." + "manual.regions.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Saving replaces any manual regions you previously set for those days." } } } }, - "manual.regions.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Regions" + "manual.regions.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Regions" } } } }, - "manual.save": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Save" + "manual.save" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Save" } } } }, - "manual.saveError.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Couldn't save that day" + "manual.saveError.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Couldn't save that day" } } } }, - "manual.saving.status": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Capturing location…" + "manual.saving.status" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Capturing location…" } } } }, - "manual.singleDay.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Time travel: tell Where where you really were." + "manual.singleDay.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Time travel: tell Where where you really were." } } } }, - "manual.through": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Through" + "manual.through" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Through" } } } }, - "manual.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Log a Day" + "manual.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Log a Day" } } } }, - "missing.banner.accessibilityHint": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Opens the list of days that still need logging." + "missing.banner.accessibilityHint" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Opens the list of days that still need logging." } } } }, - "missing.banner.compact.one": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "1 day needs a location" + "missing.banner.compact.one" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "1 day needs a location" } } } }, - "missing.banner.compact.other": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "%lld days need a location" + "missing.banner.compact.other" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld days need a location" } } } }, - "missingDays.done": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Done" + "missingDays.done" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Done" } } } }, - "missingDays.empty.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Every day this year has something logged." + "missingDays.empty.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Every day this year has something logged." } } } }, - "missingDays.empty.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "All caught up" + "missingDays.empty.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "All caught up" } } } }, - "missingDays.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Tap a stretch to record where you were. Today is included until something logs it." + "missingDays.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tap a stretch to record where you were. Today is included until something logs it." } } } }, - "missingDays.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Days to backfill" + "missingDays.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Days to backfill" } } } }, - "missingDays.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Missing days" + "missingDays.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Missing days" } } } }, - "onboarding.automatic.description": { - "comment": "Description of the automatic location logging feature in the onboarding flow.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "With background location, Where quietly notes the regions you pass through. You can always add or correct days by hand." + "onboarding.automatic.description" : { + "comment" : "Description of the automatic location logging feature in the onboarding flow.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "With background location, Where quietly notes the regions you pass through. You can always add or correct days by hand." } } } }, - "onboarding.automatic.title": { - "comment": "Title of the first onboarding screen, describing how Where automatically logs your location.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "It logs itself" + "onboarding.automatic.title" : { + "comment" : "Title of the first onboarding screen, describing how Where automatically logs your location.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "It logs itself" } } } }, - "onboarding.back": { - "comment": "Back button label in the onboarding flow.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Back" + "onboarding.back" : { + "comment" : "Back button label in the onboarding flow.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Back" } } } }, - "onboarding.continue": { - "comment": "Button text for continuing to the next onboarding step.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Continue" + "onboarding.continue" : { + "comment" : "Button text for continuing to the next onboarding step.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Continue" } } } }, - "onboarding.enableLocation": { - "comment": "Button text to prompt the user to enable location services.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Enable Location" + "onboarding.enableLocation" : { + "comment" : "Button text to prompt the user to enable location services.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Enable Location" } } } }, - "onboarding.location.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Where uses background location to log the regions you pass through. You can change this anytime in Settings." + "onboarding.location.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Where uses background location to log the regions you pass through. You can change this anytime in Settings." } } } }, - "onboarding.location.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Turn on location" + "onboarding.location.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Turn on location" } } } }, - "onboarding.next": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Next" + "onboarding.next" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Next" } } } }, - "onboarding.notNow": { - "comment": "Button title for skipping the onboarding flow.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Not Now" + "onboarding.notNow" : { + "comment" : "Button title for skipping the onboarding flow.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Not Now" } } } }, - "onboarding.privacy.description": { - "comment": "Description of the privacy policy of the app.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Your location stays on your device and in your own iCloud. Turn on background location to start your passport." + "onboarding.privacy.description" : { + "comment" : "Description of the privacy policy of the app.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Your location stays on your device and in your own iCloud. Turn on background location to start your passport." } } } }, - "onboarding.privacy.title": { - "comment": "Title of the privacy section of the onboarding flow.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Private by design" + "onboarding.privacy.title" : { + "comment" : "Title of the privacy section of the onboarding flow.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Private by design" } } } }, - "onboarding.regions.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Where do you spend your time?" + "onboarding.regions.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Where do you spend your time?" } } } }, - "onboarding.restoreBackup": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Restore from a backup" + "onboarding.restoreBackup" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Restore from a backup" } } } }, - "onboarding.restoreError.title": { - "comment": "Title of an alert that appears when a backup can't be restored.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Couldn't restore backup" + "onboarding.restoreError.title" : { + "comment" : "Title of an alert that appears when a backup can't be restored.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Couldn't restore backup" } } } }, - "onboarding.restoring": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Restoring…" + "onboarding.restoring" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Restoring…" } } } }, - "onboarding.welcome.description": { - "comment": "A longer description of Where, for the onboarding welcome screen.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Where keeps a private passport of which regions you spend your days in — built for residency and day-count questions." + "onboarding.welcome.description" : { + "comment" : "A longer description of Where, for the onboarding welcome screen.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Where keeps a private passport of which regions you spend your days in — built for residency and day-count questions." } } } }, - "onboarding.welcome.title": { - "comment": "Title of the onboarding welcome screen.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Where have you been?" + "onboarding.welcome.title" : { + "comment" : "Title of the onboarding welcome screen.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Where have you been?" } } } }, - "primary.calendar": { - "comment": "Label for the primary calendar.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Calendar" + "primary.calendar" : { + "comment" : "Label for the primary calendar.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Calendar" } } } }, - "primary.card.calendarHint": { - "comment": "Accessibility hint on a Primary region card: tapping it opens that region's calendar, filtered to the days spent there.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Opens the calendar of days spent here." + "primary.card.calendarHint" : { + "comment" : "Accessibility hint on a Primary region card: tapping it opens that region's calendar, filtered to the days spent there.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Opens the calendar of days spent here." } } } }, - "primary.elsewhereOnly.description": { - "extractionState": "manual", - "localizations": { - "en": { - "variations": { - "plural": { - "one": { - "stringUnit": { - "state": "translated", - "value": "%lld day logged this year, but none in a headline spot yet." + "primary.elsewhereOnly.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "variations" : { + "plural" : { + "one" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld day logged this year, but none in a headline spot yet." } }, - "other": { - "stringUnit": { - "state": "translated", - "value": "%lld days logged this year, but none in a headline spot yet." + "other" : { + "stringUnit" : { + "state" : "translated", + "value" : "%lld days logged this year, but none in a headline spot yet." } } } @@ -1688,2511 +1697,2511 @@ } } }, - "primary.elsewhereOnly.open": { - "comment": "Button on the Locations elsewhere-only state that opens the Elsewhere list.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "See Elsewhere" + "primary.elsewhereOnly.open" : { + "comment" : "Button on the Locations elsewhere-only state that opens the Elsewhere list.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "See Elsewhere" } } } }, - "primary.elsewhereOnly.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Nothing in your headline spots" + "primary.elsewhereOnly.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nothing in your headline spots" } } } }, - "primary.empty.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Turn on tracking or add a day in Settings and your top spots will land here." + "primary.empty.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Turn on tracking or add a day in Settings and your top spots will land here." } } } }, - "primary.empty.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No travels logged for %@" + "primary.empty.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No travels logged for %@" } } } }, - "primary.evidence": { - "comment": "Label for the \"Evidence\" tab in the primary view.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Evidence" + "primary.evidence" : { + "comment" : "Label for the \"Evidence\" tab in the primary view.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Evidence" } } } }, - "primary.loading": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Charting your year…" + "primary.loading" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Charting your year…" } } } }, - "primary.loggedDays": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Logged days" + "primary.loggedDays" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Logged days" } } } }, - "primary.recentActivity": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Recent activity" + "primary.recentActivity" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Recent activity" } } } }, - "primary.timeline": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Timeline" + "primary.timeline" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Timeline" } } } }, - "recentActivity.empty.description.day": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No locations were recorded in the last 24 hours." + "recentActivity.empty.description.day" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No locations were recorded in the last 24 hours." } } } }, - "recentActivity.empty.description.month": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No locations were recorded in the past month." + "recentActivity.empty.description.month" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No locations were recorded in the past month." } } } }, - "recentActivity.empty.description.week": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No locations were recorded in the past week." + "recentActivity.empty.description.week" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No locations were recorded in the past week." } } } }, - "recentActivity.empty.description.yearToDate": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No locations were recorded so far this year." + "recentActivity.empty.description.yearToDate" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No locations were recorded so far this year." } } } }, - "recentActivity.empty.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Nothing tracked" + "recentActivity.empty.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nothing tracked" } } } }, - "recentActivity.failed.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Couldn't summarize" + "recentActivity.failed.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Couldn't summarize" } } } }, - "recentActivity.footer.day": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "An on-device summary of where you've been in the last 24 hours. Your location never leaves your device." + "recentActivity.footer.day" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "An on-device summary of where you've been in the last 24 hours. Your location never leaves your device." } } } }, - "recentActivity.footer.month": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "An on-device summary of where you've been over the past month. Your location never leaves your device." + "recentActivity.footer.month" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "An on-device summary of where you've been over the past month. Your location never leaves your device." } } } }, - "recentActivity.footer.week": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "An on-device summary of where you've been over the past week. Your location never leaves your device." + "recentActivity.footer.week" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "An on-device summary of where you've been over the past week. Your location never leaves your device." } } } }, - "recentActivity.footer.yearToDate": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "An on-device summary of where you've been so far this year. Your location never leaves your device." + "recentActivity.footer.yearToDate" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "An on-device summary of where you've been so far this year. Your location never leaves your device." } } } }, - "recentActivity.loading": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Summarizing…" + "recentActivity.loading" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Summarizing…" } } } }, - "recentActivity.refresh": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Refresh" + "recentActivity.refresh" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Refresh" } } } }, - "recentActivity.title.day": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Last 24 hours" + "recentActivity.title.day" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Last 24 hours" } } } }, - "recentActivity.title.month": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Past month" + "recentActivity.title.month" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Past month" } } } }, - "recentActivity.title.week": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Past week" + "recentActivity.title.week" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Past week" } } } }, - "recentActivity.title.yearToDate": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Year so far" + "recentActivity.title.yearToDate" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Year so far" } } } }, - "recentActivity.unavailable.appleIntelligenceNotEnabled": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Turn on Apple Intelligence in Settings to generate summaries." + "recentActivity.unavailable.appleIntelligenceNotEnabled" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Turn on Apple Intelligence in Settings to generate summaries." } } } }, - "recentActivity.unavailable.deviceNotEligible": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "This device doesn't support on-device summaries." + "recentActivity.unavailable.deviceNotEligible" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This device doesn't support on-device summaries." } } } }, - "recentActivity.unavailable.modelNotReady": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "The on-device model is still getting ready. Try again shortly." + "recentActivity.unavailable.modelNotReady" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The on-device model is still getting ready. Try again shortly." } } } }, - "recentActivity.unavailable.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Summaries unavailable" + "recentActivity.unavailable.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Summaries unavailable" } } } }, - "recentActivity.unavailable.unknown": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "On-device summaries aren't available right now." + "recentActivity.unavailable.unknown" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "On-device summaries aren't available right now." } } } }, - "recentActivity.window.day": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "24 Hours" + "recentActivity.window.day" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "24 Hours" } } } }, - "recentActivity.window.month": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Month" + "recentActivity.window.month" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Month" } } } }, - "recentActivity.window.pickerLabel": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Summary range" + "recentActivity.window.pickerLabel" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Summary range" } } } }, - "recentActivity.window.week": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Week" + "recentActivity.window.week" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Week" } } } }, - "recentActivity.window.yearToDate": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Year" + "recentActivity.window.yearToDate" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Year" } } } }, - "regionCustomize.color": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Color" + "regionCustomize.color" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Color" } } } }, - "regionCustomize.color.accessibility": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Color %@" + "regionCustomize.color.accessibility" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Color %@" } } } }, - "regionCustomize.emoji": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Emoji" + "regionCustomize.emoji" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Emoji" } } } }, - "regionCustomize.step": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Region %1$lld of %2$lld" + "regionCustomize.step" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Region %1$lld of %2$lld" } } } }, - "regionCustomize.subtitle": { - "comment": "Subtitle for the region customization screen.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Choose a look for %@" + "regionCustomize.subtitle" : { + "comment" : "Subtitle for the region customization screen.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Choose a look for %@" } } } }, - "regionCustomize.symbol": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Icon" + "regionCustomize.symbol" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Icon" } } } }, - "regionCustomize.title": { - "comment": "Title of the screen that lets the user customize a region.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Make it yours" + "regionCustomize.title" : { + "comment" : "Title of the screen that lets the user customize a region.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Make it yours" } } } }, - "regionGroup.more": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "More regions" + "regionGroup.more" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "More regions" } } } }, - "regionGroup.usedThisYear": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Used this year" + "regionGroup.usedThisYear" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Used this year" } } } }, - "regionGroup.yours": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Your regions" + "regionGroup.yours" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Your regions" } } } }, - "regionMap.empty.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No region geometry was found in the bundle." + "regionMap.empty.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No region geometry was found in the bundle." } } } }, - "regionMap.empty.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No regions" + "regionMap.empty.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No regions" } } } }, - "regionMap.kind.attribution": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Attribution" + "regionMap.kind.attribution" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attribution" } } } }, - "regionMap.kind.attribution.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "The simplified polygons the app uses to attribute coordinates today." + "regionMap.kind.attribution.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "The simplified polygons the app uses to attribute coordinates today." } } } }, - "regionMap.kind.picker": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Geometry" + "regionMap.kind.picker" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Geometry" } } } }, - "regionMap.kind.source": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Source" + "regionMap.kind.source" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Source" } } } }, - "regionMap.kind.source.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Every feature decoded straight from the bundled GeoJSON, at full authored fidelity." + "regionMap.kind.source.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Every feature decoded straight from the bundled GeoJSON, at full authored fidelity." } } } }, - "regionMap.legend.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Features" + "regionMap.legend.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Features" } } } }, - "regionMap.loadError.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Couldn't load regions" + "regionMap.loadError.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Couldn't load regions" } } } }, - "regionMap.map.accessibility": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Map of region boundaries" + "regionMap.map.accessibility" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Map of region boundaries" } } } }, - "regionMap.showAll": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Show all" + "regionMap.showAll" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Show all" } } } }, - "regionMap.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Region Map" + "regionMap.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Region Map" } } } }, - "regionPicker.atCapacity": { - "comment": "Shown when the selection is full, so an ignored tap on a new region reads \"at capacity\" rather than \"unresponsive\".", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "That's the maximum of %lld — deselect one to choose another." + "regionPicker.atCapacity" : { + "comment" : "Shown when the selection is full, so an ignored tap on a new region reads \"at capacity\" rather than \"unresponsive\".", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "That's the maximum of %lld — deselect one to choose another." } } } }, - "regionPicker.empty.title": { - "comment": "Title of the empty state when there are no matching regions.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No matching regions" + "regionPicker.empty.title" : { + "comment" : "Title of the empty state when there are no matching regions.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No matching regions" } } } }, - "regionPicker.loadError.title": { - "comment": "Title of an alert when the map fails to load.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Couldn't load the map" + "regionPicker.loadError.title" : { + "comment" : "Title of an alert when the map fails to load.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Couldn't load the map" } } } }, - "regionPicker.map.accessibility": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Map for picking your regions" + "regionPicker.map.accessibility" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Map for picking your regions" } } } }, - "regionPicker.mode.list": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "List" + "regionPicker.mode.list" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "List" } } } }, - "regionPicker.mode.map": { - "comment": "Title of the \"Map\" tab in the region picker.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Map" + "regionPicker.mode.map" : { + "comment" : "Title of the \"Map\" tab in the region picker.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Map" } } } }, - "regionPicker.mode.picker": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "View" + "regionPicker.mode.picker" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "View" } } } }, - "regionPicker.search.prompt": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Search regions" + "regionPicker.search.prompt" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Search regions" } } } }, - "regionPicker.selectionCount": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%1$lld of %2$lld selected" + "regionPicker.selectionCount" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$lld of %2$lld selected" } } } }, - "regionPicker.subtitle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Pick up to 5 regions where you spend your time." + "regionPicker.subtitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Pick up to 5 regions where you spend your time." } } } }, - "regionPicker.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Your regions" + "regionPicker.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Your regions" } } } }, - "regions.manage.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Your regions" + "regions.manage.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Your regions" } } } }, - "relabel.reason.borderDrift": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Some points look like GPS drift near the %@ border." + "relabel.reason.borderDrift" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Some points look like GPS drift near the %@ border." } } } }, - "relabel.reason.borderDrift.distance": { - "comment": "Reason for relabeling a day as a border drift, including a distance.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Some points sit about %1$@ outside %2$@ — likely GPS drift near the border." + "relabel.reason.borderDrift.distance" : { + "comment" : "Reason for relabeling a day as a border drift, including a distance.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Some points sit about %1$@ outside %2$@ — likely GPS drift near the border." } } } }, - "relabel.reason.flight": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "This looked like a flight — high-speed points added %@. Set where you actually were." + "relabel.reason.flight" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "This looked like a flight — high-speed points added %@. Set where you actually were." } } } }, - "relabel.reason.title": { - "comment": "Title of a banner that appears when a day's regions need to be re-labeled.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Why this needs a look" + "relabel.reason.title" : { + "comment" : "Title of a banner that appears when a day's regions need to be re-labeled.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Why this needs a look" } } } }, - "relabel.reason.travelDay": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "The days around this one don't overlap — set where you were if you were traveling." + "relabel.reason.travelDay" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "The days around this one don't overlap — set where you were if you were traveling." } } } }, - "relabel.regions.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "This replaces what was recorded for this day, overriding GPS. Your raw location data is kept, so you can change it back." + "relabel.regions.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This replaces what was recorded for this day, overriding GPS. Your raw location data is kept, so you can change it back." } } } }, - "relabel.regions.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Where were you?" + "relabel.regions.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Where were you?" } } } }, - "relabel.reset": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Reset to GPS-detected location" + "relabel.reset" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reset to GPS-detected location" } } } }, - "relabel.reset.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Removes any manual correction for this day and restores the regions detected from GPS. Your raw location data is untouched." + "relabel.reset.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Removes any manual correction for this day and restores the regions detected from GPS. Your raw location data is untouched." } } } }, - "relabel.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Fix this day" + "relabel.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Fix this day" } } } }, - "resolution.abrupt.detail.bothRight": { - "comment": "Label for a button that marks both days as travel days.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "These are both right" + "resolution.abrupt.detail.bothRight" : { + "comment" : "Label for a button that marks both days as travel days.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "These are both right" } } } }, - "resolution.abrupt.detail.earlier": { - "comment": "Label for the earlier day in the \"Sudden location change\" detail view.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Earlier day" + "resolution.abrupt.detail.earlier" : { + "comment" : "Label for the earlier day in the \"Sudden location change\" detail view.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Earlier day" } } } }, - "resolution.abrupt.detail.explanation": { - "comment": "Explanation of the abrupt location change detail.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "These back-to-back days don't overlap at all — you were probably traveling and one day wasn't logged in both places." + "resolution.abrupt.detail.explanation" : { + "comment" : "Explanation of the abrupt location change detail.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "These back-to-back days don't overlap at all — you were probably traveling and one day wasn't logged in both places." } } } }, - "resolution.abrupt.detail.later": { - "comment": "Label for the column of a row in the \"Sudden location change\" detail view.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Later day" + "resolution.abrupt.detail.later" : { + "comment" : "Label for the column of a row in the \"Sudden location change\" detail view.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Later day" } } } }, - "resolution.abrupt.detail.relabelEarlier": { - "comment": "Label for a button that lets the user mark a day as a travel day when it was previously marked as a non-travel day.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Mark as a travel day" + "resolution.abrupt.detail.relabelEarlier" : { + "comment" : "Label for a button that lets the user mark a day as a travel day when it was previously marked as a non-travel day.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Mark as a travel day" } } } }, - "resolution.abrupt.detail.relabelLater": { - "comment": "Label for a button that relabels a day as a travel day.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Mark as a travel day" + "resolution.abrupt.detail.relabelLater" : { + "comment" : "Label for a button that relabels a day as a travel day.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Mark as a travel day" } } } }, - "resolution.abrupt.detail.title": { - "comment": "Title of a screen that shows a list of abrupt location changes.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Sudden location change" + "resolution.abrupt.detail.title" : { + "comment" : "Title of a screen that shows a list of abrupt location changes.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Sudden location change" } } } }, - "resolution.abrupt.rowTitle": { - "comment": "Title of a row in the resolution screen that shows the regions that the user has been in and the regions that they were in before.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%1$@ → %2$@" + "resolution.abrupt.rowTitle" : { + "comment" : "Title of a row in the resolution screen that shows the regions that the user has been in and the regions that they were in before.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%1$@ → %2$@" } } } }, - "resolution.dismiss": { - "comment": "Label for a button that dismisses a resolution.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Dismiss" + "resolution.dismiss" : { + "comment" : "Label for a button that dismisses a resolution.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Dismiss" } } } }, - "resolution.drift.subtitle": { - "comment": "Subtitle for a row in the resolution screen that describes a location that is near the border.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Looks like %1$@, ~%2$@ over the border" + "resolution.drift.subtitle" : { + "comment" : "Subtitle for a row in the resolution screen that describes a location that is near the border.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Looks like %1$@, ~%2$@ over the border" } } } }, - "resolution.empty.description": { - "comment": "Description of an empty state when there are no resolution issues.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No data issues need your attention right now." + "resolution.empty.description" : { + "comment" : "Description of an empty state when there are no resolution issues.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No data issues need your attention right now." } } } }, - "resolution.empty.title": { - "comment": "Title of the resolution screen when all missing days have been resolved.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "All clear" + "resolution.empty.title" : { + "comment" : "Title of the resolution screen when all missing days have been resolved.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "All clear" } } } }, - "resolution.flight.apply": { - "comment": "Label for a button that applies a resolution that keeps a set of regions.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Keep %@" + "resolution.flight.apply" : { + "comment" : "Label for a button that applies a resolution that keeps a set of regions.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Keep %@" } } } }, - "resolution.flight.bothRight": { - "comment": "Label for a button that lets the user keep all the regions.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "These are all correct" + "resolution.flight.bothRight" : { + "comment" : "Label for a button that lets the user keep all the regions.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "These are all correct" } } } }, - "resolution.flight.detail.explanation": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Some GPS points crossed the map at about %1$@ — that usually means a flight, not somewhere you actually stopped. Applying this keeps where you took off and landed and drops %2$@." + "resolution.flight.detail.explanation" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Some GPS points crossed the map at about %1$@ — that usually means a flight, not somewhere you actually stopped. Applying this keeps where you took off and landed and drops %2$@." } } } }, - "resolution.flight.detail.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Looks like a flight" + "resolution.flight.detail.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Looks like a flight" } } } }, - "resolution.flight.manualFix": { - "comment": "Label for a button that lets the user manually fix a \"looks like a flight\" resolution.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Not what you expected?" + "resolution.flight.manualFix" : { + "comment" : "Label for a button that lets the user manually fix a \"looks like a flight\" resolution.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Not what you expected?" } } } }, - "resolution.flight.manualFix.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "If this wasn't a flight, or you'd rather set the regions yourself, fix the day by hand." + "resolution.flight.manualFix.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "If this wasn't a flight, or you'd rather set the regions yourself, fix the day by hand." } } } }, - "resolution.flight.rowSubtitle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Looks like a flight" + "resolution.flight.rowSubtitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Looks like a flight" } } } }, - "resolution.section.abruptChange": { - "comment": "Label for a section of the resolution screen that lists days with abrupt location changes.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Sudden moves" + "resolution.section.abruptChange" : { + "comment" : "Label for a section of the resolution screen that lists days with abrupt location changes.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Sudden moves" } } } }, - "resolution.section.borderDrift": { - "comment": "Label for a section of the resolution screen that lists days that are near the border.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Near the border" + "resolution.section.borderDrift" : { + "comment" : "Label for a section of the resolution screen that lists days that are near the border.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Near the border" } } } }, - "resolution.section.flightDay": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Flights" + "resolution.section.flightDay" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Flights" } } } }, - "resolution.section.missingDays": { - "comment": "Label for a section of the resolution screen that lists missing days.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Missing days" + "resolution.section.missingDays" : { + "comment" : "Label for a section of the resolution screen that lists missing days.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Missing days" } } } }, - "resolution.title": { - "comment": "Title of a screen that lets the user resolve a missing day.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Resolve" + "resolution.title" : { + "comment" : "Title of a screen that lets the user resolve a missing day.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Resolve" } } } }, - "secondary.caption.passingThrough": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Just passing through" + "secondary.caption.passingThrough" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Just passing through" } } } }, - "secondary.empty.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Spend a day outside your top spots — or log a trip in Settings — and it'll appear here." + "secondary.empty.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Spend a day outside your top spots — or log a trip in Settings — and it'll appear here." } } } }, - "secondary.empty.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Nowhere else logged" + "secondary.empty.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nowhere else logged" } } } }, - "secondary.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Everywhere else you turned up in %@." + "secondary.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Everywhere else you turned up in %@." } } } }, - "secondary.loading": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Retracing your steps…" + "secondary.loading" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Retracing your steps…" } } } }, - "secondary.region.current": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Counts as %@" + "secondary.region.current" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Counts as %@" } } } }, - "secondary.region.empty.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No days counted for this region." + "secondary.region.empty.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No days counted for this region." } } } }, - "secondary.region.empty.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Nothing to fix" + "secondary.region.empty.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Nothing to fix" } } } }, - "secondary.region.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Tap a day to fix where it counted. Your GPS data stays untouched." + "secondary.region.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tap a day to fix where it counted. Your GPS data stays untouched." } } } }, - "secondary.region.map.accessibility": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Map of where you were" + "secondary.region.map.accessibility" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Map of where you were" } } } }, - "secondary.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Elsewhere" + "secondary.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Elsewhere" } } } }, - "settings.alerts.group": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Alerts & Data Resolution" + "settings.alerts.group" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Alerts & Data Resolution" } } } }, - "settings.appIcon.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Pick the icon Where shows on your Home Screen." + "settings.appIcon.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Pick the icon Where shows on your Home Screen." } } } }, - "settings.appIcon.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Appearance" + "settings.appIcon.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appearance" } } } }, - "settings.appIcon.link": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "App icon" + "settings.appIcon.link" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "App icon" } } } }, - "settings.appearance.group": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Appearance" + "settings.appearance.group" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Appearance" } } } }, - "settings.attachments.row": { - "comment": "Row title for the attachments (evidence) screen in the Settings Data group.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Attachments" + "settings.attachments.row" : { + "comment" : "Row title for the attachments (evidence) screen in the Settings Data group.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Attachments" } } } }, - "settings.backup.errorTitle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Backup failed" + "settings.backup.errorTitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Backup failed" } } } }, - "settings.backup.export": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Export data" + "settings.backup.export" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Export data" } } } }, - "settings.backup.exporting": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Exporting…" + "settings.backup.exporting" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Exporting…" } } } }, - "settings.backup.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Export your whole history as a .zip you can email or save to Files, then import it on another device to restore everything." + "settings.backup.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Export your whole history as a .zip you can email or save to Files, then import it on another device to restore everything." } } } }, - "settings.backup.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Backup" + "settings.backup.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Backup" } } } }, - "settings.backup.import": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Import data" + "settings.backup.import" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Import data" } } } }, - "settings.backup.importStrategy.message": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Merge keeps everything already on this device and adds the file's records. Replace erases this device first, then restores only what's in the file." + "settings.backup.importStrategy.message" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Merge keeps everything already on this device and adds the file's records. Replace erases this device first, then restores only what's in the file." } } } }, - "settings.backup.importStrategy.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Import backup" + "settings.backup.importStrategy.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Import backup" } } } }, - "settings.backup.imported.message": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Imported %lld location samples, %lld pieces of evidence, %lld manual days, %lld dismissed issues, and %lld tracked regions." + "settings.backup.imported.message" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Imported %lld location samples, %lld pieces of evidence, %lld manual days, %lld dismissed issues, and %lld tracked regions." } } } }, - "settings.backup.imported.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Backup imported" + "settings.backup.imported.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Backup imported" } } } }, - "settings.backup.importing": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Importing…" + "settings.backup.importing" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Importing…" } } } }, - "settings.backup.merge": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Merge" + "settings.backup.merge" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Merge" } } } }, - "settings.backup.replace": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Replace all" + "settings.backup.replace" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Replace all" } } } }, - "settings.backup.share": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Share backup" + "settings.backup.share" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Share backup" } } } }, - "settings.backup.shareTitle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Where Backup" + "settings.backup.shareTitle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Where Backup" } } } }, - "settings.data.cancel": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Cancel" + "settings.data.cancel" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Cancel" } } } }, - "settings.data.confirmMessage": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "This removes every sample, manual day, and piece of evidence in %@. It can't be undone." + "settings.data.confirmMessage" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "This removes every sample, manual day, and piece of evidence in %@. It can't be undone." } } } }, - "settings.data.erase": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Erase %@ data" + "settings.data.erase" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erase %@ data" } } } }, - "settings.data.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Acts on the year selected on the Primary tab (%@)." + "settings.data.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Acts on the year selected on the Primary tab (%@)." } } } }, - "settings.data.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Data" + "settings.data.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Data" } } } }, - "settings.eraseYear.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Erase year data" + "settings.eraseYear.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Erase year data" } } } }, - "settings.findIssues": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Find issues now" + "settings.findIssues" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Find issues now" } } } }, - "settings.findIssues.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Scan the selected year for data issues right now — such as GPS drift or missed days — instead of waiting for the periodic check. Anything found appears in the Resolve tab." + "settings.findIssues.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Scan the selected year for data issues right now — such as GPS drift or missed days — instead of waiting for the periodic check. Anything found appears in the Resolve tab." } } } }, - "settings.findIssues.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Find issues" + "settings.findIssues.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Find issues" } } } }, - "settings.findIssues.result.many": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "%lld issues to resolve" + "settings.findIssues.result.many" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "%lld issues to resolve" } } } }, - "settings.findIssues.result.none": { - "comment": "Result of a manual \"Find issues now\" scan — the current unresolved count for the year, worded as present state.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No issues to resolve" + "settings.findIssues.result.none" : { + "comment" : "Result of a manual \"Find issues now\" scan — the current unresolved count for the year, worded as present state.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No issues to resolve" } } } }, - "settings.findIssues.result.one": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "1 issue to resolve" + "settings.findIssues.result.one" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "1 issue to resolve" } } } }, - "settings.findIssues.scanning": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Scanning…" + "settings.findIssues.scanning" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Scanning…" } } } }, - "settings.issueAlerts.deniedFooter": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Notifications are turned off for Where, so issue alerts can't appear. Turn them on in Settings." + "settings.issueAlerts.deniedFooter" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notifications are turned off for Where, so issue alerts can't appear. Turn them on in Settings." } } } }, - "settings.issueAlerts.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Badge the app icon and send a reminder when there are data issues waiting in the Resolve tab." + "settings.issueAlerts.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Badge the app icon and send a reminder when there are data issues waiting in the Resolve tab." } } } }, - "settings.issueAlerts.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Issue alerts" + "settings.issueAlerts.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Issue alerts" } } } }, - "settings.issueAlerts.toggle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Issue alerts" + "settings.issueAlerts.toggle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Issue alerts" } } } }, - "settings.keywords.appIcon": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "app icon, icon, home screen, appearance" + "settings.keywords.appIcon" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "app icon, icon, home screen, appearance" } } } }, - "settings.keywords.attachments": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "attachments, evidence, receipt, boarding pass, ticket, photo" + "settings.keywords.attachments" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "attachments, evidence, receipt, boarding pass, ticket, photo" } } } }, - "settings.keywords.dataResolution": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "drift, gps, border, threshold, resolution, distance" + "settings.keywords.dataResolution" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "drift, gps, border, threshold, resolution, distance" } } } }, - "settings.keywords.eraseYear": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "erase, delete, clear, year, data" + "settings.keywords.eraseYear" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "erase, delete, clear, year, data" } } } }, - "settings.keywords.export": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "backup, export, save, share, archive" + "settings.keywords.export" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "backup, export, save, share, archive" } } } }, - "settings.keywords.findIssues": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "scan, find, issues, check, resolve" + "settings.keywords.findIssues" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "scan, find, issues, check, resolve" } } } }, - "settings.keywords.import": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "backup, import, restore, load, archive" + "settings.keywords.import" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "backup, import, restore, load, archive" } } } }, - "settings.keywords.issueAlerts": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "issue, alerts, notification, badge, resolve" + "settings.keywords.issueAlerts" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "issue, alerts, notification, badge, resolve" } } } }, - "settings.keywords.loggedDays": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "logged days, manual, override, entry, backfill" + "settings.keywords.loggedDays" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "logged days, manual, override, entry, backfill" } } } }, - "settings.keywords.regions": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "regions, states, countries, places, primary" + "settings.keywords.regions" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "regions, states, countries, places, primary" } } } }, - "settings.keywords.reminder": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "reminder, notification, nudge, daily, log" + "settings.keywords.reminder" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "reminder, notification, nudge, daily, log" } } } }, - "settings.keywords.reset": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "reset, erase, delete, wipe, start over" + "settings.keywords.reset" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "reset, erase, delete, wipe, start over" } } } }, - "settings.keywords.summary": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "summary, recap, notification, morning, digest" + "settings.keywords.summary" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "summary, recap, notification, morning, digest" } } } }, - "settings.keywords.tracking": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "location, gps, tracking, background, permission" + "settings.keywords.tracking" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "location, gps, tracking, background, permission" } } } }, - "settings.keywords.year": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "year, report, calendar" + "settings.keywords.year" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "year, report, calendar" } } } }, - "settings.location.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Where watches for visits and big moves to figure out which region you're in. It needs Always access and a little patience." + "settings.location.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Where watches for visits and big moves to figure out which region you're in. It needs Always access and a little patience." } } } }, - "settings.location.grant": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Grant location access" + "settings.location.grant" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Grant location access" } } } }, - "settings.location.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Location" + "settings.location.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Location" } } } }, - "settings.location.toggle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Track in the background" + "settings.location.toggle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Track in the background" } } } }, - "settings.loggedDays.row": { - "comment": "Row title for the hand-logged-days screen in the Settings Data group.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Logged Days" + "settings.loggedDays.row" : { + "comment" : "Row title for the hand-logged-days screen in the Settings Data group.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Logged Days" } } } }, - "settings.permissionAlert.message": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Where needs Always location access to log which region you're in. You can grant it in the Settings app." + "settings.permissionAlert.message" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Where needs Always location access to log which region you're in. You can grant it in the Settings app." } } } }, - "settings.permissionAlert.notNow": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Not now" + "settings.permissionAlert.notNow" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Not now" } } } }, - "settings.permissionAlert.openSettings": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Open Settings" + "settings.permissionAlert.openSettings" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Open Settings" } } } }, - "settings.permissionAlert.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Location access needed" + "settings.permissionAlert.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Location access needed" } } } }, - "settings.regions.empty": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "None yet" + "settings.regions.empty" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "None yet" } } } }, - "settings.regions.row": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Primary regions" + "settings.regions.row" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Primary regions" } } } }, - "settings.regions.section": { - "comment": "Label for the settings option to manage your regions.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Regions" + "settings.regions.section" : { + "comment" : "Label for the settings option to manage your regions.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Regions" } } } }, - "settings.reminders.deniedFooter": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Notifications are turned off for Where, so reminders and the badge can't appear. Turn them on in Settings." + "settings.reminders.deniedFooter" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notifications are turned off for Where, so reminders and the badge can't appear. Turn them on in Settings." } } } }, - "settings.reminders.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "If a day hasn't been logged, we'll nudge you before it ends and badge the app. The reminder clears itself once the day is recorded." + "settings.reminders.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "If a day hasn't been logged, we'll nudge you before it ends and badge the app. The reminder clears itself once the day is recorded." } } } }, - "settings.reminders.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Reminders" + "settings.reminders.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Reminders" } } } }, - "settings.reminders.openSettings": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Allow notifications" + "settings.reminders.openSettings" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Allow notifications" } } } }, - "settings.reminders.time": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Remind me at" + "settings.reminders.time" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Remind me at" } } } }, - "settings.reminders.toggle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Daily logging reminder" + "settings.reminders.toggle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Daily logging reminder" } } } }, - "settings.reset.confirm": { - "comment": "Button text for erasing all data and resetting the app.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Erase Everything & Reset" + "settings.reset.confirm" : { + "comment" : "Button text for erasing all data and resetting the app.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Erase Everything & Reset" } } } }, - "settings.reset.erase": { - "comment": "Label for the button to erase all data and reset the app.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Erase all data & reset" + "settings.reset.erase" : { + "comment" : "Label for the button to erase all data and reset the app.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Erase all data & reset" } } } }, - "settings.reset.footer": { - "comment": "Footer for the reset confirmation dialog.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Starts over from scratch, as if you'd just installed Where." + "settings.reset.footer" : { + "comment" : "Footer for the reset confirmation dialog.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Starts over from scratch, as if you'd just installed Where." } } } }, - "settings.reset.message": { - "comment": "Confirmation message for the reset action.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "This erases every sample, manual day, and piece of evidence on this device and returns you to first-run setup. It can't be undone." + "settings.reset.message" : { + "comment" : "Confirmation message for the reset action.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "This erases every sample, manual day, and piece of evidence on this device and returns you to first-run setup. It can't be undone." } } } }, - "settings.resolution.footer": { - "comment": "Footer for the settings screen that explains the meaning of the resolution distance.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Days logged just outside a primary region within this distance are flagged as possible GPS drift." + "settings.resolution.footer" : { + "comment" : "Footer for the settings screen that explains the meaning of the resolution distance.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Days logged just outside a primary region within this distance are flagged as possible GPS drift." } } } }, - "settings.resolution.header": { - "comment": "Title of the settings screen for data resolution.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Data resolution" + "settings.resolution.header" : { + "comment" : "Title of the settings screen for data resolution.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Data resolution" } } } }, - "settings.resolution.threshold": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Drift threshold" + "settings.resolution.threshold" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Drift threshold" } } } }, - "settings.search.prompt": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Search settings" + "settings.search.prompt" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Search settings" } } } }, - "settings.status.alwaysPaused": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Always allowed (paused)" + "settings.status.alwaysPaused" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Always allowed (paused)" } } } }, - "settings.status.denied": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Location access denied" + "settings.status.denied" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Location access denied" } } } }, - "settings.status.notDetermined": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Location access not set up" + "settings.status.notDetermined" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Location access not set up" } } } }, - "settings.status.restricted": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Location access restricted" + "settings.status.restricted" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Location access restricted" } } } }, - "settings.status.tracking": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Tracking in the background" + "settings.status.tracking" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Tracking in the background" } } } }, - "settings.status.whenInUse": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "While Using only — needs Always" + "settings.status.whenInUse" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "While Using only — needs Always" } } } }, - "settings.summary.deniedFooter": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Notifications are turned off for Where, so the daily summary can't appear. Turn them on in Settings." + "settings.summary.deniedFooter" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Notifications are turned off for Where, so the daily summary can't appear. Turn them on in Settings." } } } }, - "settings.summary.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Get a morning recap of how many days you've logged in each region so far this year." + "settings.summary.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Get a morning recap of how many days you've logged in each region so far this year." } } } }, - "settings.summary.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Daily summary" + "settings.summary.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Daily summary" } } } }, - "settings.summary.time": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Send at" + "settings.summary.time" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Send at" } } } }, - "settings.summary.toggle": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Daily summary" + "settings.summary.toggle" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Daily summary" } } } }, - "settings.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Settings" + "settings.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" } } } }, - "settings.year.footer": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Choose which year your reports, calendar, and logged days cover." + "settings.year.footer" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Choose which year your reports, calendar, and logged days cover." } } } }, - "settings.year.header": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Report year" + "settings.year.header" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Report year" } } } }, - "settings.year.label": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Year" + "settings.year.label" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Year" } } } }, - "tab.locations": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Locations" + "tab.locations" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Locations" } } } }, - "tab.resolution": { - "comment": "Label for the tab that shows data issues to resolve.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Resolve" + "tab.resolution" : { + "comment" : "Label for the tab that shows data issues to resolve.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Resolve" } } } }, - "tab.settings": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Settings" + "tab.settings" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Settings" } } } }, - "tab.year": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Your Year" + "tab.year" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Your Year" } } } }, - "timeline.empty.description": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Once Where has a run of days in a region, your stays will appear here." + "timeline.empty.description" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Once Where has a run of days in a region, your stays will appear here." } } } }, - "timeline.empty.title": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "No stays yet" + "timeline.empty.title" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "No stays yet" } } } }, - "timeline.row.accessibility": { - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "%1$@, %2$@, %3$@" + "timeline.row.accessibility" : { + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "%1$@, %2$@, %3$@" } } } }, - "widget.today.empty": { - "comment": "Text displayed in the widget when no data is available for the current day.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Nothing logged yet" + "widget.today.empty" : { + "comment" : "Text displayed in the widget when no data is available for the current day.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Nothing logged yet" } } } }, - "widget.today.title": { - "comment": "Title of the \"Today\" section in a widget.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Today" + "widget.today.title" : { + "comment" : "Title of the \"Today\" section in a widget.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Today" } } } }, - "widget.year.empty": { - "comment": "Text displayed in a widget when there are no days logged in a year.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "No days logged" + "widget.year.empty" : { + "comment" : "Text displayed in a widget when there are no days logged in a year.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "No days logged" } } } }, - "widget.year.title": { - "comment": "Title of a year widget.", - "extractionState": "manual", - "isCommentAutoGenerated": true, - "localizations": { - "en": { - "stringUnit": { - "state": "new", - "value": "Days in %@" + "widget.year.title" : { + "comment" : "Title of a year widget.", + "extractionState" : "manual", + "isCommentAutoGenerated" : true, + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "new", + "value" : "Days in %@" } } } }, - "year.segmentPicker": { - "comment": "Accessibility label for the Your Year tab's segmented control.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Year view" + "year.segmentPicker" : { + "comment" : "Accessibility label for the Your Year tab's segmented control.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Year view" } } } } }, - "version": "1.1" -} + "version" : "1.1" +} \ No newline at end of file diff --git a/Where/WhereWidgets/Resources/Localizable.xcstrings b/Where/WhereWidgets/Resources/Localizable.xcstrings index 3a16296ae..2acc1aea5 100644 --- a/Where/WhereWidgets/Resources/Localizable.xcstrings +++ b/Where/WhereWidgets/Resources/Localizable.xcstrings @@ -1,54 +1,54 @@ { - "sourceLanguage": "en", - "strings": { - "widget.gallery.today.description": { - "comment": "Widget gallery description for the Today widget.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Which region today counts for." + "sourceLanguage" : "en", + "strings" : { + "widget.gallery.today.description" : { + "comment" : "Widget gallery description for the Today widget.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Which region today counts for." } } } }, - "widget.gallery.today.name": { - "comment": "Widget gallery name for the Today widget.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Today" + "widget.gallery.today.name" : { + "comment" : "Widget gallery name for the Today widget.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Today" } } } }, - "widget.gallery.yearTotals.description": { - "comment": "Widget gallery description for the year totals widget.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Days spent in each region this year." + "widget.gallery.yearTotals.description" : { + "comment" : "Widget gallery description for the year totals widget.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Days spent in each region this year." } } } }, - "widget.gallery.yearTotals.name": { - "comment": "Widget gallery name for the year totals widget.", - "extractionState": "manual", - "localizations": { - "en": { - "stringUnit": { - "state": "translated", - "value": "Day Counts" + "widget.gallery.yearTotals.name" : { + "comment" : "Widget gallery name for the year totals widget.", + "extractionState" : "manual", + "localizations" : { + "en" : { + "stringUnit" : { + "state" : "translated", + "value" : "Day Counts" } } } } }, - "version": "1.1" -} + "version" : "1.1" +} \ No newline at end of file diff --git a/xcstrings b/xcstrings new file mode 100755 index 000000000..968fa5655 --- /dev/null +++ b/xcstrings @@ -0,0 +1,200 @@ +#!/usr/bin/swift + +// xcstrings — rewrite every String Catalog in the tree the way Xcode itself +// serializes one, and (with --lint) check that they already are. +// +// Why this exists: Xcode rewrites a `.xcstrings` in place during an IDE build +// whenever string extraction finds something the catalog doesn't have yet, and +// it writes the whole file with its own serializer (Foundation's pretty-printed +// JSON: two-space indent, `"key" : value` with a space before the colon, keys +// sorted by code point, no trailing newline). A catalog written by anything else +// — a migration script's `json.dump`, a hand edit — parses fine but differs on +// every line, so the next build in Xcode lands thousands of lines of pure +// serialization noise on top of the one entry it actually added. Keeping the +// checked-in files byte-identical to Xcode's output keeps that diff honest. +// +// This only touches *formatting*. Catalog content — which keys exist, their +// values, comments, and extraction state — belongs to Xcode and the translators; +// normalizing never adds, drops, or edits an entry. See the Localization section +// in Where/AGENTS.md. + +import Foundation + +let usage = """ +Usage: ./xcstrings [options] [path ...] + +Rewrites String Catalogs in Xcode's own serialization (content untouched). +With no paths, walks the repository for every `.xcstrings`. + +Options: + --lint Report catalogs that aren't normalized; write nothing. Exits 1 if any differ. + -h, --help Show this help + +Examples: + ./xcstrings + ./xcstrings --lint + ./xcstrings Where/WhereUI/Sources/Resources/Localizable.xcstrings +""" + +// MARK: - Xcode's serializer + +/// Serializes a parsed catalog the way Xcode's String Catalog writer does. +/// +/// Foundation's `.prettyPrinted` output is the format, with one deviation that +/// matters: `JSONSerialization.WritingOptions.sortedKeys` compares keys +/// case-insensitively, while Xcode sorts them by code point — so a catalog with +/// an auto-extracted `"Log today here"` alongside `"appIcon.title"` orders the +/// capital first. Keys are sorted here and only leaf values are handed to +/// Foundation, which keeps string escaping byte-identical to Xcode's. +struct CatalogSerializer { + enum Failure: Error, CustomStringConvertible { + case unsupportedValue(Any) + + var description: String { + switch self { + case let .unsupportedValue(value): + "unsupported JSON value in catalog: \(type(of: value)) (\(value))" + } + } + } + + func data(from object: Any) throws -> Data { + var output = "" + try write(object, indent: 0, into: &output) + return Data(output.utf8) + } + + private func write(_ value: Any, indent: Int, into output: inout String) throws { + switch value { + case let dictionary as [String: Any]: + try write(dictionary: dictionary, indent: indent, into: &output) + case let array as [Any]: + try write(array: array, indent: indent, into: &output) + default: + output += try fragment(for: value) + } + } + + private func write(dictionary: [String: Any], indent: Int, into output: inout String) throws { + // Foundation renders an empty container as an open brace, a blank line, + // and the closing brace back at the container's own indent. + guard dictionary.isEmpty == false else { + output += "{\n\n\(pad(indent))}" + return + } + output += "{\n" + let keys = dictionary.keys.sorted { $0.utf8.lexicographicallyPrecedes($1.utf8) } + for (offset, key) in keys.enumerated() { + output += "\(pad(indent + 1))\(try fragment(for: key)) : " + try write(dictionary[key]!, indent: indent + 1, into: &output) + output += offset == keys.count - 1 ? "\n" : ",\n" + } + output += "\(pad(indent))}" + } + + private func write(array: [Any], indent: Int, into output: inout String) throws { + guard array.isEmpty == false else { + output += "[\n\n\(pad(indent))]" + return + } + output += "[\n" + for (offset, element) in array.enumerated() { + output += pad(indent + 1) + try write(element, indent: indent + 1, into: &output) + output += offset == array.count - 1 ? "\n" : ",\n" + } + output += "\(pad(indent))]" + } + + /// Renders a leaf through Foundation so escaping matches Xcode exactly: + /// serializing `[value]` and dropping the brackets is the shortest way to + /// reach the same encoder without reimplementing its escape rules. + private func fragment(for value: Any) throws -> String { + guard JSONSerialization.isValidJSONObject([value]) else { + throw Failure.unsupportedValue(value) + } + let data = try JSONSerialization.data(withJSONObject: [value], options: [.withoutEscapingSlashes]) + return String(decoding: data.dropFirst().dropLast(), as: UTF8.self) + } + + private func pad(_ indent: Int) -> String { + String(repeating: " ", count: indent) + } +} + +// MARK: - Command + +func normalized(_ url: URL) throws -> Data { + let original = try Data(contentsOf: url) + let object = try JSONSerialization.jsonObject(with: original, options: []) + let rewritten = try CatalogSerializer().data(from: object) + // A round-trip must preserve content exactly; anything else is a bug here + // rather than something to quietly write over a translator's work. + let reparsed = try JSONSerialization.jsonObject(with: rewritten, options: []) + guard NSDictionary(dictionary: object as? [String: Any] ?? [:]) + .isEqual(to: reparsed as? [String: Any] ?? [:]) + else { + throw CatalogSerializer.Failure.unsupportedValue(object) + } + return rewritten +} + +func catalogs(under root: URL) throws -> [URL] { + let skipped: Set = ["Derived", ".build", ".git", "build"] + var found: [URL] = [] + let enumerator = FileManager.default.enumerator( + at: root, + includingPropertiesForKeys: nil, + options: [.skipsHiddenFiles], + ) + while let url = enumerator?.nextObject() as? URL { + if url.hasDirectoryPath, skipped.contains(url.lastPathComponent) || url.pathExtension == "xcodeproj" { + enumerator?.skipDescendants() + continue + } + if url.pathExtension == "xcstrings" { found.append(url) } + } + return found.sorted { $0.path < $1.path } +} + +var lintOnly = false +var paths: [String] = [] +for argument in CommandLine.arguments.dropFirst() { + switch argument { + case "--lint": lintOnly = true + case "-h", "--help": print(usage); exit(0) + default: + guard argument.hasPrefix("-") == false else { + FileHandle.standardError.write(Data("error: unknown option '\(argument)' (see ./xcstrings --help)\n".utf8)) + exit(1) + } + paths.append(argument) + } +} + +let root = URL(fileURLWithPath: FileManager.default.currentDirectoryPath) +let targets = try paths.isEmpty ? catalogs(under: root) : paths.map { URL(fileURLWithPath: $0) } +var offenders: [String] = [] + +for url in targets { + let display = url.path.replacingOccurrences(of: root.path + "/", with: "") + let rewritten = try normalized(url) + guard try rewritten != Data(contentsOf: url) else { continue } + offenders.append(display) + if lintOnly { + print("not normalized: \(display)") + } else { + try rewritten.write(to: url) + print("normalized: \(display)") + } +} + +if offenders.isEmpty { + let subject = targets.count == 1 ? "catalog already matches" : "catalogs already match" + print("\(targets.count) \(subject) Xcode's serialization.") +} else if lintOnly { + let subject = offenders.count == 1 ? "catalog isn't" : "catalogs aren't" + fflush(stdout) // Keep the summary below the files it counts. + FileHandle.standardError.write(Data("\(offenders.count) \(subject) normalized — run ./xcstrings\n".utf8)) + exit(1) +}