First off, thanks for considering contributing to GitWand! Every contribution helps make Git conflict resolution better for everyone.
git clone https://github.com/devlint/GitWand.git
cd GitWand
pnpm install
pnpm build
pnpm testRequires Node.js 18+ and pnpm 9+.
packages/core/ → Resolution engine (the brains)
packages/cli/ → CLI wrapper
packages/vscode/ → VS Code extension (WIP)
apps/desktop/ → Standalone app with Tauri + Vue 3
Open an issue with a minimal reproduction. If you can include the conflicted file content (with markers), that's ideal — it can become a test fixture.
- Add the pattern type to
ConflictTypeinpackages/core/src/types.ts - Add detection logic in
classifyConflict()inpackages/core/src/parser.ts - Add resolution logic in
resolveHunk()inpackages/core/src/resolver.ts - Add test fixtures and tests in
packages/core/src/__tests__/resolver.test.ts - Run
pnpm test— all tests must pass
The best way to improve patterns is to find real-world conflict cases where GitWand fails or misclassifies. Add them as test fixtures and adjust the logic.
- TypeScript strict mode
- Prefer explicit types over inference for public APIs
- Comments in French or English — both are welcome
- Every auto-resolution must include a human-readable
explanationstring
GitWand uses a lightweight, type-safe i18n system without external dependency. All user-facing strings must go through the translation system.
apps/desktop/src/
locales/
fr.ts → French (reference locale, defines the type shape)
en.ts → English
index.ts → Registry, detection, exports
composables/
useI18n.ts → Reactive composable: t(), setLocale(), locale
fr.ts is the source of truth. It defines the Locale type via as const + Widen<>. Every other locale file must match its exact structure — TypeScript will error if a key is missing or extra.
useI18n() composable provides a t(key, ...args) function that resolves dotted keys ("header.open") into the translated string for the current locale. It supports positional interpolation: t("sidebar.commitButton", 3) produces "Commit (3)".
Language detection uses navigator.language (e.g. "fr-FR" is extracted to "fr"). Users can override via Settings; the preference is stored in localStorage under gitwand-locale. Passing null to setLocale() reverts to OS auto-detection.
- Copy
apps/desktop/src/locales/fr.tstoxx.ts(e.g.de.tsfor German) - Translate all string values (keep the same object structure)
- Import:
import type { Locale } from "./fr";and type asconst xx: Locale = { ... } - Register in
apps/desktop/src/locales/index.ts:- Import the new file
- Add to
localesrecord - Add a label in
localeLabels(e.g.de: "Deutsch") - Add to the
SupportedLocaletype union
- Build and verify:
pnpm build— TypeScript will flag any missing keys
<script setup lang="ts">
import { useI18n } from "../composables/useI18n";
const { t } = useI18n();
</script>
<template>
<button>{{ t('header.open') }}</button>
<span>{{ t('sidebar.commitButton', repoStats.staged) }}</span>
</template>Keys are hierarchical and grouped by component area: header.open, sidebar.tabChanges, merge.keepOurs.
Interpolation uses {0}, {1}, etc. for positional arguments.
Pluralization is handled with separate keys when needed: header.file / header.files.
Git terminology (commit, push, pull, stage, merge) can stay in English even in French locale — these are universally understood by developers. Exception: non-technical labels like section headers or button tooltips should be translated.
When you add a new user-facing string:
- Add the key + French value to
fr.ts - Add the key + English value to
en.ts - Use
t('your.key')in the component - Build — if you forget a key in any locale, TypeScript will catch it
Never hardcode strings directly in templates or scripts. All UI text goes through t().
- Keep PRs focused on a single change
- Include tests for new functionality
- Run
pnpm build && pnpm testbefore submitting - Describe why the change is needed, not just what it does
By contributing, you agree that your contributions will be licensed under the MIT License.