claude-translator 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +135 -0
- package/LICENSE +662 -0
- package/LICENSING.md +69 -0
- package/README.md +434 -0
- package/SKILL.md +206 -0
- package/bin/claude-translator.mjs +230 -0
- package/bin/cli.test.mjs +165 -0
- package/i18n.config.example.json +67 -0
- package/package.json +60 -0
- package/references/adapting-generators.md +76 -0
- package/references/failure-modes.md +255 -0
- package/references/providers.md +157 -0
- package/references/quality-review.md +91 -0
- package/references/throughput-and-cost.md +124 -0
- package/scripts/audit-seo.mjs +261 -0
- package/scripts/build-locales.mjs +336 -0
- package/scripts/config.mjs +188 -0
- package/scripts/credit.mjs +143 -0
- package/scripts/extract.mjs +564 -0
- package/scripts/finalize.sh +58 -0
- package/scripts/providers/anthropic.mjs +118 -0
- package/scripts/providers/gemini.mjs +72 -0
- package/scripts/providers/index.mjs +95 -0
- package/scripts/providers/openai.mjs +120 -0
- package/scripts/providers/providers.test.mjs +214 -0
- package/scripts/review.mjs +310 -0
- package/scripts/translate.mjs +455 -0
- package/scripts/verify.mjs +384 -0
package/LICENSING.md
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# Licensing
|
|
2
|
+
|
|
3
|
+
This project is **[AGPL-3.0](LICENSE)**, and that is a deliberate choice rather than a
|
|
4
|
+
default. This page explains what it means for you in practice, because the answer differs a
|
|
5
|
+
lot depending on what you are doing.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## You almost certainly do not need to read further
|
|
10
|
+
|
|
11
|
+
**Localizing your own site and deploying the output is unrestricted.** The pages this
|
|
12
|
+
produces are your content. The AGPL covers *this software*, not the HTML it writes. Use it
|
|
13
|
+
commercially, on client work, on as many sites as you like, without telling anyone and
|
|
14
|
+
without paying anyone.
|
|
15
|
+
|
|
16
|
+
That covers nearly everyone.
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## When the AGPL actually bites
|
|
21
|
+
|
|
22
|
+
The AGPL's distinguishing clause is **section 13**: if you *modify* this software and let
|
|
23
|
+
other people interact with your modified version **over a network**, you must offer those
|
|
24
|
+
users the source of your modifications.
|
|
25
|
+
|
|
26
|
+
So it applies if you:
|
|
27
|
+
|
|
28
|
+
- wrap a modified copy in a hosted service, dashboard or API that other people use
|
|
29
|
+
- build a SaaS product whose translation feature is this code, changed
|
|
30
|
+
- offer localization as a hosted product to clients who operate the tooling themselves
|
|
31
|
+
|
|
32
|
+
It does **not** apply if you:
|
|
33
|
+
|
|
34
|
+
- run it unmodified, however you like
|
|
35
|
+
- modify it for internal use and never expose it to outside users over a network
|
|
36
|
+
- run an agency and hand clients the resulting static files
|
|
37
|
+
|
|
38
|
+
If you are in the first group and cannot publish your modifications — because they encode
|
|
39
|
+
something you consider proprietary — you have two options: keep your changes internal and
|
|
40
|
+
publish nothing, or take a commercial licence.
|
|
41
|
+
|
|
42
|
+
---
|
|
43
|
+
|
|
44
|
+
## Commercial licence
|
|
45
|
+
|
|
46
|
+
A commercial licence removes the section 13 obligation. You get the same code under terms
|
|
47
|
+
that let you keep your modifications closed.
|
|
48
|
+
|
|
49
|
+
**info@conveythis.com** — put "commercial licence" in the subject, tell us what you are
|
|
50
|
+
building, and we will quote it.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
## Contributing
|
|
55
|
+
|
|
56
|
+
Contributions are under AGPL-3.0, the same as the project. See
|
|
57
|
+
[CONTRIBUTING.md](CONTRIBUTING.md).
|
|
58
|
+
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
## Not legal advice
|
|
62
|
+
|
|
63
|
+
This page is a plain-language summary. The [LICENSE](LICENSE) file is the operative
|
|
64
|
+
document, and if the distinction matters to your business, ask a lawyer rather than a
|
|
65
|
+
README.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
<sub>Maintained by <a href="https://www.conveythis.com/open-source/claude-translator?utm_source=claude-skill&utm_medium=licensing&utm_campaign=claude-translator">ConveyThis</a>.</sub>
|
package/README.md
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
# Claude Translator
|
|
2
|
+
|
|
3
|
+
**Static-site localization: translate a built website into dozens of languages as real
|
|
4
|
+
static pages — without re-rendering it, and without breaking Core Web Vitals.**
|
|
5
|
+
|
|
6
|
+
[](https://www.gnu.org/licenses/agpl-3.0)
|
|
7
|
+
[](https://nodejs.org)
|
|
8
|
+
[](#using-it-as-a-claude-code-skill)
|
|
9
|
+
|
|
10
|
+
Point it at a built site, give it a list of locales and your own model API key, and it
|
|
11
|
+
produces a complete localized copy of every page — with correct `hreflang`, canonicals,
|
|
12
|
+
`dir="rtl"`, per-locale JSON-LD and sitemaps — then proves the result with six gates and a
|
|
13
|
+
full SEO audit.
|
|
14
|
+
|
|
15
|
+
Built and maintained by **[ConveyThis](https://www.conveythis.com/open-source/claude-translator?utm_source=claude-skill&utm_medium=readme-byline&utm_campaign=claude-translator)**.
|
|
16
|
+
This is the pipeline that runs **www.conveythis.com itself** — a 238-page Astro site,
|
|
17
|
+
live in 55 languages, on the same six scripts in this repo.
|
|
18
|
+
|
|
19
|
+
> Not affiliated with or endorsed by Anthropic. "Claude" is a trademark of Anthropic, PBC.
|
|
20
|
+
> This project is named for the model family it ships configured to use; it works just as
|
|
21
|
+
> well with Gemini, with any OpenAI-compatible endpoint, and with a model on your own machine.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Why this exists
|
|
26
|
+
|
|
27
|
+
Localizing an already-built site is not one problem. It is two, and they have different
|
|
28
|
+
right answers.
|
|
29
|
+
|
|
30
|
+
**Your framework's own i18n** works well when content lives in Markdown front matter. It
|
|
31
|
+
works badly once the pages are already rendered, or there are thousands of them, or the
|
|
32
|
+
build has a critical-CSS step — because every locale re-runs the whole pipeline, and
|
|
33
|
+
critical-CSS tooling drops a small, unpredictable share of each page's classes. Multiply
|
|
34
|
+
that across 40 locales and you have layout shift you cannot reproduce locally.
|
|
35
|
+
|
|
36
|
+
This repo takes a third path: splice translations into the built HTML and never re-render.
|
|
37
|
+
|
|
38
|
+
**But static substitution is the wrong shape for some sites**, and it is worth saying so
|
|
39
|
+
before you spend a weekend finding out. If your content changes daily, lives behind a CMS
|
|
40
|
+
your editors publish from, is user-generated, or sits inside a checkout flow, there is no
|
|
41
|
+
build step to hook and re-running this pipeline on every edit is a worse job than letting a
|
|
42
|
+
runtime layer do it.
|
|
43
|
+
|
|
44
|
+
| Your situation | Use |
|
|
45
|
+
| --- | --- |
|
|
46
|
+
| Static build, content changes on a release cadence, you want to own the HTML outright | **This repo** — free, self-hosted, AGPL-3.0 |
|
|
47
|
+
| CMS or e-commerce, daily edits, user-generated content, logged-in or checkout pages | **[ConveyThis](https://www.conveythis.com/open-source/claude-translator?utm_source=claude-skill&utm_medium=readme-routing&utm_campaign=claude-translator)** — managed, no build step |
|
|
48
|
+
| Documents rather than pages — PDF, DOCX, XLSX, PPTX | **[DocTranslator](https://www.doctranslator.com)** |
|
|
49
|
+
|
|
50
|
+
Same company either way. This repo is the static lane, and it is not a teaser: it is the
|
|
51
|
+
whole pipeline, and there is no key to buy, no quota and no account.
|
|
52
|
+
|
|
53
|
+
### The two design decisions
|
|
54
|
+
|
|
55
|
+
**1. Substitute into built HTML by byte offset. Never re-render.**
|
|
56
|
+
|
|
57
|
+
Each locale page is the source page with byte ranges spliced right-to-left. The document is
|
|
58
|
+
never re-serialised from a DOM, so inlined critical CSS, the LCP element, asset hashes and
|
|
59
|
+
the `width`/`height` attributes that hold CLS all carry over untouched. That is *why* locale
|
|
60
|
+
pages match the source language on Core Web Vitals rather than merely resembling it.
|
|
61
|
+
|
|
62
|
+
**2. Translate blocks, not text nodes.**
|
|
63
|
+
|
|
64
|
+
Around a fifth of a typical site's text nodes are split by inline markup:
|
|
65
|
+
|
|
66
|
+
```html
|
|
67
|
+
<p>With <strong>Acme</strong>, you'll get a streamlined flow.</p>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Translating `"With"` and `", you'll get a streamlined flow."` separately produces broken
|
|
71
|
+
grammar in any language that reorders or inflects. So the unit of translation is the whole
|
|
72
|
+
block, with inline tags replaced by numbered placeholders the model carries through:
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
With <0>Acme</0>, you'll get a streamlined flow.
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The builder restores the original tags by index.
|
|
79
|
+
|
|
80
|
+
### Does it hold?
|
|
81
|
+
|
|
82
|
+
[`doctranslator.com/fr`](https://doctranslator.com/fr) is a large Astro site whose French pages
|
|
83
|
+
were built by this pipeline. Against the English original, the markup is **byte-identical** —
|
|
84
|
+
**2,743 tags in identical sequence**, **all 2,031 `class` attributes matching**, and page weight
|
|
85
|
+
up **0.74%**, which is only French being longer than English. Nothing structural moved, so there
|
|
86
|
+
is nothing for the browser to lay out differently.
|
|
87
|
+
|
|
88
|
+
Ten seconds to check:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
curl -s https://doctranslator.com/ | grep -o 'class="[^"]*"' > en.txt
|
|
92
|
+
curl -s https://doctranslator.com/fr | grep -o 'class="[^"]*"' > fr.txt
|
|
93
|
+
diff en.txt fr.txt && echo "markup identical — only the text changed"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
PageSpeed Insights performance, measured 25 August 2026:
|
|
97
|
+
|
|
98
|
+
| | English source | French, from this tool |
|
|
99
|
+
| --- | --- | --- |
|
|
100
|
+
| Desktop | 100 | **100** |
|
|
101
|
+
| Mobile | 98 | **98** |
|
|
102
|
+
|
|
103
|
+
Accessibility, best practices and SEO were 100 on every run of both pages, in both strategies.
|
|
104
|
+
|
|
105
|
+
**These are medians, deliberately.** Lighthouse scores move: five consecutive runs of the same
|
|
106
|
+
English mobile page returned 98, 98, 88, 98, 98, with LCP swinging between 1.8s and 3.2s. That
|
|
107
|
+
is network and CDN variance, not page quality. Measure both languages yourself and compare them
|
|
108
|
+
against each other rather than against a number in a README.
|
|
109
|
+
|
|
110
|
+
---
|
|
111
|
+
|
|
112
|
+
## Requirements
|
|
113
|
+
|
|
114
|
+
- **Node.js ≥ 20**
|
|
115
|
+
- A site that builds to static HTML
|
|
116
|
+
- **An API key for whichever model you want to use** — Claude by default
|
|
117
|
+
([console.anthropic.com](https://console.anthropic.com/)), or Gemini
|
|
118
|
+
([aistudio.google.com/apikey](https://aistudio.google.com/apikey)), or any
|
|
119
|
+
OpenAI-compatible endpoint. **Or no key at all**, if you point it at a model running
|
|
120
|
+
on your own machine — see [Models and providers](#models-and-providers).
|
|
121
|
+
|
|
122
|
+
> This project ships **no API key and makes no calls on your behalf**. Your key is read
|
|
123
|
+
> from your environment, used to call your chosen provider directly from your machine, and
|
|
124
|
+
> never transmitted anywhere else. There is no telemetry.
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## Quickstart
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
# 1. Install into your project
|
|
132
|
+
cd <your-project>
|
|
133
|
+
npx claude-translator init
|
|
134
|
+
npm install # parse5, the only dependency
|
|
135
|
+
|
|
136
|
+
# 2. Configure — baseUrl, locales, provider
|
|
137
|
+
$EDITOR i18n.config.json
|
|
138
|
+
|
|
139
|
+
# 3. Provide your key (skip entirely for a local model)
|
|
140
|
+
echo "ANTHROPIC_API_KEY=your-key-here" >> .env # .gitignore this
|
|
141
|
+
|
|
142
|
+
# 4. Run
|
|
143
|
+
npm run build # your normal build
|
|
144
|
+
node scripts/i18n/extract.mjs # find translatable units
|
|
145
|
+
node scripts/i18n/translate.mjs --lang es,fr,de # translate (uses your key)
|
|
146
|
+
node scripts/i18n/build-locales.mjs --lang all # write localized pages
|
|
147
|
+
node scripts/i18n/verify.mjs --lang all # six gates
|
|
148
|
+
node scripts/i18n/audit-seo.mjs # full SEO audit
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Deploy the resulting build directory exactly as you deploy it today.
|
|
152
|
+
|
|
153
|
+
`init` copies the pipeline into `scripts/i18n/`, writes a config, declares `parse5`, and adds
|
|
154
|
+
the derived `i18n/` paths to `.gitignore`. It **never overwrites anything without `--force`**
|
|
155
|
+
and prints every file it touched. `--dir <path>` puts the scripts somewhere else.
|
|
156
|
+
|
|
157
|
+
<details>
|
|
158
|
+
<summary>Installing without npx</summary>
|
|
159
|
+
|
|
160
|
+
```bash
|
|
161
|
+
git clone https://github.com/ConveyThis/claude-translator.git
|
|
162
|
+
cp -r claude-translator/scripts <your-project>/scripts/i18n
|
|
163
|
+
cp claude-translator/i18n.config.example.json <your-project>/i18n.config.json
|
|
164
|
+
cd <your-project> && npm install --save-dev parse5
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Or run the scaffolder straight from the clone:
|
|
168
|
+
`node claude-translator/bin/claude-translator.mjs init`
|
|
169
|
+
|
|
170
|
+
</details>
|
|
171
|
+
|
|
172
|
+
The scripts are copied into your project rather than run from `node_modules` on purpose: they
|
|
173
|
+
resolve `parse5` and every relative path from the project they live in, they are short enough to
|
|
174
|
+
read, and this is AGPL software whose point is that you can change them.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
## Configuration
|
|
179
|
+
|
|
180
|
+
`i18n.config.json` is the only file that knows anything about your site.
|
|
181
|
+
|
|
182
|
+
```json
|
|
183
|
+
{
|
|
184
|
+
"buildDir": "dist",
|
|
185
|
+
"baseUrl": "https://example.com",
|
|
186
|
+
"sourceLanguage": "English",
|
|
187
|
+
"siteName": "Acme",
|
|
188
|
+
"siteDescription": "an online project-management tool",
|
|
189
|
+
|
|
190
|
+
"locales": [
|
|
191
|
+
{ "hreflang": "es", "pathCode": "es", "nativeLabel": "Español" },
|
|
192
|
+
{ "hreflang": "pt-BR", "pathCode": "pt-br", "nativeLabel": "Português (Brasil)" },
|
|
193
|
+
{ "hreflang": "ar", "pathCode": "ar", "nativeLabel": "العربية" }
|
|
194
|
+
],
|
|
195
|
+
|
|
196
|
+
"pages": { "source": "build", "exclude": ["404", "admin"] },
|
|
197
|
+
|
|
198
|
+
"doNotTranslate": {
|
|
199
|
+
"brands": ["Acme", "Acme Cloud Inc"],
|
|
200
|
+
"formats": ["PDF", "DOCX", "XLSX"]
|
|
201
|
+
},
|
|
202
|
+
|
|
203
|
+
"provider": "anthropic",
|
|
204
|
+
"model": "claude-haiku-4-5"
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
| Key | Meaning |
|
|
209
|
+
| --- | --- |
|
|
210
|
+
| `buildDir` | Where your generator writes HTML (`dist`, `out`, `public`, `_site`…) |
|
|
211
|
+
| `baseUrl` | Canonical origin, no trailing slash |
|
|
212
|
+
| `sourceLanguage` | The language your built site is written in |
|
|
213
|
+
| `siteName` / `siteDescription` | Given to the translator so it picks the right register |
|
|
214
|
+
| `locales[]` | `hreflang` (ISO 639-1, region UPPERCASE), `pathCode` (URL segment), `nativeLabel` |
|
|
215
|
+
| `pages.source` | `"build"` to derive from output, or a path to a slug list |
|
|
216
|
+
| `pages.exclude` | First path segments never to localize — 404 pages, CMS admin shells |
|
|
217
|
+
| `doNotTranslate` | Brand names and formats that must survive unchanged |
|
|
218
|
+
| `provider` | `anthropic` (default), `gemini`, `openai`, or a path to your own adapter |
|
|
219
|
+
| `model` | Any model id for that provider — defaults to the provider's own |
|
|
220
|
+
| `apiBaseUrl` | Model API host. Set this for local models, Azure or a gateway. **Not** `baseUrl`, which is your site |
|
|
221
|
+
| `apiKeyEnv` | Read the key from a different environment variable |
|
|
222
|
+
| `pricing` | `{"in": …, "out": …}` USD per million tokens, for the cost estimate |
|
|
223
|
+
| `credit` | Attribution switches — see [Attribution](#attribution) |
|
|
224
|
+
|
|
225
|
+
`rtlLocales` defaults to `ar, fa, he, ur, ps, sd, ug, yi` and can be overridden.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## What you get
|
|
230
|
+
|
|
231
|
+
For every page, in every locale:
|
|
232
|
+
|
|
233
|
+
- `<html lang>` and `dir="rtl"` where the script requires it
|
|
234
|
+
- A self-referencing canonical — `https`, no trailing slash
|
|
235
|
+
- A complete `hreflang` set: every locale, plus `x-default` and the source language
|
|
236
|
+
pointing at the **original** page, not at self
|
|
237
|
+
- `og:url` / `og:locale`
|
|
238
|
+
- JSON-LD with per-locale `@id`, `url` and `inLanguage` — and `Organization` left alone,
|
|
239
|
+
because a company is one entity in every language
|
|
240
|
+
- Locale-prefixed internal links
|
|
241
|
+
- Per-locale sitemaps
|
|
242
|
+
|
|
243
|
+
## Trusting the output
|
|
244
|
+
|
|
245
|
+
Machine translation at scale fails in ways that look like success. Two commands exist to
|
|
246
|
+
catch that.
|
|
247
|
+
|
|
248
|
+
**`verify.mjs` — six gates**
|
|
249
|
+
|
|
250
|
+
| # | Gate | Catches |
|
|
251
|
+
| --- | --- | --- |
|
|
252
|
+
| 1 | URL parity | a missing page — a dead URL in a language you now advertise |
|
|
253
|
+
| 2 | Structure | tag sequence differs from the source page → substitution damaged markup |
|
|
254
|
+
| 3 | Placeholder leak | a raw `<0>` survived into shipped HTML |
|
|
255
|
+
| 4 | Locale identity | wrong `lang`, canonical, `hreflang` or JSON-LD |
|
|
256
|
+
| 5 | Coverage | share of extracted segments present in the memory |
|
|
257
|
+
| 6 | **Never offered** | visible text the extractor never picked up |
|
|
258
|
+
|
|
259
|
+
Gate 6 exists because **coverage is not completeness**. Coverage measures
|
|
260
|
+
translated-of-*extracted*, so it is structurally blind to extraction bugs. A single bug has
|
|
261
|
+
been observed reporting 100% coverage while every icon+label pair on a site remained
|
|
262
|
+
untranslated. Gate 6 compares built output against the source instead.
|
|
263
|
+
|
|
264
|
+
**`audit-seo.mjs`** then checks canonicals, the full hreflang mesh, `og` tags, JSON-LD and
|
|
265
|
+
sitemaps across *every* page — not a sample.
|
|
266
|
+
|
|
267
|
+
**`review.mjs`** flags likely translation defects: dropped placeholders, wholesale
|
|
268
|
+
source-language returns, wrong target language, truncated output. Read
|
|
269
|
+
[`references/quality-review.md`](references/quality-review.md) before acting on its output —
|
|
270
|
+
purging is destructive and its heuristics have known blind spots.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Models and providers
|
|
275
|
+
|
|
276
|
+
The translation step is the only part that talks to a model, and it talks through a small
|
|
277
|
+
adapter. Three ship with the project, and anything else is one file.
|
|
278
|
+
|
|
279
|
+
| `provider` | Default model | Key |
|
|
280
|
+
| --- | --- | --- |
|
|
281
|
+
| `anthropic` *(default)* | `claude-haiku-4-5` | `ANTHROPIC_API_KEY` |
|
|
282
|
+
| `gemini` | `gemini-2.5-flash-lite` | `GEMINI_API_KEY` |
|
|
283
|
+
| `openai` | `gpt-4o-mini` | `OPENAI_API_KEY` |
|
|
284
|
+
| `./my-provider.mjs` | — | yours |
|
|
285
|
+
|
|
286
|
+
Omit `provider` and it is inferred from the model id, so configs written before 1.2 keep
|
|
287
|
+
working unchanged.
|
|
288
|
+
|
|
289
|
+
**The `openai` adapter is the interesting one**, because `/v1/chat/completions` is what
|
|
290
|
+
everything speaks. That one adapter covers OpenAI, Azure, Groq, DeepSeek, Mistral,
|
|
291
|
+
OpenRouter, Together and Fireworks — and Ollama, LM Studio and vLLM, which means the whole
|
|
292
|
+
pipeline runs on your own hardware for nothing:
|
|
293
|
+
|
|
294
|
+
```json
|
|
295
|
+
{
|
|
296
|
+
"provider": "openai",
|
|
297
|
+
"apiBaseUrl": "http://localhost:11434/v1",
|
|
298
|
+
"model": "qwen2.5:14b"
|
|
299
|
+
}
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
No key, no quota, no request leaving the machine.
|
|
303
|
+
|
|
304
|
+
**Claude is the default, not a requirement.** It is roughly ten times the cost of the
|
|
305
|
+
Gemini option, which is a real difference on a large site and is spelled out in
|
|
306
|
+
[`references/throughput-and-cost.md`](references/throughput-and-cost.md). Changing it is
|
|
307
|
+
one line. Writing your own adapter is about thirty — see
|
|
308
|
+
[`references/providers.md`](references/providers.md).
|
|
309
|
+
|
|
310
|
+
---
|
|
311
|
+
|
|
312
|
+
## Attribution
|
|
313
|
+
|
|
314
|
+
Every localized page carries two markers, inserted after `<head>`:
|
|
315
|
+
|
|
316
|
+
```html
|
|
317
|
+
<meta name="generator" content="ConveyThis Claude Translator 1.2.0">
|
|
318
|
+
<!-- Localized into Español (es) by ConveyThis · https://www.conveythis.com -->
|
|
319
|
+
```
|
|
320
|
+
|
|
321
|
+
That is **about 150 bytes, no request, no script, no link, no layout shift** — under 0.1% of
|
|
322
|
+
a typical 240 KB page, and `build-locales.mjs`
|
|
323
|
+
prints the exact byte count each time it runs, and `verify.mjs` gate 2 proves the rest of the
|
|
324
|
+
document is byte-identical to the source page. This is the same mechanism Astro, Hugo and
|
|
325
|
+
WordPress use, and it is how the project gets counted in technology-adoption surveys.
|
|
326
|
+
|
|
327
|
+
**Neither marker is a link**, deliberately. A link injected sitewide into thousands of pages
|
|
328
|
+
the site owner never asked for is a link scheme under Google's spam policy, and it would put
|
|
329
|
+
both parties at risk.
|
|
330
|
+
|
|
331
|
+
Turn either off in `i18n.config.json`:
|
|
332
|
+
|
|
333
|
+
```json
|
|
334
|
+
"credit": {
|
|
335
|
+
"generatorTag": true, // the <meta name="generator"> tag
|
|
336
|
+
"htmlComment": true, // the HTML comment
|
|
337
|
+
"visibleLink": false, // opt-in, see below
|
|
338
|
+
"console": true, // the sign-off line when a run finishes
|
|
339
|
+
"upsellHints": true // the notes described in "Where this stops"
|
|
340
|
+
}
|
|
341
|
+
```
|
|
342
|
+
|
|
343
|
+
Setting all five to `false` produces output with no trace of us in it, and nothing anywhere
|
|
344
|
+
in this repo checks whether you did.
|
|
345
|
+
|
|
346
|
+
### The visible credit is opt-in, and paid for
|
|
347
|
+
|
|
348
|
+
If you *want* to show a credit, set `visibleLink: true` and place the slot yourself, wherever
|
|
349
|
+
you want it:
|
|
350
|
+
|
|
351
|
+
```html
|
|
352
|
+
<span data-conveythis-credit></span>
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
Nothing is injected anywhere else, and if the flag is on and no slot exists the build tells
|
|
356
|
+
you rather than guessing. In exchange we will credit free translation words to a ConveyThis
|
|
357
|
+
account — [details here](https://www.conveythis.com/open-source/claude-translator?utm_source=claude-skill&utm_medium=readme-visible-credit&utm_campaign=claude-translator).
|
|
358
|
+
|
|
359
|
+
The link is `rel="nofollow"`. Because you are compensated for it, it is a paid link under
|
|
360
|
+
Google's guidelines and must not pass ranking signal. It is worth referral traffic, not
|
|
361
|
+
backlinks, and anyone telling you otherwise is selling you a penalty.
|
|
362
|
+
|
|
363
|
+
---
|
|
364
|
+
|
|
365
|
+
## Where this stops
|
|
366
|
+
|
|
367
|
+
Six things this pipeline genuinely cannot do. The scripts say so when they detect one, once
|
|
368
|
+
per run; `"upsellHints": false` silences them.
|
|
369
|
+
|
|
370
|
+
| Limit | What you'll see |
|
|
371
|
+
| --- | --- |
|
|
372
|
+
| **Client-side hydration** | Islands and framework payloads re-render in the browser, over the substituted HTML. `extract.mjs` counts the affected pages. |
|
|
373
|
+
| **Documents** | Linked PDFs, DOCX and XLSX stay in the source language — this only ever touches HTML. |
|
|
374
|
+
| **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. |
|
|
375
|
+
| **Editing a translation** | Find the hash in `i18n/tm/{lang}.json`, edit the string, rebuild. No editor, no reviewer, no workflow. |
|
|
376
|
+
| **Volume** | You pay your own model provider directly, at their rate, with your own key. |
|
|
377
|
+
| **Modified network use** | AGPL-3.0 §13 — see **[LICENSING.md](LICENSING.md)**. Running an unmodified copy, or a modified one internally, is unrestricted. |
|
|
378
|
+
|
|
379
|
+
None of these is a crippled feature. They are the shape of the approach: static substitution
|
|
380
|
+
needs a build to hook and files to write. Where that shape doesn't fit,
|
|
381
|
+
[ConveyThis](https://www.conveythis.com/open-source/claude-translator?utm_source=claude-skill&utm_medium=readme-limits&utm_campaign=claude-translator) is the managed version and
|
|
382
|
+
[DocTranslator](https://www.doctranslator.com) handles the documents.
|
|
383
|
+
|
|
384
|
+
---
|
|
385
|
+
|
|
386
|
+
## Using it as a Claude Code skill
|
|
387
|
+
|
|
388
|
+
This repo doubles as a [Claude Code](https://claude.com/claude-code) skill:
|
|
389
|
+
|
|
390
|
+
```bash
|
|
391
|
+
git clone https://github.com/ConveyThis/claude-translator.git \
|
|
392
|
+
~/.claude/skills/claude-translator
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
Then ask Claude to "localize this site". It follows `SKILL.md`, including the failure modes in
|
|
396
|
+
`references/` and the routing rules for when this is the wrong tool entirely.
|
|
397
|
+
|
|
398
|
+
---
|
|
399
|
+
|
|
400
|
+
## Documentation
|
|
401
|
+
|
|
402
|
+
| Document | Read it when |
|
|
403
|
+
| --- | --- |
|
|
404
|
+
| [`references/failure-modes.md`](references/failure-modes.md) | **Before modifying any script.** Every known bug: symptom → cause → fix |
|
|
405
|
+
| [`references/quality-review.md`](references/quality-review.md) | Before purging anything the reviewer flags |
|
|
406
|
+
| [`references/throughput-and-cost.md`](references/throughput-and-cost.md) | Budgeting a run, or making it faster |
|
|
407
|
+
| [`references/adapting-generators.md`](references/adapting-generators.md) | Using anything other than Astro |
|
|
408
|
+
| [`references/providers.md`](references/providers.md) | Changing model, running locally, or writing an adapter |
|
|
409
|
+
| [`LICENSING.md`](LICENSING.md) | You are wrapping a modified copy in a hosted service |
|
|
410
|
+
|
|
411
|
+
## Supported generators
|
|
412
|
+
|
|
413
|
+
Anything that emits static HTML: **Astro**, **Next.js** (`output: 'export'`), **Hugo**,
|
|
414
|
+
**Eleventy**, **Jekyll**, **Gatsby**, or hand-written HTML. See
|
|
415
|
+
[`references/adapting-generators.md`](references/adapting-generators.md) for per-generator
|
|
416
|
+
notes — particularly around hydration payloads, which can re-render over your translations.
|
|
417
|
+
|
|
418
|
+
## Contributing
|
|
419
|
+
|
|
420
|
+
Issues and pull requests welcome — see [CONTRIBUTING.md](CONTRIBUTING.md). You can work on
|
|
421
|
+
almost all of it without spending a cent on API calls.
|
|
422
|
+
|
|
423
|
+
## Licence
|
|
424
|
+
|
|
425
|
+
[AGPL-3.0](LICENSE). Localizing your own sites and shipping the output is unrestricted —
|
|
426
|
+
the licence covers this software, not the HTML it writes. It only bites if you run a
|
|
427
|
+
*modified* copy as a network service for other people, in which case you must publish your
|
|
428
|
+
modifications or take a commercial licence. **[LICENSING.md](LICENSING.md)** explains which
|
|
429
|
+
group you are in; most people are in the unrestricted one.
|
|
430
|
+
|
|
431
|
+
---
|
|
432
|
+
|
|
433
|
+
<sub>Built and maintained by <a href="https://www.conveythis.com/open-source/claude-translator?utm_source=claude-skill&utm_medium=readme-footer&utm_campaign=claude-translator">ConveyThis</a> — website
|
|
434
|
+
translation and localization.</sub>
|