Contributing
OpenVitals is early and practical feedback is valuable.
Useful Bug Reports
Include:
- Device model.
- Android version.
- Health Connect provider and version if known.
- OpenVitals version.
- Which permissions were granted.
- Which screen or workflow failed.
- Whether the data exists in Health Connect.
- Screenshots or logs when they help explain the issue.
Where To Report Issues
Use the Android app repository for app bugs:
codeberg.org/OpenVitals/mobile-app/issues
Use the documentation repository for documentation or website issues:
codeberg.org/OpenVitals/docs/issues
For contributor discussion, join the OpenVitals Zulip:
Development Workflow
OpenVitals is a Kotlin/Jetpack Compose app (Hilt, Room, Health Connect). See Build from source for the toolchain, including the prerequisite that most often bites: the SDK package is platforms;android-37.0, not android-37.
-
Clone the Android app repository.
-
Run the app with
./gradlew :app:installDebug. -
Run the checks before pushing:
./gradlew verifyCi -
Kotlin annotation processing (Hilt, Room) runs as part of the Gradle build; there is no separate code-generation step to run by hand.
-
Keep the local app internet-free.
-
Keep Health Connect writes inside explicit Add entry or edit-entry workflows.
-
Add tests when changing shared behavior, permissions, period selection, formatting, or Health Connect query logic.
Documentation Workflow
- Clone the documentation repository.
- Install npm dependencies.
- Run
npm run devfor local preview. - Run
npm run buildbefore opening a pull request.
git clone https://codeberg.org/OpenVitals/docs.git
cd docs
npm install
npm run buildTranslation Notes
Translate OpenVitals on Codeberg Translate:
translate.codeberg.org/projects/openvitals/mobile-app
Where The Strings Live
App strings are Android string catalogs (strings.xml). Weblate edits them directly and opens pull requests against the app repository, so a hand edit and a Weblate edit are the same kind of change.
app/src/main/res/values/strings.xmlis the template and source language.values-de/,values-es/,values-it/,values-et/are the shipped translations;values-gl/is hosted but below the shipping floor.- The language picker’s coverage data is generated at build time by
scripts/generate-translation-coverage.py; nothing hand-maintained.
When adding or changing user-facing copy, edit the key in values/strings.xml and leave the other locales to Weblate. A missing key falls back to English. Validate with ./gradlew verifyTranslations.
Placeholders Are Android Format Strings
Placeholders use %1$s / %1$d positions, and a literal percent in a formatted string must be written %% — a bare % next to a letter parses as a conversion and crashes the screen that renders it (this shipped once, in four locales). Keep every plural quantity the language needs, even ones the English source does not have; the gate checks the extra branches against the source’s other. Escape apostrophes the Android way: Couldn\'t.
Hosting Versus Shipping
Hosting a language and shipping it are two different things:
- A language is hosted in Codeberg Translate from 0%, so translators have somewhere to put their work.
- A language is shipped — offered in the in-app language picker and matched against the device locale — only once it is above 70% translated and someone adds the corresponding app-language constant. Crossing 70% is a notice from CI, never a build failure.
Shipped app languages today are English, Spanish, German, Italian, and Estonian.