Skip to content

rejifald/movar

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

273 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Movar

Keep the internet in your language.

Stand With Ukraine

Stand With Ukraine code health: 81 (B) coverage: 94% lines · 86% branches content.js: 37 KB (source graph) license: MIT promises: 3/3 kept

See the full metrics report →

Movar is a cross-browser extension that enforces your language preferences. It prioritizes Ukrainian (with English as a fallback) and automatically steers search engines and multilingual sites away from Russian. Optionally, it can also filter unwanted languages out of on-site language pickers and on-page content, blurring or hiding blocked content cards (Beta, off by default).

Why

Many Ukrainian sites ship UA and RU versions but ignore your stated preference and default to Russian. Search engines surface Russian results even with a Ukrainian locale. Movar fixes that automatically, so you never have to choose.

Features

  • Automatic language switching driven by a priority list (default: UA → EN → browser)
  • Extension settings override browser language settings
  • On-page content filtering — strips unwanted-language picker options and blurs or hides content cards (Beta, off by default)
  • Temporary pause (1h / until resumed)

Tech stack

WXT · React · TypeScript · Tailwind CSS · Vitest · Playwright. Targets: Chrome, Firefox, Edge, Opera, Brave, Safari (incl. iOS).

Monorepo layout

apps/extension          # the WXT extension (the published product)
apps/marketing          # the Astro marketing site (movar.fyi)
apps/safari-host-app    # the Safari wrapper's React host screen (Detector/Settings/About), bundled CSP-safe for the WKWebView
apps/e2e                # Playwright end-to-end suites (offline CI + manual live)
apps/diagnostics        # local-only detection diagnostics (dev, never published)
packages/brand          # brand & contact constants (support, feedback, source URLs)
packages/events         # correction-log types (the local dashboard record)
packages/settings       # settings schema, defaults + locked-language invariant
packages/lang-detect    # UA-vs-RU language detection + BCP-47 code normalization
packages/lang-pickers   # on-site language-picker discovery + model (redirect layer)
packages/page-content   # per-site content extractor model (content-filter layer)
packages/page-language  # page-language verdict that drives redirect decisions
packages/page-mode      # page color-scheme (light/dark) detection
packages/host-match     # shared host predicates (isGoogleHost/isYouTubeHost); redirect rules live in apps/extension/src/sites/
packages/app-shell      # shared React shell (mountApp + StrictMode + crash ErrorBoundary) every surface mounts inside
packages/i18n           # UI string catalogues (en/uk) + the browser-free React I18nProvider
packages/options-ui     # shared, storage-agnostic options/popup UI (settings sections + pickers)
packages/theme          # design tokens (colors/space/fonts/radii/breakpoints/sizes): typed source -> generated CSS
packages/ui             # shared design-system primitives (extension + marketing)

Development

pnpm install
pnpm dev            # WXT dev server (Chrome by default)
pnpm build          # build all packages/apps
pnpm lint
pnpm typecheck
pnpm test

For fast popup/options iteration without loading the extension into a browser, the extension ships a static-serve preview that inlines a WebExtension API shim — see apps/extension/preview/README.md. For anything that touches real chrome.storage, the background worker, or content scripts, use pnpm --filter @movar/extension dev:firefox:installed instead.

New to the codebase? CONTRIBUTING.md is the contributor entry point (setup, the two-layer mental model, where a site rule lives, the gate commands), and docs/glossary.md defines the domain jargon (SERP, curtain, the two layers, the package map) so the rest of the docs read clearly.

See apps/extension/AGENTS.md for the extension's architecture overview (entrypoints, the two-layer pipeline, the build). Editing user-facing strings (popup, options, content curtains, marketing site, store listings)? See docs/copy.md — voice, lexicon, mechanics, length-and-register caps.

Metrics

  • Code health 81 (B) — fallow maintainability score, 0-100 with an A-F grade, over complexity, duplication, dead code, and churn; refreshed by pnpm metrics.
  • Coverage 94% lines · 86% branches — Vitest (v8) line and branch coverage, aggregated across the test-bearing workspace projects weighted by size; snapshotted by pnpm metrics.
  • Content.js 37 KB (source graph) — source-graph size of the always-on content script (the esbuild import graph of content.ts, measured by check:content-bundle; the real emitted artifact is ~40 KB, gated at 48 KB by wxt.config.ts) — franc and the language profiles live in the background worker, not here; snapshotted by pnpm metrics.
  • License MIT — SPDX identifier read from the root LICENSE file.
  • Promises 3/3 kept — public claims from movar.fyi (apps/marketing) verified against the code each build — pnpm check:readme fails if any breaks:
    • Open source — root LICENSE is MIT, an OSI-approved open-source license (marketing: hero badge + footer)
    • Nothing leaves your browser — manifest declares data collection 'none', no analytics dependency, and no fetch/XHR/WebSocket/sendBeacon in the extension runtime (marketing: hero badge + privacy section + limitations)
    • On-page filtering stays off until you turn it ondefaultSettings.contentModification is false in @movar/settings — DOM filtering ships opt-in (marketing: how-it-works step 2 + limitations)
  • Permissions 3 requested — browser permissions the extension manifest requests, each scoped to one job:
    • storage — persist your settings, pause state, and the local corrections log (preferences sync; state stays on-device)
    • declarativeNetRequest — rewrite the outgoing Accept-Language request header to your preferred language order via one declarative rule — request and response bodies are never read
    • alarms — auto-resume Movar when a timed (1-hour) pause expires
    • <all_urls> host access — run the language-correction content script on whatever site you allow it — requested at runtime on Chrome/Firefox (a one-click native prompt, see the onboarding page), granted at install on Safari; no page content or browsing history leaves the device
  • Lines of code 40.6k — TypeScript under apps/ + packages/, tests excluded; snapshotted by pnpm metrics.
  • Suppressions 42 eslint-disable · 25 fallow-ignore — inline lint / complexity opt-outs across the tree; the fallow-ignore set is budgeted and each is justified at the call site.

Generated by pnpm gen:readme from committed sources; the code-health score and coverage are snapshotted by pnpm metrics.

Roadmap

Next up (v1.3.0): Movar on the iOS & iPadOS App Stores — macOS is live — plus a card-scoped diagnostics view for maintainers. See docs/ROADMAP.md and the GitHub milestones.

License

MIT

About

Movar — keep the internet in your language. Cross-browser extension that enforces your language preferences (UA first, EN fallback).

Resources

License

Contributing

Stars

6 stars

Watchers

0 watching

Forks

Packages

 
 
 

Contributors