توسعه
Development Guide
Update documentation only under website/docs (English). Translations under website/i18n/<locale>/… are generated and should not be edited manually. Use the translation tasks (e.g., make translate_web_docs_batch) to refresh localized content.
Prerequisites
- Node.js 22+ and npm (tested with Node 22)
 - Thunderbird 128 ESR or newer (for manual testing)
 
Project Layout (high‑level)
- Root: packaging script 
distribution_zip_packer.sh, docs, screenshots sources/: main add-on code (background, options/popup UI, manifests, icons)tests/: Vitest suitewebsite/: Docusaurus docs (with i18n underwebsite/i18n/de/...)
Install & Tooling
- Install root deps: 
npm ci - Docs (optional): 
cd website && npm ci - Discover targets: 
make help 
Live Dev (web‑ext run)
- Quick loop in Firefox Desktop (UI smoke‑tests only):
 npx web-ext run --source-dir sources --target=firefox-desktop- Run in Thunderbird (preferred for MailExtensions):
 npx web-ext run --source-dir sources --start-url about:addons --firefox-binary "$(command -v thunderbird || echo /path/to/thunderbird)"- Tips:
 - Keep Thunderbird’s Error Console open (Tools → Developer Tools → Error Console).
 - MV3 event pages are suspended when idle; reload the add‑on after code changes, or let web‑ext auto‑reload.
 - Some Firefox‑only behaviors differ; always verify in Thunderbird for API parity.
 - Thunderbird binary paths (examples):
 - Linux: 
thunderbird(e.g.,/usr/bin/thunderbird) - macOS: 
/Applications/Thunderbird.app/Contents/MacOS/thunderbird - Windows: 
"C:\\Program Files\\Mozilla Thunderbird\\thunderbird.exe" - Profile isolation: Use a separate Thunderbird profile for development to avoid impacting your daily setup.
 
Make Targets (Alphabetical)
The Makefile standardizes common dev flows. Run make help anytime for a one‑line summary of every target.
Tip: running make with no target opens a simple Whiptail menu to pick a target.
| Target | One‑line description | 
|---|---|
clean | Remove local build/preview artifacts (tmp/, web-local-preview/, website/build/). | 
commit | Format, run tests (incl. i18n), update changelog, commit & push. | 
eslint | Run ESLint via flat config (npm run -s lint:eslint). | 
help | List all targets with one‑line docs (sorted). | 
lint | web‑ext lint on sources/ (temp manifest; ignores ZIPs; non‑fatal). | 
menu | Interactive menu to select a target and optional arguments. | 
pack | Build ATN & LOCAL ZIPs (runs linter; calls packer script). | 
prettier | Format repository in place (writes changes). | 
prettier_check | Prettier in check mode (no writes); fails if reformat needed. | 
prettier_write | Alias for prettier. | 
test | Prettier (write), ESLint, then Vitest (coverage if configured). | 
test_i18n | i18n‑only tests: add‑on placeholders/parity + website parity. | 
translate_app | Alias for translation_app. | 
translation_app | Translate app UI strings from sources/_locales/en/messages.json. | 
translate_web_docs_batch | Translate website docs via OpenAI Batch API (preferred). | 
translate_web_docs_sync | Translate website docs synchronously (legacy, non-batch). | 
translate_web_index | Alias for translation_web_index. | 
translation_web_index | Translate homepage/navbar/footer UI (website/i18n/en/code.json → .../<lang>/code.json). | 
web_build | Build docs to website/build (supports --locales / BUILD_LOCALES). | 
web_build_linkcheck | Offline‑safe link check (skips remote HTTP[S]). | 
web_build_local_preview | Local gh‑pages preview; auto‑serve on 8080–8090; optional tests/link‑check. | 
web_push_github | Push website/build to the gh-pages branch. | 
Syntax for options
- Use 
make <command> OPTS="…"to pass options (quotes recommended). Each target below shows example usage. 
--
Locale build tips
- Build a subset of locales: set 
BUILD_LOCALES="en de"or passOPTS="--locales en,de"to web targets. - Preview a specific locale: 
http://localhost:<port>/Thunderbird-Reply-with-Attachments/de/. 
Build & Package
- Build ZIPs: 
make pack - Produces ATN and LOCAL ZIPs in the repo root (do not edit artifacts by hand)
 - Tip: update version in both 
sources/manifest_ATN.jsonandsources/manifest_LOCAL.jsonbefore packaging - Manual install (dev): Thunderbird → Tools → Add‑ons and Themes → gear → Install Add‑on From File… → select the built ZIP
 
Test
- Full suite: 
make test(Vitest) - Coverage (optional):
 npm i -D @vitest/coverage-v8- Run 
make test; opencoverage/index.htmlfor HTML report - i18n only: 
make test_i18n(UI keys/placeholders/titles + website per‑locale per‑doc parity with id/title/sidebar_label checks) 
Debugging & Logs
- Error Console: Tools → Developer Tools → Error Console
 - Toggle verbose logs at runtime:
 - Enable: 
messenger.storage.local.set({ debug: true }) - Disable: 
messenger.storage.local.set({ debug: false }) - Logs appear while composing/sending replies
 
Docs (website)
- Dev server: 
cd website && npm run start - Build static site: 
cd website && npm run build - Make equivalents (alphabetical): 
make web_build,make web_build_linkcheck,make web_build_local_preview,make web_push_github - Usage examples:
 - EN only, skip tests/link‑check, no push: 
make web_build_local_preview OPTS="--locales en --no-test --no-link-check --dry-run" - All locales, with tests/link‑check, then push: 
make web_build_local_preview && make web_push_github - Before publishing, run the offline‑safe link check: 
make web_build_linkcheck. - i18n: English lives in 
website/docs/*.md; German translations inwebsite/i18n/de/docusaurus-plugin-content-docs/current/*.md - Search: If Algolia DocSearch env vars are set in CI (
DOCSEARCH_APP_ID,DOCSEARCH_API_KEY,DOCSEARCH_INDEX_NAME), the site uses Algolia search; otherwise it falls back to local search. On the homepage, press/orCtrl+Kto open the search box. 
Donate redirect route
website/src/pages/donate.js- Route: 
/donate(and/<locale>/donate) - Behavior:
 - If the current route has a locale (e.g., 
/de/donate), use it - Otherwise, pick the best match from 
navigator.languagesvs configured locales; fall back to default locale - Redirects to:
 en→/docs/donation- others → 
/<locale>/docs/donation - Uses 
useBaseUrlfor proper baseUrl handling - Includes meta refresh + 
noscriptlink as fallback 
Preview Tips
- Stop Node preview cleanly: open 
http://localhost:<port>/__stop(printed afterLocal server started). - If images don’t load in MDX/JSX, use 
useBaseUrl('/img/...')to respect the sitebaseUrl. - The preview starts first; the link check runs afterward and is non‑blocking (broken external links won’t stop the preview).
 - Example preview URL: 
http://localhost:<port>/Thunderbird-Reply-with-Attachments/(printed after “Local server started”). - External links in link‑check: Some external sites (e.g., addons.thunderbird.net) block automated crawlers and may show 403 in link checks. The preview still starts; these are safe to ignore.
 
Translate the Website
What you can translate
- Website UI only: homepage, navbar, footer, and other UI strings. Docs content stays English‑only for now.
 
Where to edit
- Edit 
website/i18n/<locale>/code.json(useenas reference). Keep placeholders like{year},{slash},{ctrl},{k},{code1}unchanged. 
Generate or refresh files
- Create missing stubs for all locales: 
npm --prefix website run i18n:stubs - Overwrite stubs from English (after adding new strings): 
npm --prefix website run i18n:stubs:force - Alternative for a single locale: 
npx --prefix website docusaurus write-translations --locale <locale> 
Translate homepage/navbar/footer UI strings (OpenAI)
- Set credentials once (shell or .env):
 export OPENAI_API_KEY=sk-...- Optional: 
export OPENAI_MODEL=gpt-4o-mini - One‑shot (all locales, skip en): 
make translate_web_index - Limit to specific locales: 
make translate_web_index OPTS="--locales de,fr" - Overwrite existing values: 
make translate_web_index OPTS="--force" 
Validation & retries
- The translation script validates JSON shape, preserves curly‑brace placeholders, and ensures URLs are unchanged.
 - On validation failure, it retries with feedback up to 2 times before keeping existing values.
 
Preview your locale
- Dev server: 
npm --prefix website run start - Visit 
http://localhost:3000/<locale>/Thunderbird-Reply-with-Attachments/ 
Submitting
- Open a PR with the edited 
code.jsonfile(s). Keep changes focused and include a quick screenshot when possible. 
Security & Configuration Tips
- Do not commit 
sources/manifest.json(created temporarily by the build) - Keep 
browser_specific_settings.gecko.idstable to preserve the update channel 
Settings Persistence
- Storage: All user settings live in 
storage.localand persist across add‑on updates. - Install: Defaults are applied only when a key is strictly missing (undefined).
 - Update: A migration fills only missing keys; existing values are never overwritten.
 - Schema marker: 
settingsVersion(currently1). - Keys and defaults:
 blacklistPatterns: string[]→['*intern*', '*secret*', '*passwor*']confirmBeforeAdd: boolean→falseconfirmDefaultChoice: 'yes'|'no'→'yes'warnOnBlacklistExcluded: boolean→true- Code: see 
sources/background.js→initializeOrMigrateSettings()andSCHEMA_VERSION. 
Dev workflow (adding a new setting)
- Bump 
SCHEMA_VERSIONinsources/background.js. - Add the new key + default to the 
DEFAULTSobject ininitializeOrMigrateSettings(). - Use the "only-if-undefined" rule when seeding defaults; do not overwrite existing values.
 - If the setting is user‑visible, wire it in 
sources/options.jsand add localized strings. - Add/adjust tests (see 
tests/background.settings.migration.test.js). 
Manual testing tips
- Simulate a fresh install: clear the extension’s data dir or start with a new profile.
 - Simulate an update: set 
settingsVersionto0instorage.localand re‑load; confirm existing values remain unchanged and only missing keys are added. 
Troubleshooting
- Ensure Thunderbird is 128 ESR or newer
 - Use the Error Console for runtime issues
 - If stored settings appear not to apply properly, restart Thunderbird and try again. (Thunderbird may cache state across sessions; a restart ensures fresh settings are loaded.)
 
CI & Coverage
- GitHub Actions (
CI — Tests) runs vitest with coverage thresholds (85% lines/functions/branches/statements). If thresholds are not met, the job fails. - The workflow uploads an artifact 
coverage-htmlwith the HTML report; download it from the run page (Actions → latest run → Artifacts). 
Contributing
- See CONTRIBUTING.md for branch/commit/PR guidelines
 - Tip: Create a separate Thunderbird development profile for testing to avoid impacting your daily profile.
 
Translations
- Running large “all → all” translation jobs can be slow and expensive. Start with a subset (e.g., a few docs and 1–2 locales), review the result, then expand.
 
- Retry policy: translation jobs perform up to 3 retries with exponential backoff on API errors; see 
scripts/translate_web_docs_batch.jsandscripts/translate_web_docs_sync.js. 
Screenshots for docs
- 
Store images under
website/static/img/. - 
Reference them in MD/MDX via
useBaseUrl('/img/<filename>')so paths work with the sitebaseUrl. - 
After adding or renaming images under
website/static/img/, confirm all references still useuseBaseUrl('/img/…')and render in a local preview. Favicons - 
The multi‑size
favicon.icois generated automatically in all build paths (Make + scripts) viawebsite/scripts/build-favicon.mjs. - 
No manual step is required; updating
icon-*.pngis enough. Review tip - 
Keep the front‑matter
idunchanged in translated docs; translate onlytitleandsidebar_labelwhen present. 
clean
- Purpose: remove local build/preview artifacts.
 - Usage: 
make clean - Removes (if present):
 tmp/web-local-preview/website/build/
commit
- Purpose: format, test, update changelog, commit, and push.
 - Usage: 
make commit - Details: runs Prettier (write), 
make test,make test_i18n; appends changelog when there are staged diffs; pushes toorigin/<branch>. 
eslint
- Purpose: run ESLint via flat config.
 - Usage: 
make eslint 
help
- Purpose: list all targets with one‑line docs.
 - Usage: 
make help 
lint
- Purpose: lint the MailExtension using 
web-ext. - Usage: 
make lint - Notes: temp‑copies 
sources/manifest_LOCAL.json→sources/manifest.json; ignores built ZIPs; warnings do not fail the pipeline. 
menu
- Purpose: interactive menu to select a Make target and optional arguments.
 - Usage: run 
makewith no arguments. - Notes: if 
whiptailis not available, the menu falls back tomake help. 
pack
- Purpose: build ATN and LOCAL ZIPs (depends on 
lint). - Usage: 
make pack - Tip: bump versions in both 
sources/manifest_*.jsonbefore packaging. 
prettier
- Purpose: format the repo in place.
 - Usage: 
make prettier 
prettier_check
- Purpose: verify formatting (no writes).
 - Usage: 
make prettier_check 
prettier_write
- Purpose: alias for 
prettier. - Usage: 
make prettier_write 
test
- Purpose: run Prettier (write), ESLint, then Vitest (coverage if installed).
 - Usage: 
make test