gptrans 2.1.10 → 2.2.4

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/index.js CHANGED
@@ -1,20 +1,26 @@
1
1
  import DeepBase from 'deepbase';
2
+ import { JsonDriver } from 'deepbase-json';
2
3
  import stringHash from 'string-hash';
3
4
  import { ModelMix } from 'modelmix';
4
5
  import { isoAssoc, isLanguageAvailable } from './isoAssoc.js';
5
6
  import { GeminiGenerator } from 'genmix';
6
7
  import fs from 'fs';
7
- import path from 'path';
8
+ import pathModule from 'path';
9
+
10
+ const TRANSLATE_PROMPT_FILE = pathModule.join(import.meta.dirname, 'prompt', 'translate.md');
11
+ const REFINE_PROMPT_FILE = pathModule.join(import.meta.dirname, 'prompt', 'refine.md');
12
+ const DEFAULT_MODEL_CHAIN = Object.freeze(['sonnet5@50', 'gpt56luna@100']);
8
13
 
9
14
  class GPTrans {
10
15
  static #mmixInstances = new Map();
11
16
  static #translationLocks = new Map();
12
17
 
13
- static mmix(models = 'sonnet45', { debug = 0 } = {}) {
14
- const key = Array.isArray(models) ? models.join(',') : models;
18
+ static mmix(models = DEFAULT_MODEL_CHAIN, { debug = 0 } = {}) {
19
+ const modelChain = Array.isArray(models) ? models : [models];
20
+ const key = modelChain.join(',');
15
21
 
16
22
  if (!this.#mmixInstances.has(key)) {
17
- let instance = ModelMix.new({
23
+ const instance = ModelMix.new({
18
24
  config: {
19
25
  debug,
20
26
  bottleneck: {
@@ -22,18 +28,7 @@ class GPTrans {
22
28
  maxConcurrent: 1
23
29
  }
24
30
  }
25
- });
26
- const modelArray = Array.isArray(models) ? models : [models];
27
-
28
- for (const model of modelArray) {
29
- if (typeof instance[model] !== 'function') {
30
- throw new Error(
31
- `Model "${model}" is not available. Please check the model name. ` +
32
- `Available models include: gpt51, gpt52, sonnet46, sonnet45, opus46, haiku45, etc.`
33
- );
34
- }
35
- instance = instance[model]();
36
- }
31
+ }).chain(...modelChain);
37
32
 
38
33
  this.#mmixInstances.set(key, instance);
39
34
  }
@@ -62,23 +57,21 @@ class GPTrans {
62
57
  return isLanguageAvailable(langCode);
63
58
  }
64
59
 
65
- constructor({ from = 'en-US', target = 'es', model = 'sonnet46', batchThreshold = 1500, debounceTimeout = 500, promptFile = null, name = '', context = '', instruction = '', freeze = false, debug = false } = {}) {
60
+ constructor({ from = 'en-US', target = 'es', model = DEFAULT_MODEL_CHAIN, batchThreshold = 1500, debounceTimeout = 500, promptFile = null, name = '', context = '', instruction = '', freeze = false, debug = false, path: dbPath } = {}) {
61
+
62
+ if (typeof dbPath !== 'string' || !pathModule.isAbsolute(dbPath)) {
63
+ throw new TypeError('GPTrans requires an absolute "path" option.');
64
+ }
66
65
 
67
66
  target = this.normalizeBCP47(target);
68
67
  from = this.normalizeBCP47(from);
69
68
 
70
- try {
71
- process.loadEnvFile();
72
- } catch {
73
- /* optional .env missing or unreadable */
74
- }
75
-
76
- const path = new URL('../../db', import.meta.url).pathname;
77
69
  const namePrefix = name ? '_' + name : '';
78
- this.dbPath = path;
70
+ this.dbPath = dbPath;
79
71
  this.instanceName = name;
80
- this.dbTarget = new DeepBase({ name: 'gptrans' + namePrefix + '_' + target, path });
81
- this.dbFrom = new DeepBase({ name: 'gptrans' + namePrefix + '_from_' + from, path });
72
+ this.dbTarget = this._createDatabase('gptrans' + namePrefix + '_' + target);
73
+ this.dbFrom = this._createDatabase('gptrans' + namePrefix + '_from_' + from);
74
+ this.pendingSourceWrites = Promise.resolve();
82
75
 
83
76
  try {
84
77
  this.replaceTarget = isoAssoc(target, 'TARGET_');
@@ -95,7 +88,7 @@ class GPTrans {
95
88
  this.isProcessingBatch = false; // Track if a batch is currently being processed
96
89
  this.modelMixOptions = { debug };
97
90
  this.modelKey = model;
98
- this.promptFile = promptFile ?? new URL('./prompt/translate.md', import.meta.url).pathname;
91
+ this.promptFile = promptFile ? pathModule.resolve(promptFile) : TRANSLATE_PROMPT_FILE;
99
92
  this.context = context;
100
93
  this.instruction = instruction;
101
94
  this.freeze = freeze;
@@ -116,6 +109,17 @@ class GPTrans {
116
109
  return iso.toLowerCase();
117
110
  }
118
111
 
112
+ _createDatabase(name) {
113
+ return new DeepBase(new JsonDriver({ name, path: this.dbPath }));
114
+ }
115
+
116
+ _saveSourceText(context, contextHash, key, text) {
117
+ this.pendingSourceWrites = this.pendingSourceWrites.then(async () => {
118
+ await this.dbFrom.set(context, key, text);
119
+ await this.dbFrom.set('_context', contextHash, context);
120
+ });
121
+ }
122
+
119
123
  setContext(context = '') {
120
124
  if (this.context !== context && this.pendingTranslations.size > 0) {
121
125
  clearTimeout(this.debounceTimer);
@@ -143,9 +147,10 @@ class GPTrans {
143
147
  // If this key was enqueued via t(), avoid duplicate work in a later batch.
144
148
  this._dequeuePendingTranslation(key);
145
149
 
150
+ await this.pendingSourceWrites;
146
151
  const translatedText = await this._translate(text, [[key, text]], {}, this.preloadBaseLanguage);
147
152
  const immediateTranslation = translatedText.trim();
148
- this.dbTarget.set(contextHash, key, immediateTranslation);
153
+ await this.dbTarget.set(contextHash, key, immediateTranslation);
149
154
 
150
155
  return this._applyParams(immediateTranslation, params);
151
156
  }
@@ -171,11 +176,10 @@ class GPTrans {
171
176
  }
172
177
 
173
178
  const contextHash = this._hash(this.context);
174
- const translation = this.dbTarget.get(contextHash, key);
179
+ const translation = this.dbTarget.getSync(contextHash, key);
175
180
 
176
- if (!this.freeze && !this.dbFrom.get(this.context, key)) {
177
- this.dbFrom.set(this.context, key, text);
178
- this.dbFrom.set('_context', contextHash, this.context);
181
+ if (!this.freeze && !this.dbFrom.getSync(this.context, key)) {
182
+ this._saveSourceText(this.context, contextHash, key, text);
179
183
  }
180
184
 
181
185
  if (translation) {
@@ -233,16 +237,17 @@ class GPTrans {
233
237
  async _processBatch(context) {
234
238
 
235
239
  const batch = Array.from(this.pendingTranslations.entries());
240
+ const batchCharCount = this.pendingCharCount;
236
241
 
237
242
  // Clear pending translations and character count before awaiting translation
238
243
  this.pendingTranslations.clear();
244
+ this.pendingCharCount = 0;
245
+ await this.pendingSourceWrites;
239
246
 
240
- this.modelConfig.options.max_tokens = this.pendingCharCount + 1000;
241
- const minTime = Math.floor((60000 / (8000 / this.pendingCharCount)) * 1.4);
247
+ this.modelConfig.options.max_tokens = batchCharCount + 1000;
248
+ const minTime = Math.floor((60000 / (8000 / batchCharCount)) * 1.4);
242
249
  GPTrans.mmix(this.modelKey, this.modelMixOptions).limiter.updateSettings({ minTime });
243
250
 
244
- this.pendingCharCount = 0;
245
-
246
251
  // Load references for each text in the batch if preloadReferences is set
247
252
  const batchReferences = {};
248
253
  if (this.preloadReferences && this.preloadReferences.length > 0) {
@@ -280,7 +285,7 @@ class GPTrans {
280
285
  const minLength = Math.min(translatedTexts.length, batch.length);
281
286
  for (let i = 0; i < minLength; i++) {
282
287
  if (translatedTexts[i] && translatedTexts[i].trim()) {
283
- this.dbTarget.set(contextHash, batch[i][0], translatedTexts[i].trim());
288
+ await this.dbTarget.set(contextHash, batch[i][0], translatedTexts[i].trim());
284
289
  }
285
290
  }
286
291
  return;
@@ -295,15 +300,15 @@ class GPTrans {
295
300
  return;
296
301
  }
297
302
 
298
- batch.forEach(([key], index) => {
303
+ for (const [index, [key]] of batch.entries()) {
299
304
  if (!trimmed[index]) {
300
305
  console.error(`❌ No translation found for ${key} at index ${index}`);
301
306
  console.error(` Original text: ${batch[index][1]}`);
302
- return;
307
+ continue;
303
308
  }
304
309
 
305
- this.dbTarget.set(contextHash, key, trimmed[index]);
306
- });
310
+ await this.dbTarget.set(contextHash, key, trimmed[index]);
311
+ }
307
312
 
308
313
  } catch (e) {
309
314
  console.error('❌ Error in _processBatch:', e.message);
@@ -318,7 +323,7 @@ class GPTrans {
318
323
  try {
319
324
  const model = GPTrans.mmix(this.modelKey, this.modelMixOptions);
320
325
 
321
- model.setSystem("You are an expert translator specialized in literary translation between {FROM_LANG} and {TARGET_DENONYM} {TARGET_LANG}.");
326
+ model.setSystem("You are an expert translator specialized in literary translation between <%- FROM_LANG %> and <%- TARGET_DENONYM %> <%- TARGET_LANG %>.");
322
327
 
323
328
  // Build references section (includes header when references exist, empty otherwise)
324
329
  let referencesText = '';
@@ -362,21 +367,21 @@ class GPTrans {
362
367
  }
363
368
  }
364
369
 
365
- // Use ModelMix templates: addTextFromFile + replace + block
370
+ // Use ModelMix templates: addTextFromFile + assign + block
366
371
  model.addTextFromFile(this.promptFile);
367
- model.replace({
368
- '{INPUT}': text,
369
- '{CONTEXT}': this.context,
370
- '{INSTRUCTION}': this.instruction,
371
- '{REFERENCES}': referencesText,
372
- '{TARGET_ISO}': this.replaceTarget.TARGET_ISO,
373
- '{TARGET_LANG}': this.replaceTarget.TARGET_LANG,
374
- '{TARGET_COUNTRY}': this.replaceTarget.TARGET_COUNTRY,
375
- '{TARGET_DENONYM}': this.replaceTarget.TARGET_DENONYM,
376
- '{FROM_ISO}': fromReplace.FROM_ISO,
377
- '{FROM_LANG}': fromReplace.FROM_LANG,
378
- '{FROM_COUNTRY}': fromReplace.FROM_COUNTRY,
379
- '{FROM_DENONYM}': fromReplace.FROM_DENONYM,
372
+ model.assign({
373
+ INPUT: text,
374
+ CONTEXT: this.context,
375
+ INSTRUCTION: this.instruction,
376
+ REFERENCES: referencesText,
377
+ TARGET_ISO: this.replaceTarget.TARGET_ISO,
378
+ TARGET_LANG: this.replaceTarget.TARGET_LANG,
379
+ TARGET_COUNTRY: this.replaceTarget.TARGET_COUNTRY,
380
+ TARGET_DENONYM: this.replaceTarget.TARGET_DENONYM,
381
+ FROM_ISO: fromReplace.FROM_ISO,
382
+ FROM_LANG: fromReplace.FROM_LANG,
383
+ FROM_COUNTRY: fromReplace.FROM_COUNTRY,
384
+ FROM_DENONYM: fromReplace.FROM_DENONYM,
380
385
  });
381
386
 
382
387
  return await model.block({ addSystemExtra: false });
@@ -411,12 +416,9 @@ class GPTrans {
411
416
 
412
417
  for (const lang of referenceLangs) {
413
418
  const namePrefix = this.instanceName ? '_' + this.instanceName : '';
414
- const dbRef = new DeepBase({
415
- name: `gptrans${namePrefix}_${lang}`,
416
- path: this.dbPath
417
- });
419
+ const dbRef = this._createDatabase(`gptrans${namePrefix}_${lang}`);
418
420
 
419
- const translation = dbRef.get(contextHash, key);
421
+ const translation = dbRef.getSync(contextHash, key);
420
422
  if (translation) {
421
423
  references[lang] = translation;
422
424
  }
@@ -427,6 +429,8 @@ class GPTrans {
427
429
 
428
430
  async preload({ references = [], baseLanguage = null } = {}) {
429
431
 
432
+ await this.pendingSourceWrites;
433
+
430
434
  if (!this.context && this.replaceFrom.FROM_ISO === this.replaceTarget.TARGET_ISO) {
431
435
  return this;
432
436
  }
@@ -454,7 +458,7 @@ class GPTrans {
454
458
  // Track which keys need translation
455
459
  const keysNeedingTranslation = [];
456
460
 
457
- for (const [context, pairs] of this.dbFrom.entries()) {
461
+ for (const [context, pairs] of Object.entries(this.dbFrom.getSync() ?? {})) {
458
462
  // Skip the _context metadata
459
463
  if (context === '_context') continue;
460
464
 
@@ -463,7 +467,7 @@ class GPTrans {
463
467
 
464
468
  for (const [key, text] of Object.entries(pairs)) {
465
469
  // Check if translation already exists
466
- if (!this.dbTarget.get(contextHash, key)) {
470
+ if (!this.dbTarget.getSync(contextHash, key)) {
467
471
  keysNeedingTranslation.push({ context, contextHash, key });
468
472
  // Only call get() if translation doesn't exist
469
473
  this.get(key, text);
@@ -488,7 +492,7 @@ class GPTrans {
488
492
  // Check if all needed translations are now complete
489
493
  let allTranslated = true;
490
494
  for (const { contextHash, key } of keysNeedingTranslation) {
491
- if (!this.dbTarget.get(contextHash, key)) {
495
+ if (!this.dbTarget.getSync(contextHash, key)) {
492
496
  allTranslated = false;
493
497
  break;
494
498
  }
@@ -514,12 +518,14 @@ class GPTrans {
514
518
  }
515
519
 
516
520
  async purge() {
521
+ await this.pendingSourceWrites;
522
+
517
523
  // Iterate through dbTarget and remove keys that don't exist in dbFrom
518
- for (const [contextHash, pairs] of this.dbTarget.entries()) {
524
+ for (const [contextHash, pairs] of Object.entries(this.dbTarget.getSync() ?? {})) {
519
525
  for (const key of Object.keys(pairs)) {
520
526
 
521
- const context = this.dbFrom.get('_context', contextHash);
522
- if (!this.dbFrom.get(context, key)) {
527
+ const context = this.dbFrom.getSync('_context', contextHash);
528
+ if (!this.dbFrom.getSync(context, key)) {
523
529
  console.log(contextHash, key);
524
530
  await this.dbTarget.del(contextHash, key);
525
531
  }
@@ -539,14 +545,14 @@ class GPTrans {
539
545
  }
540
546
 
541
547
  const finalInstruction = instructions.length > 1 ? `- ${merged}` : merged;
542
- const refinePromptFile = promptFile ?? new URL('./prompt/refine.md', import.meta.url).pathname;
548
+ const refinePromptFile = promptFile ? pathModule.resolve(promptFile) : REFINE_PROMPT_FILE;
543
549
 
544
550
  // Collect all existing translations grouped by contextHash
545
551
  const allBatches = [];
546
552
  let currentBatch = [];
547
553
  let currentCharCount = 0;
548
554
 
549
- for (const [contextHash, pairs] of this.dbTarget.entries()) {
555
+ for (const [contextHash, pairs] of Object.entries(this.dbTarget.getSync() ?? {})) {
550
556
  for (const [key, translation] of Object.entries(pairs)) {
551
557
  const entryCharCount = translation.length;
552
558
 
@@ -607,20 +613,20 @@ class GPTrans {
607
613
  const minLength = Math.min(refinedTexts.length, entries.length);
608
614
  for (let i = 0; i < minLength; i++) {
609
615
  if (refinedTexts[i] && refinedTexts[i].trim()) {
610
- this.dbTarget.set(entries[i].contextHash, entries[i].key, refinedTexts[i].trim());
616
+ await this.dbTarget.set(entries[i].contextHash, entries[i].key, refinedTexts[i].trim());
611
617
  }
612
618
  }
613
619
  return;
614
620
  }
615
621
 
616
- entries.forEach((entry, index) => {
622
+ for (const [index, entry] of entries.entries()) {
617
623
  const refinedText = refinedTexts[index]?.trim();
618
624
  if (!refinedText) {
619
625
  console.error(`❌ No refined text for ${entry.key} at index ${index}`);
620
- return;
626
+ continue;
621
627
  }
622
- this.dbTarget.set(entry.contextHash, entry.key, refinedText);
623
- });
628
+ await this.dbTarget.set(entry.contextHash, entry.key, refinedText);
629
+ }
624
630
 
625
631
  } catch (e) {
626
632
  console.error('❌ Error in _processRefineBatch:', e.message);
@@ -634,22 +640,22 @@ class GPTrans {
634
640
  try {
635
641
  const model = GPTrans.mmix(this.modelKey, this.modelMixOptions);
636
642
 
637
- model.setSystem("You are an expert translator and editor specialized in refining {TARGET_DENONYM} {TARGET_LANG} translations.");
643
+ model.setSystem("You are an expert translator and editor specialized in refining <%- TARGET_DENONYM %> <%- TARGET_LANG %> translations.");
638
644
 
639
- // Use ModelMix templates: addTextFromFile + replace + block
645
+ // Use ModelMix templates: addTextFromFile + assign + block
640
646
  model.addTextFromFile(refinePromptFile);
641
- model.replace({
642
- '{INPUT}': text,
643
- '{INSTRUCTION}': instruction,
644
- '{CONTEXT}': this.context,
645
- '{TARGET_ISO}': this.replaceTarget.TARGET_ISO,
646
- '{TARGET_LANG}': this.replaceTarget.TARGET_LANG,
647
- '{TARGET_COUNTRY}': this.replaceTarget.TARGET_COUNTRY,
648
- '{TARGET_DENONYM}': this.replaceTarget.TARGET_DENONYM,
649
- '{FROM_ISO}': this.replaceFrom.FROM_ISO,
650
- '{FROM_LANG}': this.replaceFrom.FROM_LANG,
651
- '{FROM_COUNTRY}': this.replaceFrom.FROM_COUNTRY,
652
- '{FROM_DENONYM}': this.replaceFrom.FROM_DENONYM,
647
+ model.assign({
648
+ INPUT: text,
649
+ INSTRUCTION: instruction,
650
+ CONTEXT: this.context,
651
+ TARGET_ISO: this.replaceTarget.TARGET_ISO,
652
+ TARGET_LANG: this.replaceTarget.TARGET_LANG,
653
+ TARGET_COUNTRY: this.replaceTarget.TARGET_COUNTRY,
654
+ TARGET_DENONYM: this.replaceTarget.TARGET_DENONYM,
655
+ FROM_ISO: this.replaceFrom.FROM_ISO,
656
+ FROM_LANG: this.replaceFrom.FROM_LANG,
657
+ FROM_COUNTRY: this.replaceFrom.FROM_COUNTRY,
658
+ FROM_DENONYM: this.replaceFrom.FROM_DENONYM,
653
659
  });
654
660
 
655
661
  return await model.block({ addSystemExtra: false });
@@ -668,13 +674,13 @@ class GPTrans {
668
674
  } = options;
669
675
 
670
676
  // Parse image filename and extension
671
- const parsedPath = path.parse(imagePath);
677
+ const parsedPath = pathModule.parse(imagePath);
672
678
  const filename = parsedPath.base;
673
679
  const targetLang = this.replaceTarget.TARGET_ISO || 'en';
674
680
 
675
681
  // Check if image is already in a language folder
676
- const dirName = path.basename(path.dirname(imagePath));
677
- const parentDir = path.dirname(path.dirname(imagePath));
682
+ const dirName = pathModule.basename(pathModule.dirname(imagePath));
683
+ const parentDir = pathModule.dirname(pathModule.dirname(imagePath));
678
684
 
679
685
  // If the image is in a language folder (e.g., en/image.jpg)
680
686
  // create the target at the same level (e.g., es/image.jpg)
@@ -683,12 +689,12 @@ class GPTrans {
683
689
 
684
690
  if (this._isLanguageFolder(dirName)) {
685
691
  // Image is in a language folder: create sibling folder
686
- targetDir = path.join(parentDir, targetLang);
687
- targetPath = path.join(targetDir, filename);
692
+ targetDir = pathModule.join(parentDir, targetLang);
693
+ targetPath = pathModule.join(targetDir, filename);
688
694
  } else {
689
695
  // Image is not in a language folder: create subfolder
690
- targetDir = path.join(path.dirname(imagePath), targetLang);
691
- targetPath = path.join(targetDir, filename);
696
+ targetDir = pathModule.join(pathModule.dirname(imagePath), targetLang);
697
+ targetPath = pathModule.join(targetDir, filename);
692
698
  }
693
699
 
694
700
  // Check if translated image already exists
@@ -736,7 +742,7 @@ class GPTrans {
736
742
  }
737
743
 
738
744
  // Save translated image - preserve original file format
739
- const filename = path.basename(targetPath, path.extname(targetPath));
745
+ const filename = pathModule.basename(targetPath, pathModule.extname(targetPath));
740
746
  const formatOptions = generator.getReferenceMetadata();
741
747
 
742
748
  // Apply default quality settings for JPEG images
@@ -755,4 +761,4 @@ class GPTrans {
755
761
  }
756
762
  }
757
763
 
758
- export default GPTrans;
764
+ export default GPTrans;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "gptrans",
3
3
  "type": "module",
4
- "version": "2.1.10",
4
+ "version": "2.2.4",
5
5
  "description": "🚆 GPTrans - The smarter AI-powered way to translate.",
6
6
  "keywords": [
7
7
  "translate",
@@ -32,12 +32,13 @@
32
32
  },
33
33
  "homepage": "https://github.com/clasen/GPTrans#readme",
34
34
  "engines": {
35
- "node": ">=20.6.0"
35
+ "node": ">=20.12.0"
36
36
  },
37
37
  "dependencies": {
38
- "deepbase": "^1.5.6",
39
- "genmix": "^1.2.4",
40
- "modelmix": "^4.6.5",
38
+ "deepbase": "^3.9.0",
39
+ "deepbase-json": "3.9.0",
40
+ "genmix": "^1.2.5",
41
+ "modelmix": "^5.1.6",
41
42
  "string-hash": "^1.1.3"
42
43
  },
43
44
  "scripts": {
@@ -1,5 +1,10 @@
1
1
  allowBuilds:
2
2
  sharp: true
3
+ minimumReleaseAgeExclude:
4
+ - genmix@1.2.5
5
+ - deepbase-json@3.9.0
6
+ - deepbase@3.9.0
7
+ - modelmix@5.1.6
3
8
  overrides:
4
9
  sharp: "^0.35.0"
5
10
  "@hono/node-server": "^2.0.5"
package/prompt/refine.md CHANGED
@@ -1,12 +1,12 @@
1
1
  # Goal
2
- Refine existing translations in {TARGET_ISO} ({TARGET_DENONYM} {TARGET_LANG}) based on the following instruction.
2
+ Refine existing translations in <%- TARGET_ISO %> (<%- TARGET_DENONYM %> <%- TARGET_LANG %>) based on the following instruction.
3
3
 
4
4
  ## Refinement Instruction
5
- {INSTRUCTION}
5
+ <%- INSTRUCTION %>
6
6
 
7
7
  ## Current Translations to Evaluate
8
8
  ```
9
- {INPUT}
9
+ <%- INPUT %>
10
10
  ```
11
11
 
12
12
  # Return Format
@@ -23,4 +23,4 @@ Refine existing translations in {TARGET_ISO} ({TARGET_DENONYM} {TARGET_LANG}) ba
23
23
  - **Consistency:** Maintain consistent terminology across all translations in the batch.
24
24
 
25
25
  # Context
26
- {CONTEXT}
26
+ <%- CONTEXT %>
@@ -1,13 +1,13 @@
1
1
  # Goal
2
- Translation from {FROM_ISO} to {TARGET_ISO} ({TARGET_DENONYM} {TARGET_LANG}) with cultural adaptations.
3
- {INSTRUCTION}
2
+ Translation from <%- FROM_ISO %> to <%- TARGET_ISO %> (<%- TARGET_DENONYM %> <%- TARGET_LANG %>) with cultural adaptations.
3
+ <%- INSTRUCTION %>
4
4
 
5
5
  ## Text to translate
6
6
  ```
7
- {INPUT}
7
+ <%- INPUT %>
8
8
  ```
9
9
 
10
- {REFERENCES}
10
+ <%- REFERENCES %>
11
11
 
12
12
  # Return Format
13
13
  - The input may contain multiple texts separated by `------`. Translate each one independently and return them in the same order, separated by `------`. The number of segments in your output must exactly match the number of segments in the input.
@@ -15,13 +15,13 @@ Translation from {FROM_ISO} to {TARGET_ISO} ({TARGET_DENONYM} {TARGET_LANG}) wit
15
15
  - Do not include alternative translations, only provide the best translation.
16
16
 
17
17
  # Warnings
18
- - **Context:** I will provide you with a text in {FROM_DENONYM} {FROM_LANG}. The goal is to translate it to {TARGET_ISO} ({TARGET_DENONYM} {TARGET_LANG}) while maintaining the essence, style, intention, and tone of the original.
18
+ - **Context:** I will provide you with a text in <%- FROM_DENONYM %> <%- FROM_LANG %>. The goal is to translate it to <%- TARGET_ISO %> (<%- TARGET_DENONYM %> <%- TARGET_LANG %>) while maintaining the essence, style, intention, and tone of the original.
19
19
  - **Proper names:** Do not translate proper names (people, places, brands, etc.) unless they have an officially recognized translation in the target language.
20
- - **Cultural references:** Adapt or explain references that are not familiar in {TARGET_DENONYM} culture, whenever necessary.
20
+ - **Cultural references:** Adapt or explain references that are not familiar in <%- TARGET_DENONYM %> culture, whenever necessary.
21
21
  - **Wordplay and humor:** When it's impossible to directly translate wordplay, find a resource that recreates the playful effect.
22
22
  - **Idioms:** Do not introduce new idioms or expressions that are not present in the original text.
23
23
  - **Variables:** Do not translate content between curly braces. These are system variables and must remain exactly the same.
24
24
 
25
25
 
26
26
  # Context
27
- {CONTEXT}
27
+ <%- CONTEXT %>