datocms-plugin-ai-translations 2.3.0 → 2.4.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/README.md CHANGED
@@ -14,21 +14,24 @@ See the [CHANGELOG.md](./CHANGELOG.md) file for details about all the latest fea
14
14
 
15
15
  On the plugin's Settings screen:
16
16
 
17
- 1. **AI Vendor**: Choose your provider — OpenAI (ChatGPT), Google (Gemini), or Anthropic (Claude).
17
+ 1. **AI Vendor**: Choose your provider — OpenAI (ChatGPT), Google (Gemini), Anthropic (Claude), or DeepL.
18
18
  2. If you chose OpenAI:
19
19
  - **OpenAI API Key**: Paste a valid OpenAI key.
20
- - **GPT Model**: After entering your key, the plugin lists relevant chat models and highlights a recommended default.
21
- - Default: gpt‑4.1‑mini (fastest and broadly available)
22
- - High‑stakes short copy: gpt‑4.1
23
- - Large or budget batches: gpt‑4o‑mini
20
+ - **GPT Model**: After entering your key, the plugin lists available chat models. Select a model from the dropdown.
24
21
  3. If you chose Google (Gemini):
25
22
  - **Google API Key**: Paste a valid key from a GCP project with the Generative Language API enabled.
26
- - **Gemini Model**: Recommended `gemini-2.5-flash` (fast/cost‑effective default). For the highest fidelity, use `gemini-2.5-pro`. For very large or budget batches, consider `gemini-2.5-flash-lite`.
27
- 4. **Translatable Field Types**: Pick which field editor types (single_line, markdown, structured_text, etc.) can be translated.
28
- 5. **Translate Whole Record**: Enable the sidebar that translates every localized field in a record.
29
- 6. **Translate Bulk Records**: Enable bulk translations from table view or via the dedicated page.
30
- 7. **AI Bulk Translations Page**: Translate whole models at once.
31
- 8. **Prompt Template**: Customize how translations are requested. Use `{fieldValue}`, `{fromLocale}`, `{toLocale}`, and `{recordContext}`.
23
+ - **Gemini Model**: Select a model from the dropdown.
24
+ 4. If you chose Anthropic (Claude):
25
+ - **Anthropic API Key**: Paste a valid Anthropic key.
26
+ - **Claude Model**: Select a model from the dropdown.
27
+ 5. If you chose DeepL:
28
+ - **DeepL API Key**: Paste your DeepL API key.
29
+ - **Use DeepL Free endpoint**: Enable this if your key ends with `:fx` (Free plan).
30
+ 6. **Translatable Field Types**: Pick which field editor types (single_line, markdown, structured_text, etc.) can be translated.
31
+ 7. **Translate Whole Record**: Enable the sidebar that translates every localized field in a record.
32
+ 8. **Translate Bulk Records**: Enable bulk translations from table view or via the dedicated page.
33
+ 9. **AI Bulk Translations Page**: Translate whole models at once.
34
+ 10. **Prompt Template** (AI vendors only): Customize how translations are requested. Use `{fieldValue}`, `{fromLocale}`, `{toLocale}`, and `{recordContext}`.
32
35
 
33
36
  ### Key Restrictions and Security
34
37
  - Keys are stored in plugin settings and used client‑side. Do not share your workspace publicly.
@@ -38,8 +41,8 @@ On the plugin's Settings screen:
38
41
  - The plugin redacts API keys from debug logs automatically.
39
42
 
40
43
  _**Models**_
41
- - OpenAI: the list is dynamic for your account; the plugin filters out embeddings, audio/whisper/tts, moderation, image, and realtime models, prioritizing general-purpose chat models used for translation.
42
- - Google: provides a fixed list in settings (`gemini-1.5-flash` and `gemini-1.5-pro`).
44
+ - OpenAI: the model list is fetched dynamically for your account; the plugin filters out embeddings, audio/whisper/tts, moderation, image, and realtime models.
45
+ - Google: the model list is fetched dynamically from the Generative Language API.
43
46
 
44
47
  Save your changes. The plugin is now ready.
45
48
 
@@ -135,167 +138,6 @@ You can customize the translation prompt template in the plugin settings:
135
138
  - **Model Not Found**: Verify the exact model id exists for your account/region and is spelled correctly.
136
139
  - **Localization**: Make sure your project has at least two locales, otherwise translation actions won't appear.
137
140
 
138
- ## DeepL Requires a Proxy (Why and How)
139
-
140
- DeepL’s API does not support browser‑origin requests (no CORS). If you call DeepL directly from the plugin (which runs in the browser), the preflight request fails and you’ll see network/CORS errors. To use DeepL in this plugin, you must route requests through a small server you control (a “proxy”).
141
-
142
- What the proxy must do
143
- - Accept a POST with JSON body that matches DeepL’s `/v2/translate` input. The plugin sends bodies like:
144
- - `{ "text": ["Hello"], "target_lang": "DE", ... }`
145
- - Add CORS headers to the response (at minimum `Access-Control-Allow-Origin: *` for testing; you can restrict later).
146
- - Forward the request to DeepL’s API with the Authorization header added server‑side:
147
- - `Authorization: DeepL-Auth-Key <YOUR_KEY>`
148
- - Choose the proper upstream host:
149
- - Free keys (end with `:fx`) → `https://api-free.deepl.com`
150
- - Pro keys → `https://api.deepl.com`
151
-
152
- Plugin settings to use with a proxy
153
- - In Settings → DeepL, set “Proxy URL” to the base of your function (examples below) — the plugin will call `POST <proxy>/v2/translate`.
154
- - If your key ends with `:fx`, also enable “Use DeepL Free endpoint (api-free.deepl.com)” so validation and error messages match your plan.
155
- - Use the “Test proxy” button: we send a tiny "Hello world" test, and show inline success/error feedback.
156
-
157
- Security notes
158
- - Never expose the DeepL key in the browser. Keep it in your serverless function/env.
159
- - For production, restrict CORS to `https://admin.datocms.com` and your own preview domains instead of `*`.
160
- - Do not log request bodies or headers; avoid leaving keys in logs.
161
-
162
- ### Option A: Cloudflare Workers
163
-
164
- Environment vars
165
- - `DEEPL_AUTH_KEY` — your DeepL key
166
- - `DEEPL_BASE_URL` — `https://api-free.deepl.com` (Free) or `https://api.deepl.com` (Pro)
167
-
168
- Worker (wrangler.toml configured; minimal example)
169
- ```
170
- export default {
171
- async fetch(req, env) {
172
- const cors = {
173
- 'Access-Control-Allow-Origin': '*',
174
- 'Access-Control-Allow-Headers': '*',
175
- };
176
- if (req.method === 'OPTIONS') return new Response(null, { headers: cors });
177
-
178
- const url = new URL(req.url);
179
- const isFree = url.searchParams.get('endpoint') === 'free';
180
- const baseUrl = isFree ? 'https://api-free.deepl.com' : 'https://api.deepl.com';
181
- const upstream = new URL('/v2/translate', baseUrl);
182
-
183
- const body = await req.text(); // passthrough JSON body
184
-
185
- const resp = await fetch(upstream, {
186
- method: 'POST',
187
- headers: {
188
- 'Content-Type': 'application/json',
189
- 'Authorization': `DeepL-Auth-Key ${env.DEEPL_AUTH_KEY}`,
190
- },
191
- body,
192
- });
193
-
194
- const text = await resp.text();
195
- return new Response(text, { status: resp.status, headers: { ...cors, 'Content-Type': 'application/json' } });
196
- }
197
- }
198
- ```
199
-
200
- Deploy
201
- - `wrangler deploy`
202
- - Set `DEEPL_AUTH_KEY` and `DEEPL_BASE_URL` in your Worker’s environment.
203
- - Copy the Worker URL (e.g., `https://your-worker.yourname.workers.dev`) into the plugin’s “Proxy URL”.
204
-
205
- ### Option B: Vercel Serverless Function (Next.js API Route)
206
-
207
- Environment vars (Project Settings → Environment Variables):
208
- - `DEEPL_AUTH_KEY` — your key
209
- - `DEEPL_BASE_URL` — `https://api-free.deepl.com` or `https://api.deepl.com`
210
-
211
- Create `pages/api/deepl.ts` (or `app/api/deepl/route.ts` for App Router):
212
- ```
213
- export default async function handler(req, res) {
214
- res.setHeader('Access-Control-Allow-Origin', '*');
215
- res.setHeader('Access-Control-Allow-Headers', '*');
216
- if (req.method === 'OPTIONS') return res.status(204).end();
217
-
218
- const isFree = req.query.endpoint === 'free';
219
- const baseUrl = isFree ? 'https://api-free.deepl.com' : 'https://api.deepl.com';
220
- const upstream = `${baseUrl}/v2/translate`;
221
-
222
- const r = await fetch(upstream, {
223
- method: 'POST',
224
- headers: {
225
- 'Content-Type': 'application/json',
226
- 'Authorization': `DeepL-Auth-Key ${process.env.DEEPL_AUTH_KEY}`,
227
- },
228
- body: JSON.stringify(req.body ?? {}),
229
- });
230
- const text = await r.text();
231
- res.status(r.status).setHeader('Content-Type', 'application/json').send(text);
232
- }
233
- ```
234
-
235
- Deploy
236
- - `vercel deploy` (or push to GitHub with Vercel connected).
237
- - Set env vars, redeploy, then use `https://your-app.vercel.app/api/deepl` as the “Proxy URL”.
238
-
239
- Note on Vercel Deployment Protection
240
- - If your Vercel organization enforces Deployment Protection, unauthenticated public requests return 401.
241
- - Go to Vercel → Project → Settings → Deployment Protection and either disable protection for this project or add a public bypass so DatoCMS can call the endpoint.
242
- - After changing this setting, the proxy should be reachable from the plugin’s “Test proxy” and during translations.
243
-
244
- ### Option C: Netlify Functions
245
-
246
- Environment vars (Netlify dashboard → Site settings → Environment):
247
- - `DEEPL_AUTH_KEY`, `DEEPL_BASE_URL`
248
-
249
- Create `netlify/functions/deepl-proxy.ts`:
250
- ```
251
- export const handler = async (event) => {
252
- if (event.httpMethod === 'OPTIONS') {
253
- return { statusCode: 204, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': '*' } };
254
- }
255
-
256
- const isFree = event.queryStringParameters?.endpoint === 'free';
257
- const baseUrl = isFree ? 'https://api-free.deepl.com' : 'https://api.deepl.com';
258
- const upstream = `${baseUrl}/v2/translate`;
259
-
260
- const r = await fetch(upstream, {
261
- method: 'POST',
262
- headers: {
263
- 'Content-Type': 'application/json',
264
- 'Authorization': `DeepL-Auth-Key ${process.env.DEEPL_AUTH_KEY}`,
265
- },
266
- body: event.body || '{}',
267
- });
268
- const text = await r.text();
269
- return {
270
- statusCode: r.status,
271
- headers: { 'Access-Control-Allow-Origin': '*', 'Content-Type': 'application/json' },
272
- body: text,
273
- };
274
- };
275
- ```
276
-
277
- Deploy
278
- - `netlify deploy` (or via the Netlify app/CLI). Use `/.netlify/functions/deepl-proxy` as your “Proxy URL”.
279
-
280
- ### Testing and common errors
281
-
282
- - Use the “Test proxy” button in plugin settings to verify connectivity.
283
- - Wrong endpoint for key (403 / “Wrong endpoint”):
284
- - Free key (`…:fx`) must target `api-free.deepl.com`. Pro keys must target `api.deepl.com`.
285
- - Fix by setting `DEEPL_BASE_URL` accordingly (and/or toggle “Use DeepL Free endpoint” in the plugin).
286
- - CORS errors: ensure your proxy responds to OPTIONS and includes `Access-Control-Allow-Origin`.
287
- - 414/URI too long: means you’re not POSTing a body through your proxy. The examples above use POST and won’t hit this.
288
- - 429/Rate limit: lower concurrency or try smaller batches; upgrade plan if needed.
289
-
290
- Endpoint selection (Free vs Pro)
291
- - The example proxies choose the upstream via an environment variable `DEEPL_BASE_URL`.
292
- - Set `DEEPL_BASE_URL` to `https://api-free.deepl.com` if your key ends with `:fx` (DeepL Free), otherwise to `https://api.deepl.com` (Pro).
293
- - In the plugin settings, the toggle “Use DeepL Free endpoint (api-free.deepl.com)” should match the proxy’s `DEEPL_BASE_URL` so errors and validations are consistent. A mismatch will surface as a “Wrong endpoint for your API key” error.
294
-
295
- That’s it — once your proxy passes the test, DeepL translations (including large Structured Text fields) will work end‑to‑end.
296
-
297
-
298
-
299
141
  ## DeepL Glossaries
300
142
 
301
143
  The plugin supports DeepL glossaries to enforce preferred terminology. You can set a default glossary ID and/or map specific language pairs to specific glossary IDs. This works for all field types, including Structured Text.
@@ -303,15 +145,14 @@ The plugin supports DeepL glossaries to enforce preferred terminology. You can s
303
145
  ### Requirements
304
146
 
305
147
  - A DeepL API key with access to Glossaries. Check your DeepL account/plan capabilities.
306
- - The same proxy described above; translations with a glossary still call `POST <proxy>/v2/translate` with an extra `glossary_id` in the JSON body.
307
148
 
308
149
  ### Configure in the Plugin
309
150
 
310
- 1. Open Settings → vendor DeepL”.
311
- 2. Set “Proxy URL” and verify it via Test proxy”.
312
- 3. Expand Advanced settings”.
313
- 4. Optional: set Default glossary ID (e.g., `gls-abc123`).
314
- 5. Optional: fill in Glossaries by language pair with one mapping per line.
151
+ 1. Open Settings → vendor "DeepL".
152
+ 2. Enter your DeepL API Key and verify it via "Test API Key".
153
+ 3. Expand "Advanced settings".
154
+ 4. Optional: set "Default glossary ID" (e.g., `gls-abc123`).
155
+ 5. Optional: fill in "Glossaries by language pair" with one mapping per line.
315
156
 
316
157
  You can use either DatoCMS locales (e.g., `en-US`, `pt-BR`) or DeepL codes (e.g., `EN`, `PT-BR`). The plugin normalizes both to DeepL codes internally.
317
158
 
@@ -394,14 +235,14 @@ curl -X POST https://api.deepl.com/v2/glossaries \
394
235
 
395
236
  Note: If your account uses the Free endpoint, replace the host with `https://api-free.deepl.com`.
396
237
 
397
- You do not need to expose `/v2/glossaries` through your proxy for the plugin to work — it only calls `/v2/translate`. Manage glossaries from your server/CLI, then paste the resulting IDs into the plugin settings.
238
+ Manage glossaries from your server/CLI or the DeepL dashboard, then paste the resulting IDs into the plugin settings.
398
239
 
399
240
  ### Tips and Limitations
400
241
 
401
242
  - Glossaries apply only to the DeepL vendor. OpenAI/Gemini/Anthropic do not use glossaries.
402
243
  - The plugin preserves placeholders and HTML tags automatically (`notranslate`, `ph`, etc.). Glossaries will not alter those tokens.
403
- - If you use DeepL formality”, it is sent only for targets that support it; otherwise omitted.
404
- - A wrong Pro/Free endpoint for your key will still raise the “Wrong endpoint” hint shown in settings and translation errors.
244
+ - If you use DeepL "formality", it is sent only for targets that support it; otherwise omitted.
245
+ - Ensure your API key matches the endpoint setting: Free keys (ending with `:fx`) should have "Use DeepL Free endpoint" enabled.
405
246
 
406
247
  ### Quick Sanity Test
407
248
 
@@ -416,6 +257,13 @@ You do not need to expose `/v2/glossaries` through your proxy for the plugin to
416
257
  1. In Google Cloud, enable the Generative Language API for your project.
417
258
  2. Create an API key and restrict it by HTTP referrer if possible.
418
259
  3. In the plugin settings, switch vendor to Google (Gemini), paste the key, and select a Gemini model.
260
+ - To use Anthropic (Claude):
261
+ 1. Get an API key from the Anthropic Console.
262
+ 2. In the plugin settings, switch vendor to Anthropic (Claude), paste the key, and select a Claude model.
263
+ - To use DeepL:
264
+ 1. Get an API key from your DeepL account (Pro or Free).
265
+ 2. In the plugin settings, switch vendor to DeepL and paste the key.
266
+ 3. If using a Free key (ends with `:fx`), enable "Use DeepL Free endpoint".
419
267
 
420
268
  ## License
421
269