mirror of
https://github.com/sudosylabs/vnidrop.git
synced 2026-08-05 10:29:58 +02:00
Add a second macOS shipping channel alongside the App Store build: - New VniDropDirect target (Release-Direct config) sharing VniDrop's sources via an AppBase target template; links Sparkle behind the DIRECT_DISTRIBUTION flag so the App Store binary never bundles a self-updater. arm64-only (core is arm64). - Sparkle updater (SparkleUpdater.swift) + "Check for Updates" menu, compiled only under DIRECT_DISTRIBUTION; Info.plist SUFeedURL points at the GitHub Release /latest/download/appcast.xml, non-sandboxed entitlements for Developer ID. - build-dmg.sh (archive → Developer ID export → DMG → sign → notarize → staple), generate-appcast.sh, and ExportOptions-DeveloperID.plist. - apple-release.yml: on tag v*.*.*, build/notarize the DMG, publish the GitHub Release with appcast, and push the Homebrew cask to sudosylabs/homebrew-vnidrop. apple.yml gains a PR compile-check of the direct target. - CFBundleVersion is stamped at build time as a UTC YYMMDD.HHMM timestamp for both channels, replacing the hand-maintained build number. - Docs (RELEASE-MACOS.md, README), cask template + tap README, localized updates_check string, Makefile targets, gitignore for dist/ artifacts.
Localization
Single source of truth for every user-facing string, in strings.json.
A Bun CLI generates the platform-native files from it:
| Target | Output | Notes |
|---|---|---|
apple |
apple/VniDrop/Resources/Localizable.xcstrings |
one catalog, all languages nested |
kmp |
shared/src/commonMain/composeResources/values[-lang]/strings.xml |
one file per language |
Workflow
# From the repository root:
make check-localization # structural checks (run before committing)
make localization # regenerate .xcstrings + strings.xml from strings.json
make localization-migrate # one-time: rebuild strings.json from platform files
Never edit the generated .xcstrings / strings.xml by hand — edit strings.json and
regenerate. Regenerated output is deterministic (sorted keys), so diffs stay small.
strings.json format
{
"sourceLanguage": "en",
"supportedLanguages": ["en", "fr"],
"strings": {
"send_title": {
"context": "Send tab — screen title.",
"translations": { "en": "Send", "fr": "Envoyer" }
},
"send_selected_files_count": {
"context": "Send flow — number of files chosen before creating a transfer.",
"targets": ["kmp", "apple"],
"args": [{ "name": "count", "type": "int" }],
"plural": {
"en": { "one": "{count} file selected", "other": "{count} files selected" },
"fr": { "one": "{count} fichier sélectionné", "other": "{count} fichiers sélectionnés" }
}
}
}
}
Fields
context(required) — where the string appears and its purpose. Emitted as the.xcstringscomment and an XML comment; also the note translators see.targets(optional) —["kmp", "apple"]. Omit to mean all targets.args(optional) — ordered list of{ name, type },type∈string | int | double. Referenced in text as{name}.translations— flat text per language. Mutually exclusive withplural.plural— per language, per CLDR category (zero,one,two,few,many,other).otheris always required.
Placeholders
Write named tokens {count}, {name} in text. The generator converts them to the right
positional token per platform, using the declared type:
| type | Apple | Android/KMP |
|---|---|---|
string |
%N$@ |
%N$s |
int |
%N$d |
%N$d |
double |
%N$f |
%N$f |
A literal % in text is emitted as %% whenever the string has args.
Adding a language
Add its code to supportedLanguages, fill in translations / plural for each key, then
generate. KMP gets a new values-<lang>/strings.xml; Apple gets the language inside the
single catalog. validate warns about any key still missing that language.
Migration notes (from the initial import)
- Apple keys that were literal English strings (
"%@ · %@") were imported verbatim — rename them to semantic keys and update the Swift call sites. - Arg names default to
arg1,arg2… (a lone int arg becomescount). Rename for clarity; keep the{token}in text in sync. - Folding
transfer_file_count_one/_otherinto the plural keytransfer_file_countrequires switching the KMP call site fromRes.string.transfer_file_count_oneto the Compose plural API (pluralStringResource(Res.plurals.transfer_file_count, count, count)), and the Apple side to automatic plural inflection.