English | 中文
An unofficial, community-maintained lens database and navigation site for the L-Mount lens mount system. It indexes lenses from L-Mount Alliance members (Leica, Panasonic, Sigma, and other brands publicly listed at l-mount.com) as well as third-party manufacturers that make L-Mount lenses (TTArtisan, 7Artisans, Laowa, and others) — clearly labeled so the two are never confused.
This project is not affiliated with, sponsored by, or endorsed by Leica
Camera AG, the L-Mount Alliance, Panasonic, Sigma, or any other manufacturer.
"L-Mount" is a trademark of Leica Camera AG. See
/about for the full disclaimer.
All 168 stored entries were individually reviewed on 2026-10-21. Native L-Mount availability is confirmed for all 168, including the original Meike 85mm F1.8 STM after its archived manufacturer page was recovered. Evidence gaps are displayed as “Awaiting confirmation”, rather than inferred specifications. See the review report and the site's /data-audit page. Passing the data validator checks structure and evidence coverage; it does not independently prove factual accuracy.
- A fast, searchable, filterable directory of L-Mount lenses — a single page you can scan on desktop or mobile to compare specs.
- Clear, honest labeling of official Alliance-member lenses vs. third-party L-Mount lenses, without implying certification that doesn't exist.
- Fully data-driven: every lens page is generated from structured data, not hand-written HTML, so adding a lens is a data change, not a code change.
- Easy for anyone to contribute a correction or a new lens via pull request.
- Astro (static output) — no client-side framework; pages are plain HTML/CSS with small vanilla-JS islands for search/filter and lens comparison.
- TypeScript for data types and page logic.
- Data lives in
src/data/lenses.json, validated by a Node script before every build. - Bilingual (English/Chinese) by static generation: every page is rendered once per language at build time, so there is no client-side translation pass.
- No backend, no database — deploys as static files to GitHub Pages.
src/
data/lenses.json # the lens database (edit this to add/update lenses)
lib/types.ts # TypeScript shape of a lens entry
lib/lenses.ts # data-loading & formatting helpers
lib/locales.js # the locale registry: which languages the site ships
lib/i18n.ts # build-time translation + locale-aware URL helpers
lib/i18n-dict.js # the EN/ZH UI string dictionary
components/ # LensCard, LensTable, FilterBar, Header, Footer, Compare*
layouts/Layout.astro # shared HTML shell, SEO meta, hreflang, language redirect
pages/[...locale]/index.astro # home page: searchable/filterable lens list
pages/[...locale]/lenses/[id].astro # lens detail page (one per lens, auto-generated)
pages/[...locale]/about.astro # About & Disclaimer page
pages/[...locale]/compare.astro # side-by-side lens comparison page
scripts/filter.js # client-side search/filter/sort/view-toggle
scripts/compare.js # client-side lens-comparison selection
scripts/i18n.js # runtime t() for JS-generated strings; remembers language choice
scripts/validate-data.mjs # data validation script (required fields, ids, URLs, notes locales)
Every route lives under pages/[...locale]/. Astro generates one static page
per language from each of them (see Languages below).
The site ships in English and Chinese. Every page is server-rendered once per language at build time, so the HTML the browser receives is already in the right language — there is no runtime translation pass and therefore no wrong-language flash to hide.
- URLs: the default language (English) is served un-prefixed —
/,/about,/compare,/lenses/<id>. Every other language is served under its own prefix —/zh/,/zh/about,/zh/compare,/zh/lenses/<id>. With 168 stored lenses and 2 languages, including the audit page, the build emits 344 pages (172 per language). - First visit: a small blocking inline script in
<head>, present on un-prefixed pages only, picks a language — in order of precedence: an explicitly saved choice (localStorage), then the browser'snavigator.languages, then English. If that resolves to a non-default language it redirects to the prefixed URL before the body is parsed, so nothing has painted yet. Locale-prefixed URLs never redirect: an explicit URL always wins, stays shareable, and cannot bounce in a loop. - Switching: the language switcher in the header is a plain link to the same page in the other language, so it works with JavaScript disabled. Clicking it also saves the choice, which the first-visit redirect honours next time.
- SEO: each language has its own indexable URL, its own translated
<title>and<meta name="description">, a per-language canonical, and<link rel="alternate" hreflang>entries for every language plusx-default. - Tradeoff: with JavaScript disabled, a visitor whose browser is set to Chinese and who lands on an un-prefixed URL gets the English page (the language link still works). A Chinese visitor's first hit to an un-prefixed URL also costs one extra client-side redirect.
- Add an entry to
src/lib/locales.js— the locale code (which becomes the URL prefix), the<html lang>value, the language's own name for itself (used as the switcher's link text), and thenavigator.languageprefixes that should match it. - Add that locale's section to
src/lib/i18n-dict.js, including abrand.<Brand>key for every brand. - Optionally add
notes.<code>to entries insrc/data/lenses.json— anything you don't translate falls back to English.
That is the whole change. The routes, the hreflang alternates, the language
switcher, the first-visit redirect and the client-side search index all derive
from the registry in locales.js — no other code needs to be touched.
See CONTRIBUTING.md for the full guide. Short version:
- Add an entry to
src/data/lenses.jsonfollowing the shape insrc/lib/types.ts. - Set
allianceMemberaccurately —trueonly for lenses from a brand that is a publicly listed L-Mount Alliance member; the authoritative roster is the member list at l-mount.com. The brands currently flagged as members in this dataset are Leica, Panasonic, Samyang, Sigma, Sirui and Viltrox. Everything else isfalse. - Write
notesas an object keyed by locale code, e.g.{ "en": "...", "zh": "..." }. The"en"entry is required; every other language is optional and falls back to English. - Include at least one
sourceUrlsentry citing where the specs came from. - Run
npm run validate:dataand fix any reported errors. - Open a pull request.
No other code changes are needed — the list page, filters, and detail page are all generated automatically from the data file.
Requires Node.js 18+.
npm install
npm run dev # starts a local dev server with hot reloadOther scripts:
npm run validate:data # validate src/data/lenses.json
npm run build # validate data, then build the static site to dist/
npm run preview # preview the production build locally
npm run lint # type-check the project (astro check)This repo includes a GitHub Actions workflow (.github/workflows/deploy.yml)
that builds and deploys the site to GitHub Pages automatically on every push
to main.
To enable it on your fork/repo:
- In your GitHub repo, go to Settings → Pages and set Source to GitHub Actions.
- Open
astro.config.mjsand update:site— your GitHub Pages URL, e.g.https://your-username.github.ioREPO_NAME— your repository name (used to build thebasepath, e.g./L-Mount-Lens-Guide/). If you deploy to a custom domain or a<user>.github.ioroot repo, setbaseto/instead.
- Push to
main. The workflow builds the site withnpm run buildand publishes thedist/folder to GitHub Pages.
To deploy manually instead:
npm run build
# then publish the contents of dist/ to your GitHub Pages branch/host of choice- Code: MIT
- Lens data (
src/data/lenses.json): CC BY-SA 4.0 — see that file for the reasoning and what it requires of reusers.
This is a hobby/community open-source project, not an official resource from
any camera or lens manufacturer. Third-party (non-Alliance) lens listings
indicate only that the manufacturer offers or claims an L-Mount version of
that product — not that it has been certified or endorsed by the L-Mount
Alliance. Always verify specifications with the manufacturer before
purchasing. Full disclaimer: src/pages/[...locale]/about.astro (rendered at
/about, and at /zh/about in Chinese).