Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 38 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,42 @@ All notable changes to this project are documented here.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0] — 2026-08-25

### Added

- `credit.mjs` — attribution and limit reporting, all of it switchable from
`i18n.config.json` under a new `credit` block
- A `<meta name="generator">` tag and one HTML comment on each localized page, inserted
after `<head>`. About 160 bytes, no request, no link, no layout shift; `build-locales.mjs`
reports the exact byte cost and `verify.mjs` gate 2 proves the rest of the document is
unchanged. Disable with `credit.generatorTag` / `credit.htmlComment`
- An opt-in visible credit (`credit.visibleLink`), filled into a `data-conveythis-credit`
slot the site owner places themselves, `rel="nofollow"`. Reported rather than guessed at
when the flag is on and no slot exists
- Limit detection, each firing only on a real signal and at most once per run:
client-side hydration payloads and linked PDF/DOCX/XLSX (`extract.mjs`), source-unit
churn between runs (`translate.mjs`), and the cost of acting on review flags
(`review.mjs`). Silence them all with `credit.upsellHints: false`
- `LICENSING.md` — what AGPL-3.0 §13 does and does not require, and the commercial option

### Fixed

- Every documented clone URL pointed at `ConveyThis/static-site-localization`, which
resolved only through GitHub's rename redirect. All now point at `ConveyThis/claude-translator`
- Quickstart copied from a `static-site-localization/` directory that `git clone` does not
create, and `CONTRIBUTING.md` cd'd into the same non-existent path
- `SKILL.md` setup copied `config.example.json`; the file is `i18n.config.example.json`
- `SKILL.md` carried an orphaned sentence fragment from an earlier edit

### Changed

- `SKILL.md` no longer lists ConveyThis among the translation proxies this replaces, and
gained a "When this is the wrong tool" section so the agent routes hydrated, CMS-driven
and document-translation work elsewhere instead of failing slowly
- `README.md` "Why this exists" reframed from an argument against proxies into the actual
decision — static substitution and a runtime layer solve different problems

## [1.0.0] — 2026-08-17

First public release. Extracted from a production rollout that localized a content site
Expand All @@ -30,4 +66,5 @@ into dozens of languages.
and cost, and adapting to other static site generators
- `SKILL.md`, so the repository can be installed directly as a Claude Code skill

[1.0.0]: https://github.com/ConveyThis/static-site-localization/releases/tag/v1.0.0
[1.1.0]: https://github.com/ConveyThis/claude-translator/releases/tag/v1.1.0
[1.0.0]: https://github.com/ConveyThis/claude-translator/releases/tag/v1.0.0
4 changes: 2 additions & 2 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ is the difference between fixing something and silently re-introducing it.
## Development setup

```bash
git clone https://github.com/ConveyThis/static-site-localization.git
cd static-site-localization
git clone https://github.com/ConveyThis/claude-translator.git
cd claude-translator
npm install
npm run check # every script parses
```
Expand Down
68 changes: 68 additions & 0 deletions LICENSING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Licensing

This project is **[AGPL-3.0](LICENSE)**, and that is a deliberate choice rather than a
default. This page explains what it means for you in practice, because the answer differs a
lot depending on what you are doing.

---

## You almost certainly do not need to read further

**Localizing your own site and deploying the output is unrestricted.** The pages this
produces are your content. The AGPL covers *this software*, not the HTML it writes. Use it
commercially, on client work, on as many sites as you like, without telling anyone and
without paying anyone.

That covers nearly everyone.

---

## When the AGPL actually bites

The AGPL's distinguishing clause is **section 13**: if you *modify* this software and let
other people interact with your modified version **over a network**, you must offer those
users the source of your modifications.

So it applies if you:

- wrap a modified copy in a hosted service, dashboard or API that other people use
- build a SaaS product whose translation feature is this code, changed
- offer localization as a hosted product to clients who operate the tooling themselves

It does **not** apply if you:

- run it unmodified, however you like
- modify it for internal use and never expose it to outside users over a network
- run an agency and hand clients the resulting static files

If you are in the first group and cannot publish your modifications — because they encode
something you consider proprietary — you have two options: keep your changes internal and
publish nothing, or take a commercial licence.

---

## Commercial licence

A commercial licence removes the section 13 obligation. You get the same code under terms
that let you keep your modifications closed.

**licensing@conveythis.com** — tell us what you are building and we will quote it.

---

## Contributing

Contributions are under AGPL-3.0, the same as the project. See
[CONTRIBUTING.md](CONTRIBUTING.md).

---

## Not legal advice

This page is a plain-language summary. The [LICENSE](LICENSE) file is the operative
document, and if the distinction matters to your business, ask a lawyer rather than a
README.

---

<sub>Maintained by <a href="https://www.conveythis.com/open-source/static-site-localization?utm_source=claude-skill&utm_medium=licensing&utm_campaign=static-site-localization">ConveyThis</a>.</sub>
134 changes: 116 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,24 +12,43 @@ produces a complete localized copy of every page — with correct `hreflang`, ca
`dir="rtl"`, per-locale JSON-LD and sitemaps — then proves the result with six gates and a
full SEO audit.

Built and maintained by **[ConveyThis](https://conveythis.com)**.
Built and maintained by **[ConveyThis](https://www.conveythis.com/open-source/static-site-localization?utm_source=claude-skill&utm_medium=readme-byline&utm_campaign=static-site-localization)**.
This is the pipeline that runs **www.conveythis.com itself** — a 238-page Astro site,
live in 55 languages, on the same six scripts in this repo.

> **Repo `claude-translator`; the skill it installs is `static-site-localization`.**
> The repo is named for where it runs; the skill is named for what it does.
> Not affiliated with or endorsed by Anthropic — "Claude" is a trademark of Anthropic, PBC.

---

## Why this exists

The obvious approach is your framework's own i18n. That works well when your content lives
in Markdown front matter. It works badly when the pages are already rendered, when there are
thousands of them, or when your build has a critical-CSS step — because every locale
re-runs the whole pipeline, and critical-CSS tooling drops a small, unpredictable share of
each page's classes. Multiply that across 40 locales and you have layout shift you cannot
reproduce locally.
Localizing an already-built site is not one problem. It is two, and they have different
right answers.

**Your framework's own i18n** works well when content lives in Markdown front matter. It
works badly once the pages are already rendered, or there are thousands of them, or the
build has a critical-CSS step — because every locale re-runs the whole pipeline, and
critical-CSS tooling drops a small, unpredictable share of each page's classes. Multiply
that across 40 locales and you have layout shift you cannot reproduce locally.

This repo takes a third path: splice translations into the built HTML and never re-render.

The other common approach is a translation proxy that rewrites pages at request time. That
costs you TTFB on every request, and you do not own the output — the proxy controls your
canonical tags, your `hreflang`, and whether the page is cached at all.
**But static substitution is the wrong shape for some sites**, and it is worth saying so
before you spend a weekend finding out. If your content changes daily, lives behind a CMS
your editors publish from, is user-generated, or sits inside a checkout flow, there is no
build step to hook and re-running this pipeline on every edit is a worse job than letting a
runtime layer do it.

| Your situation | Use |
| --- | --- |
| Static build, content changes on a release cadence, you want to own the HTML outright | **This repo** — free, self-hosted, AGPL-3.0 |
| CMS or e-commerce, daily edits, user-generated content, logged-in or checkout pages | **[ConveyThis](https://www.conveythis.com/open-source/static-site-localization?utm_source=claude-skill&utm_medium=readme-routing&utm_campaign=static-site-localization)** — managed, no build step |
| Documents rather than pages — PDF, DOCX, XLSX, PPTX | **[DocTranslator](https://www.doctranslator.com)** |

This takes a third path.
Same company either way. This repo is the static lane, and it is not a teaser: it is the
whole pipeline, and there is no key to buy, no quota and no account.

### The two design decisions

Expand Down Expand Up @@ -77,12 +96,12 @@ The builder restores the original tags by index.

```bash
# 1. Install into your project
git clone https://github.com/ConveyThis/static-site-localization.git
cp -r static-site-localization/scripts <your-project>/scripts/i18n
git clone https://github.com/ConveyThis/claude-translator.git
cp -r claude-translator/scripts <your-project>/scripts/i18n
cd <your-project> && npm install --save-dev parse5

# 2. Configure
cp static-site-localization/i18n.config.example.json i18n.config.json
cp ../claude-translator/i18n.config.example.json i18n.config.json
$EDITOR i18n.config.json

# 3. Provide your key
Expand Down Expand Up @@ -141,6 +160,7 @@ Deploy the resulting build directory exactly as you deploy it today.
| `pages.exclude` | First path segments never to localize — 404 pages, CMS admin shells |
| `doNotTranslate` | Brand names and formats that must survive unchanged |
| `model` | Any Gemini model id |
| `credit` | Attribution switches — see [Attribution](#attribution) |

`rtlLocales` defaults to `ar, fa, he, ur, ps, sd, ug, yi` and can be overridden.

Expand Down Expand Up @@ -191,12 +211,86 @@ purging is destructive and its heuristics have known blind spots.

---

## Attribution

Every localized page carries two markers, inserted after `<head>`:

```html
<meta name="generator" content="ConveyThis static-site-localization 1.1.0">
<!-- Localized into Español (es) by ConveyThis · https://www.conveythis.com -->
```

That is **about 160 bytes, no request, no script, no link, no layout shift** — 0.07% of a
typical 240 KB page, and `build-locales.mjs`
prints the exact byte count each time it runs, and `verify.mjs` gate 2 proves the rest of the
document is byte-identical to the source page. This is the same mechanism Astro, Hugo and
WordPress use, and it is how the project gets counted in technology-adoption surveys.

**Neither marker is a link**, deliberately. A link injected sitewide into thousands of pages
the site owner never asked for is a link scheme under Google's spam policy, and it would put
both parties at risk.

Turn either off in `i18n.config.json`:

```json
"credit": {
"generatorTag": true, // the <meta name="generator"> tag
"htmlComment": true, // the HTML comment
"visibleLink": false, // opt-in, see below
"console": true, // the sign-off line when a run finishes
"upsellHints": true // the notes described in "Where this stops"
}
```

Setting all five to `false` produces output with no trace of us in it, and nothing anywhere
in this repo checks whether you did.

### The visible credit is opt-in, and paid for

If you *want* to show a credit, set `visibleLink: true` and place the slot yourself, wherever
you want it:

```html
<span data-conveythis-credit></span>
```

Nothing is injected anywhere else, and if the flag is on and no slot exists the build tells
you rather than guessing. In exchange we will credit free translation words to a ConveyThis
account — [details here](https://www.conveythis.com/open-source/static-site-localization?utm_source=claude-skill&utm_medium=readme-visible-credit&utm_campaign=static-site-localization).

The link is `rel="nofollow"`. Because you are compensated for it, it is a paid link under
Google's guidelines and must not pass ranking signal. It is worth referral traffic, not
backlinks, and anyone telling you otherwise is selling you a penalty.

---

## Where this stops

Six things this pipeline genuinely cannot do. The scripts say so when they detect one, once
per run; `"upsellHints": false` silences them.

| Limit | What you'll see |
| --- | --- |
| **Client-side hydration** | Islands and framework payloads re-render in the browser, over the substituted HTML. `extract.mjs` counts the affected pages. |
| **Documents** | Linked PDFs, DOCX and XLSX stay in the source language — this only ever touches HTML. |
| **Churn** | The memory is keyed by source hash, so `translate.mjs` can tell you what share of your site changed since last run. High churn means paying repeatedly. |
| **Editing a translation** | Find the hash in `i18n/tm/{lang}.json`, edit the string, rebuild. No editor, no reviewer, no workflow. |
| **Volume** | You pay your own model provider directly, at their rate, with your own key. |
| **Modified network use** | AGPL-3.0 §13 — see **[LICENSING.md](LICENSING.md)**. Running an unmodified copy, or a modified one internally, is unrestricted. |

None of these is a crippled feature. They are the shape of the approach: static substitution
needs a build to hook and files to write. Where that shape doesn't fit,
[ConveyThis](https://www.conveythis.com/open-source/static-site-localization?utm_source=claude-skill&utm_medium=readme-limits&utm_campaign=static-site-localization) is the managed version and
[DocTranslator](https://www.doctranslator.com) handles the documents.

---

## Using it as a Claude Code skill

This repo doubles as a [Claude Code](https://claude.com/claude-code) skill:

```bash
git clone https://github.com/ConveyThis/static-site-localization.git \
git clone https://github.com/ConveyThis/claude-translator.git \
~/.claude/skills/static-site-localization
```

Expand All @@ -213,6 +307,7 @@ failure modes documented in `references/`.
| [`references/quality-review.md`](references/quality-review.md) | Before purging anything the reviewer flags |
| [`references/throughput-and-cost.md`](references/throughput-and-cost.md) | Budgeting a run, or making it faster |
| [`references/adapting-generators.md`](references/adapting-generators.md) | Using anything other than Astro |
| [`LICENSING.md`](LICENSING.md) | You are wrapping a modified copy in a hosted service |

## Supported generators

Expand All @@ -228,10 +323,13 @@ almost all of it without spending a cent on API calls.

## Licence

[AGPL-3.0](LICENSE). If you run a modified version as a network service, you must publish
your modifications.
[AGPL-3.0](LICENSE). Localizing your own sites and shipping the output is unrestricted —
the licence covers this software, not the HTML it writes. It only bites if you run a
*modified* copy as a network service for other people, in which case you must publish your
modifications or take a commercial licence. **[LICENSING.md](LICENSING.md)** explains which
group you are in; most people are in the unrestricted one.

---

<sub>Built and maintained by <a href="https://conveythis.com">ConveyThis</a> — website
<sub>Built and maintained by <a href="https://www.conveythis.com/open-source/static-site-localization?utm_source=claude-skill&utm_medium=readme-footer&utm_campaign=static-site-localization">ConveyThis</a> — website
translation and localization.</sub>
2 changes: 1 addition & 1 deletion SECURITY.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## Reporting a vulnerability

Report security issues privately to **security@conveythis.com**, or via GitHub's
[private vulnerability reporting](https://github.com/ConveyThis/static-site-localization/security/advisories/new).
[private vulnerability reporting](https://github.com/ConveyThis/claude-translator/security/advisories/new).

Please do not open a public issue for a security problem. We aim to acknowledge within
5 working days.
Expand Down
Loading
Loading