@gringow/gringow 0.1.3 → 0.2.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.
Files changed (49) hide show
  1. package/README.md +279 -43
  2. package/dist/config.d.mts +7 -8
  3. package/dist/config.mjs +32 -20
  4. package/dist/config.test.mjs +39 -25
  5. package/dist/constants/default-config.mjs +4 -3
  6. package/dist/data/check-cache.mjs +33 -63
  7. package/dist/data/clear-cache.mjs +32 -20
  8. package/dist/data/create-cache-dir.mjs +32 -20
  9. package/dist/data/delete-cache-item.mjs +32 -20
  10. package/dist/data/get-cache.mjs +32 -20
  11. package/dist/data/get-or-create-cache.mjs +32 -20
  12. package/dist/data/save-cache.mjs +32 -20
  13. package/dist/data/write-cache-to-disk.mjs +32 -20
  14. package/dist/gringow.mjs +84 -491
  15. package/dist/index.mjs +84 -491
  16. package/dist/io/ask-llm.d.mts +3 -1
  17. package/dist/io/ask-llm.mjs +77 -449
  18. package/dist/schemas/config.shcema.d.mts +40 -47
  19. package/dist/schemas/config.shcema.mjs +26 -15
  20. package/dist/types/index.d.mts +3 -25
  21. package/gringow.config.js.example +2 -4
  22. package/gringow.config.json.example +4 -2
  23. package/package.json +2 -5
  24. package/dist/io/anthropic/ask.d.mts +0 -11
  25. package/dist/io/anthropic/ask.mjs +0 -190
  26. package/dist/io/anthropic/commit-response.d.mts +0 -21
  27. package/dist/io/anthropic/commit-response.mjs +0 -10
  28. package/dist/io/anthropic/index.d.mts +0 -14
  29. package/dist/io/anthropic/index.mjs +0 -208
  30. package/dist/io/anthropic/parse.d.mts +0 -20
  31. package/dist/io/anthropic/parse.mjs +0 -10
  32. package/dist/io/gemini/ask.d.mts +0 -11
  33. package/dist/io/gemini/ask.mjs +0 -232
  34. package/dist/io/gemini/commit-response.d.mts +0 -11
  35. package/dist/io/gemini/commit-response.mjs +0 -7
  36. package/dist/io/gemini/index.d.mts +0 -14
  37. package/dist/io/gemini/index.mjs +0 -248
  38. package/dist/io/gemini/parse.d.mts +0 -20
  39. package/dist/io/gemini/parse.mjs +0 -11
  40. package/dist/io/huggingface/ask.d.mts +0 -13
  41. package/dist/io/huggingface/ask.mjs +0 -405
  42. package/dist/io/huggingface/commit-response.d.mts +0 -39
  43. package/dist/io/huggingface/commit-response.mjs +0 -14
  44. package/dist/io/huggingface/index.d.mts +0 -13
  45. package/dist/io/huggingface/index.mjs +0 -426
  46. package/dist/io/huggingface/languages-map.d.mts +0 -191
  47. package/dist/io/huggingface/languages-map.mjs +0 -187
  48. package/dist/io/huggingface/parse.d.mts +0 -20
  49. package/dist/io/huggingface/parse.mjs +0 -9
package/README.md CHANGED
@@ -1,6 +1,18 @@
1
1
  # @gringow/gringow
2
2
 
3
- Core library for Gringow to translate strings and template strings using different LLM providers.
3
+ [![npm version](https://img.shields.io/npm/v/@gringow/gringow)](https://www.npmjs.com/package/@gringow/gringow)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
+
6
+ AI-powered translation library for template strings using multiple LLM providers (Hugging Face, Anthropic, Gemini). Gringow provides smart caching, deterministic content hashing, and seamless integration for modern JavaScript/TypeScript projects.
7
+
8
+ ## Features
9
+
10
+ - 🌍 **Multi-language translation** using LLM providers
11
+ - 🏷️ **Tagged template literal** syntax for inline translations
12
+ - 💾 **Smart caching** with content-based hashing
13
+ - 🔌 **Three LLM providers**: Hugging Face (local), Anthropic, Gemini
14
+ - 🚀 **Zero configuration** - works out of the box with Hugging Face
15
+ - 📦 **Optimized builds** via Vite/Next.js plugins
4
16
 
5
17
  ## Installation
6
18
 
@@ -12,45 +24,90 @@ pnpm add @gringow/gringow
12
24
  yarn add @gringow/gringow
13
25
  ```
14
26
 
15
- ## Usage
27
+ ## Quick Start
16
28
 
17
29
  ```typescript
18
- import Gringow, { rebuild } from '@gringow/gringow'
30
+ import Gringow from '@gringow/gringow'
19
31
 
20
32
  // Simple string translation
21
33
  const { cacheId, translation } = await Gringow`Hello world`
22
- console.log(cacheId) // deterministic cache ID created from the flattened string
23
- console.log(translation.translation) // { "pt-BR": "Olá mundo", "fr-CA": "Bonjour le monde" }
34
+ console.log(translation.translation)
35
+ // => { "pt-BR": "Olá mundo", "fr-CA": "Bonjour le monde" }
24
36
 
25
- // Template string translation (values are flattened before hashing)
37
+ // Template string with dynamic values
26
38
  const name = 'John'
27
- const { translation: hiJohn } = await Gringow`Hello ${name}`
28
- console.log(hiJohn.translation) // { "pt-BR": "Olá John", "fr-CA": "Bonjour John" }
39
+ const { translation: result } = await Gringow`Welcome, ${name}!`
40
+ console.log(result.translation)
41
+ // => { "pt-BR": "Bem-vindo, John!", "fr-CA": "Bienvenue, John!" }
42
+ ```
43
+
44
+ ## Usage Examples
29
45
 
30
- // Re-run an existing cache entry against the configured LLM
46
+ ### Basic Translation
47
+
48
+ ```typescript
49
+ import Gringow from '@gringow/gringow'
50
+
51
+ // Translate a static string
52
+ const { translation } = await Gringow`Hello world`
53
+ console.log(translation.translation['pt-BR']) // "Olá mundo"
54
+ ```
55
+
56
+ ### Dynamic Content
57
+
58
+ ```typescript
59
+ // Template literals are flattened before hashing - dynamic values preserved
60
+ const user = { name: 'Alice', role: 'admin' }
61
+ const { translation } = await Gringow`User ${user.name} has ${user.role} privileges`
62
+
63
+ console.log(translation.translation['pt-BR'])
64
+ // => "Usuário Alice tem privilégios de admin"
65
+ ```
66
+
67
+ ### Cache Management
68
+
69
+ ```typescript
70
+ import Gringow, { rebuild, checkCache } from '@gringow/gringow'
71
+
72
+ const { cacheId } = await Gringow`Hello world`
73
+
74
+ // Check if translation exists in cache
75
+ const cached = await checkCache(cacheId)
76
+ console.log(cached) // GringowCacheItem or undefined
77
+
78
+ // Force re-translation by rebuilding cache entry
31
79
  const refreshed = await rebuild(cacheId)
32
80
  console.log(refreshed.translation.translation)
33
81
  ```
34
82
 
35
- Gringow always returns a `{ cacheId, translation }` object. The `translation` payload can include optional
36
- `prepend`/`append` strings when you use custom prompts.
83
+ ### Browser Usage
84
+
85
+ For client-side interpolation without Node.js dependencies:
86
+
87
+ ```typescript
88
+ import { interpolateTemplate } from '@gringow/gringow/browser'
89
+
90
+ const template = 'Hello {name}, you have {count} messages'
91
+ const result = interpolateTemplate(template, { name: 'Alice', count: 5 })
92
+ console.log(result) // "Hello Alice, you have 5 messages"
93
+ ```
37
94
 
38
95
  ## Configuration
39
96
 
40
- Gringow loads configuration via `cosmiconfig` using the `gringow` namespace. You can place any of the supported
41
- formats in your project root (e.g. `gringow.config.js`, `gringow.config.mjs`, `gringow.config.json`). Missing fields
42
- are merged with the defaults below and validated with Zod.
97
+ Gringow uses [cosmiconfig](https://github.com/cosmiconfig/cosmiconfig) to load configuration from your project root. Supported formats: `gringow.config.js`, `gringow.config.mjs`, `gringow.config.json`, or a `gringow` field in `package.json`.
98
+
99
+ ### Default Configuration
43
100
 
44
101
  ```js
45
102
  // gringow.config.js
46
103
  export default {
47
104
  debug: false,
48
- log: { level: 'debug' },
105
+ log: { level: 'info' },
49
106
  cache: {
50
107
  dir: './gringow',
51
108
  file: 'gringow.json',
52
109
  prefix: 'grw',
53
- write: true, // set to false to skip writing to disk
110
+ write: true,
54
111
  },
55
112
  keys: {
56
113
  anthropicApiKey: process.env.ANTHROPIC_API_KEY,
@@ -63,35 +120,171 @@ export default {
63
120
  model: 'Xenova/nllb-200-distilled-600M',
64
121
  temperature: 1.0,
65
122
  sleep: 0,
66
- // Prompt shaping (all optional)
67
- prePrompt: undefined,
68
- postPrompt: undefined,
69
- prePromptAppend: undefined,
70
- postPromptPrepend: undefined,
71
- prePromptReplace: undefined,
72
- postPromptReplace: undefined,
73
123
  },
74
- // Files scanned by the Vite/Next.js plugins when building caches
75
124
  globby: './src/**/*.{js,jsx,ts,tsx}',
76
125
  }
77
126
  ```
78
127
 
79
- > For `anthropic` or `gemini`, the corresponding API key **must** be present or config validation will fail.
128
+ ### Example: Using Gemini
129
+
130
+ ```js
131
+ // gringow.config.js
132
+ export default {
133
+ keys: {
134
+ geminiApiKey: process.env.GEMINI_API_KEY,
135
+ },
136
+ llm: {
137
+ choice: 'gemini',
138
+ model: 'gemini-2.0-flash',
139
+ prePromptAppend: 'Please respond in a friendly tone.',
140
+ },
141
+ languages: ['es-ES', 'de-DE', 'ja-JP'],
142
+ }
143
+ ```
144
+
145
+ ### Example: Using Anthropic
146
+
147
+ ```js
148
+ // gringow.config.js
149
+ export default {
150
+ keys: {
151
+ anthropicApiKey: process.env.ANTHROPIC_API_KEY,
152
+ },
153
+ llm: {
154
+ choice: 'anthropic',
155
+ model: 'claude-3-5-sonnet-20241022',
156
+ temperature: 0.7,
157
+ },
158
+ }
159
+ ```
160
+
161
+ ### Prompt Customization
162
+
163
+ Fine-tune LLM behavior with prompt options:
164
+
165
+ ```js
166
+ export default {
167
+ llm: {
168
+ choice: 'huggingface',
169
+ prePrompt: 'Translate the following text:', // Default prompt prefix
170
+ postPrompt: 'Ensure translations are natural.', // Additional context
171
+ prePromptAppend: 'Use formal language.', // Appended to pre-prompt
172
+ postPromptPrepend: 'Maintain original formatting.', // Prepended to post-prompt
173
+ prePromptReplace: 'Custom instruction here', // Replaces entire pre-prompt
174
+ },
175
+ }
176
+ ```
80
177
 
81
178
  ## LLM Providers
82
179
 
83
- - **Hugging Face** (default): Runs local models, no API key required.
84
- - **Anthropic**: Requires `keys.anthropicApiKey`.
85
- - **Gemini**: Requires `keys.geminiApiKey`.
180
+ ### Hugging Face (Default)
86
181
 
87
- ## API surface
182
+ Runs local models via `@huggingface/transformers`. **No API key required.**
183
+
184
+ ```js
185
+ // gringow.config.js
186
+ export default {
187
+ llm: {
188
+ choice: 'huggingface',
189
+ model: 'Xenova/nllb-200-distilled-600M', // Multilingual translation model
190
+ },
191
+ }
192
+ ```
88
193
 
89
- - `default export Gringow(strings, ...values)` — translate a string or tagged template. Returns a `Promise<GringowResponse>`.
90
- - `rebuild(cacheId)` — re-asks the configured LLM for a cached entry and writes it back when `cache.write` is true.
91
- - Cache helpers: `checkCache`, `getCache`, `getOrCreateCache`, `writeCacheToDisk`, `deleteCacheItem`, `clearCache`.
92
- - Utilities: `createCacheId`, `flatTemplateString`, `interpolateTemplate` (browser build), `awaitedConfig`, `isLocalConfigFound`, `getConfigSource`.
194
+ **Pros**: Free, private, offline-capable
195
+ **Cons**: Slower first run (model download), higher memory usage
93
196
 
94
- ```ts
197
+ ### Anthropic
198
+
199
+ Uses Claude models via Anthropic API. **Requires API key.**
200
+
201
+ ```js
202
+ // gringow.config.js
203
+ export default {
204
+ keys: {
205
+ anthropicApiKey: process.env.ANTHROPIC_API_KEY,
206
+ },
207
+ llm: {
208
+ choice: 'anthropic',
209
+ model: 'claude-3-5-sonnet-20241022',
210
+ },
211
+ }
212
+ ```
213
+
214
+ **Pros**: High-quality translations, fast
215
+ **Cons**: API costs, requires internet
216
+
217
+ ### Gemini
218
+
219
+ Uses Google's Gemini models. **Requires API key.**
220
+
221
+ ```js
222
+ // gringow.config.js
223
+ export default {
224
+ keys: {
225
+ geminiApiKey: process.env.GEMINI_API_KEY,
226
+ },
227
+ llm: {
228
+ choice: 'gemini',
229
+ model: 'gemini-2.0-flash',
230
+ },
231
+ }
232
+ ```
233
+
234
+ **Pros**: Fast, cost-effective
235
+ **Cons**: API costs, requires internet
236
+
237
+ ## API Reference
238
+
239
+ ### Core Functions
240
+
241
+ #### `Gringow(strings, ...values): Promise<GringowResponse>`
242
+
243
+ Main translation function. Accepts tagged template literals or plain strings.
244
+
245
+ ```typescript
246
+ const result = await Gringow`Hello ${name}`
247
+ ```
248
+
249
+ **Returns**: `Promise<GringowResponse>` with `{ cacheId, translation }`
250
+
251
+ #### `rebuild(cacheId: string): Promise<GringowResponse>`
252
+
253
+ Re-translates a cached entry using the current LLM configuration.
254
+
255
+ ```typescript
256
+ const refreshed = await rebuild('grw_abc123')
257
+ ```
258
+
259
+ ### Cache Helpers
260
+
261
+ ```typescript
262
+ import {
263
+ checkCache, // Check if cacheId exists
264
+ getCache, // Get entire cache object
265
+ getOrCreateCache,// Get cache or create empty one
266
+ writeCacheToDisk,// Manually write cache entry
267
+ deleteCacheItem, // Remove cache entry
268
+ clearCache, // Clear all cache entries
269
+ } from '@gringow/gringow'
270
+ ```
271
+
272
+ ### Utilities
273
+
274
+ ```typescript
275
+ import {
276
+ createCacheId, // Generate cache ID from string
277
+ flatTemplateString, // Flatten template literal to string
278
+ interpolateTemplate, // Browser-safe interpolation (from /browser export)
279
+ awaitedConfig, // Access resolved configuration
280
+ isLocalConfigFound, // Check if local config exists
281
+ getConfigSource, // Get config file path
282
+ } from '@gringow/gringow'
283
+ ```
284
+
285
+ ### Type Definitions
286
+
287
+ ```typescript
95
288
  type GringowTranslation = Record<string, string>
96
289
 
97
290
  type GringowCacheItem = {
@@ -108,22 +301,65 @@ type GringowResponse = {
108
301
  }
109
302
  ```
110
303
 
304
+ ## How It Works
305
+
306
+ 1. **Input Processing**: Template strings are flattened to plain text (preserving dynamic values)
307
+ 2. **Cache ID Generation**: Content-based hash created using `createCacheId()`
308
+ 3. **Cache Lookup**: Check `./gringow/gringow.json` for existing translation
309
+ 4. **LLM Query**: If not cached, request translation from configured provider
310
+ 5. **Response Parsing**: Parse provider response to `GringowCacheItem` format
311
+ 6. **Cache Storage**: Write to disk when `cache.write` is `true`
312
+
313
+ **Example cache structure:**
314
+
315
+ ```json
316
+ {
317
+ "grw_a1b2c3": {
318
+ "original": "Hello world",
319
+ "translation": {
320
+ "pt-BR": "Olá mundo",
321
+ "fr-CA": "Bonjour le monde"
322
+ }
323
+ }
324
+ }
325
+ ```
326
+
111
327
  ## Development
112
328
 
113
329
  ```bash
330
+ # Install dependencies
114
331
  pnpm install
115
- pnpm run build # builds the package
116
- pnpm run test # vitest suite
332
+
333
+ # Build the package
334
+ pnpm run build
335
+
336
+ # Run tests
337
+ pnpm run test
338
+
339
+ # Watch mode
340
+ pnpm run test:watch
117
341
  ```
118
342
 
343
+ ## Integrations
344
+
345
+ Gringow has official integrations for modern web frameworks:
346
+
347
+ - **[@gringow/cli](https://www.npmjs.com/package/@gringow/gringow-cli)** - Command-line interface for cache management and translations
348
+ - **[@gringow/gringow-vite](https://www.npmjs.com/package/@gringow/gringow-vite)** - Vite plugin for build-time translation extraction
349
+ - **[@gringow/gringow-react](https://www.npmjs.com/package/@gringow/gringow-react)** - React hooks and components
350
+ - **[@gringow/gringow-shadow](https://www.npmjs.com/package/@gringow/gringow-shadow)** - Web Component layer (vanilla JS)
351
+ - **[@gringow/gringow-nextjs](https://www.npmjs.com/package/@gringow/gringow-nextjs)** - Next.js plugin (experimental)
352
+
353
+ ## Related Resources
354
+
355
+ - [Documentation](https://gringow.dev)
356
+ - [GitHub Repository](https://github.com/rntgspr/gringow)
357
+ - [Examples](https://github.com/rntgspr/gringow/tree/main/example-gringow-vite)
358
+
119
359
  ## License
120
360
 
121
- MIT
361
+ MIT © [Renato Gaspar](https://github.com/rntgspr)
122
362
 
123
- ## Related Packages (npm)
363
+ ---
124
364
 
125
- - [@gringow/gringow-cli](https://www.npmjs.com/package/@gringow/gringow-cli) - Command-line interface
126
- - [@gringow/gringow-shadow](https://www.npmjs.com/package/@gringow/gringow-shadow) - Web Component layer powering the React bindings
127
- - [@gringow/gringow-react](https://www.npmjs.com/package/@gringow/gringow-react) - React bindings
128
- - [@gringow/gringow-vite](https://www.npmjs.com/package/@gringow/gringow-vite) - Vite plugin
129
- - [@gringow/gringow-nextjs](https://www.npmjs.com/package/@gringow/gringow-nextjs) - Experimental Next.js plugin
365
+ **Questions or Issues?** Open an issue on [GitHub](https://github.com/rntgspr/gringow/issues)
package/dist/config.d.mts CHANGED
@@ -26,10 +26,6 @@ declare function loadUserConfig(): Promise<GringowConfig>;
26
26
  * @returns The user configuration.
27
27
  */
28
28
  declare const awaitedConfig: Promise<{
29
- keys: {
30
- anthropicApiKey?: string | undefined;
31
- geminiApiKey?: string | undefined;
32
- };
33
29
  log: {
34
30
  level: "debug" | "info" | "warn" | "error" | "trace";
35
31
  };
@@ -40,14 +36,17 @@ declare const awaitedConfig: Promise<{
40
36
  write?: boolean | undefined;
41
37
  };
42
38
  sourceLanguage: string;
39
+ defaultLanguage: string;
43
40
  languages: string[];
44
41
  llm: {
45
- choice: "gemini" | "anthropic" | "huggingface";
42
+ provider: "anthropic" | "gemini" | "openai" | "groq" | "mistral" | "ollama" | "xai" | "deepseek" | "openrouter" | "cerebras" | "lmstudio" | "azure" | "meta";
46
43
  model: string | null;
47
- temperature?: number | undefined;
48
- sleep?: number | undefined;
49
44
  prePrompt?: string | undefined;
50
45
  postPrompt?: string | undefined;
46
+ apiKey?: string | undefined;
47
+ baseURL?: string | undefined;
48
+ temperature?: number | undefined;
49
+ sleep?: number | undefined;
51
50
  prePromptReplace?: string | undefined;
52
51
  postPromptReplace?: string | undefined;
53
52
  prePromptAppend?: string | undefined;
@@ -58,7 +57,7 @@ declare const awaitedConfig: Promise<{
58
57
  }>;
59
58
  declare function defaultPrePrompt(config: GringowConfig, extraInstructions?: string): string;
60
59
  declare function defaultPostPrompt(_config: GringowConfig): string;
61
- declare function prePrompt(config: GringowConfig, append?: string, replace?: string): string;
60
+ declare function prePrompt(config: GringowConfig, prepend?: string, replace?: string): string;
62
61
  declare function postPrompt(config: GringowConfig, prepend?: string, replace?: string): string;
63
62
 
64
63
  export { awaitedConfig, defaultPostPrompt, defaultPrePrompt, getConfigSource, isLocalConfigFound, loadUserConfig, postPrompt, prePrompt };
package/dist/config.mjs CHANGED
@@ -16,19 +16,34 @@ var defaultConfig = {
16
16
  prefix: "grw",
17
17
  write: true
18
18
  },
19
- keys: {},
20
19
  sourceLanguage: "en-US",
20
+ defaultLanguage: "pt-BR",
21
21
  languages: ["pt-BR", "fr-CA"],
22
22
  llm: {
23
- choice: "huggingface",
24
- model: "Xenova/nllb-200-distilled-600M",
23
+ provider: "openai",
24
+ apiKey: void 0,
25
+ model: "gpt-4o-mini",
25
26
  temperature: 1,
26
27
  sleep: 0
27
28
  },
28
29
  globby: "./src/**/*.{js,jsx,ts,tsx}"
29
30
  };
30
31
  var languageSchema = z.string().regex(/^[a-z]{2,3}(-[A-Z]{2})?$/);
31
- var llmOptionsSchema = z.enum(["gemini", "anthropic", "huggingface"]);
32
+ var llmProviderSchema = z.enum([
33
+ "anthropic",
34
+ "gemini",
35
+ "openai",
36
+ "groq",
37
+ "mistral",
38
+ "ollama",
39
+ "xai",
40
+ "deepseek",
41
+ "openrouter",
42
+ "cerebras",
43
+ "lmstudio",
44
+ "azure",
45
+ "meta"
46
+ ]);
32
47
  var configSchema = z.object({
33
48
  debug: z.boolean().optional(),
34
49
  log: z.object({
@@ -40,14 +55,13 @@ var configSchema = z.object({
40
55
  prefix: z.string(),
41
56
  write: z.boolean().optional()
42
57
  }),
43
- keys: z.object({
44
- anthropicApiKey: z.string().optional(),
45
- geminiApiKey: z.string().optional()
46
- }),
47
58
  sourceLanguage: languageSchema,
59
+ defaultLanguage: languageSchema,
48
60
  languages: z.array(languageSchema),
49
61
  llm: z.object({
50
- choice: llmOptionsSchema,
62
+ provider: llmProviderSchema,
63
+ apiKey: z.string().optional(),
64
+ baseURL: z.string().optional(),
51
65
  model: z.string().nullable(),
52
66
  temperature: z.number().optional(),
53
67
  sleep: z.number().optional(),
@@ -61,17 +75,15 @@ var configSchema = z.object({
61
75
  globby: z.string().regex(/^\.\/.*/).optional()
62
76
  }).refine(
63
77
  (data) => {
64
- if (data.llm.choice === "gemini" && !data.keys.geminiApiKey) {
65
- return false;
66
- }
67
- if (data.llm.choice === "anthropic" && !data.keys.anthropicApiKey) {
68
- return false;
78
+ const noApiKeyRequired = ["ollama", "lmstudio"];
79
+ if (noApiKeyRequired.includes(data.llm.provider)) {
80
+ return true;
69
81
  }
70
- return true;
82
+ return !!data.llm.apiKey;
71
83
  },
72
84
  {
73
- message: "The API key corresponding to the chosen LLM must be present.",
74
- path: ["keys"]
85
+ message: "The API key must be present in llm.apiKey for the chosen provider.",
86
+ path: ["llm", "apiKey"]
75
87
  }
76
88
  );
77
89
 
@@ -113,7 +125,7 @@ Your task is to translate a given text and output **only one valid JSON object**
113
125
 
114
126
  Follow these rules strictly:
115
127
 
116
- 1. The original text is written in English.
128
+ 1. The original text is written in English or Spanish.
117
129
  2. You will receive additional user parameters under the variable 'extraInstructions'. These may specify tone, persona, style, context, or any relevant translation guideline.
118
130
  - Examples: \u201Ctranslate as if you were a Shakespearean narrator\u201D or \u201Cuse a formal business tone suitable for a corporate presentation.\u201D
119
131
  - Apply these creatively but **without altering the meaning or punctuation** of the original text.
@@ -146,10 +158,10 @@ Translate the following text faithfully:
146
158
  function defaultPostPrompt(_config) {
147
159
  return "";
148
160
  }
149
- function prePrompt(config, append, replace) {
161
+ function prePrompt(config, prepend, replace) {
150
162
  return [
151
163
  // ...(append ? ['[SPECIFIC_INPUTS]', String(append), '[/SPECIFIC_INPUTS]'] : []),
152
- replace ? String(replace) : defaultPrePrompt(config, append)
164
+ replace ? String(replace) : defaultPrePrompt(config, prepend)
153
165
  ].join(" ").trim();
154
166
  }
155
167
  function postPrompt(config, prepend, replace) {
@@ -18133,19 +18133,34 @@ var defaultConfig = {
18133
18133
  prefix: "grw",
18134
18134
  write: true
18135
18135
  },
18136
- keys: {},
18137
18136
  sourceLanguage: "en-US",
18137
+ defaultLanguage: "pt-BR",
18138
18138
  languages: ["pt-BR", "fr-CA"],
18139
18139
  llm: {
18140
- choice: "huggingface",
18141
- model: "Xenova/nllb-200-distilled-600M",
18140
+ provider: "openai",
18141
+ apiKey: void 0,
18142
+ model: "gpt-4o-mini",
18142
18143
  temperature: 1,
18143
18144
  sleep: 0
18144
18145
  },
18145
18146
  globby: "./src/**/*.{js,jsx,ts,tsx}"
18146
18147
  };
18147
18148
  var languageSchema = z.string().regex(/^[a-z]{2,3}(-[A-Z]{2})?$/);
18148
- var llmOptionsSchema = z.enum(["gemini", "anthropic", "huggingface"]);
18149
+ var llmProviderSchema = z.enum([
18150
+ "anthropic",
18151
+ "gemini",
18152
+ "openai",
18153
+ "groq",
18154
+ "mistral",
18155
+ "ollama",
18156
+ "xai",
18157
+ "deepseek",
18158
+ "openrouter",
18159
+ "cerebras",
18160
+ "lmstudio",
18161
+ "azure",
18162
+ "meta"
18163
+ ]);
18149
18164
  var configSchema = z.object({
18150
18165
  debug: z.boolean().optional(),
18151
18166
  log: z.object({
@@ -18157,14 +18172,13 @@ var configSchema = z.object({
18157
18172
  prefix: z.string(),
18158
18173
  write: z.boolean().optional()
18159
18174
  }),
18160
- keys: z.object({
18161
- anthropicApiKey: z.string().optional(),
18162
- geminiApiKey: z.string().optional()
18163
- }),
18164
18175
  sourceLanguage: languageSchema,
18176
+ defaultLanguage: languageSchema,
18165
18177
  languages: z.array(languageSchema),
18166
18178
  llm: z.object({
18167
- choice: llmOptionsSchema,
18179
+ provider: llmProviderSchema,
18180
+ apiKey: z.string().optional(),
18181
+ baseURL: z.string().optional(),
18168
18182
  model: z.string().nullable(),
18169
18183
  temperature: z.number().optional(),
18170
18184
  sleep: z.number().optional(),
@@ -18178,17 +18192,15 @@ var configSchema = z.object({
18178
18192
  globby: z.string().regex(/^\.\/.*/).optional()
18179
18193
  }).refine(
18180
18194
  (data) => {
18181
- if (data.llm.choice === "gemini" && !data.keys.geminiApiKey) {
18182
- return false;
18183
- }
18184
- if (data.llm.choice === "anthropic" && !data.keys.anthropicApiKey) {
18185
- return false;
18195
+ const noApiKeyRequired = ["ollama", "lmstudio"];
18196
+ if (noApiKeyRequired.includes(data.llm.provider)) {
18197
+ return true;
18186
18198
  }
18187
- return true;
18199
+ return !!data.llm.apiKey;
18188
18200
  },
18189
18201
  {
18190
- message: "The API key corresponding to the chosen LLM must be present.",
18191
- path: ["keys"]
18202
+ message: "The API key must be present in llm.apiKey for the chosen provider.",
18203
+ path: ["llm", "apiKey"]
18192
18204
  }
18193
18205
  );
18194
18206
 
@@ -18224,7 +18236,7 @@ Your task is to translate a given text and output **only one valid JSON object**
18224
18236
 
18225
18237
  Follow these rules strictly:
18226
18238
 
18227
- 1. The original text is written in English.
18239
+ 1. The original text is written in English or Spanish.
18228
18240
  2. You will receive additional user parameters under the variable 'extraInstructions'. These may specify tone, persona, style, context, or any relevant translation guideline.
18229
18241
  - Examples: \u201Ctranslate as if you were a Shakespearean narrator\u201D or \u201Cuse a formal business tone suitable for a corporate presentation.\u201D
18230
18242
  - Apply these creatively but **without altering the meaning or punctuation** of the original text.
@@ -18257,10 +18269,10 @@ Translate the following text faithfully:
18257
18269
  function defaultPostPrompt(_config) {
18258
18270
  return "";
18259
18271
  }
18260
- function prePrompt(config2, append, replace) {
18272
+ function prePrompt(config2, prepend, replace) {
18261
18273
  return [
18262
18274
  // ...(append ? ['[SPECIFIC_INPUTS]', String(append), '[/SPECIFIC_INPUTS]'] : []),
18263
- replace ? String(replace) : defaultPrePrompt(config2, append)
18275
+ replace ? String(replace) : defaultPrePrompt(config2, prepend)
18264
18276
  ].join(" ").trim();
18265
18277
  }
18266
18278
  function postPrompt(config2, prepend, replace) {
@@ -18279,9 +18291,11 @@ describe("config", () => {
18279
18291
  languages: ["pt-BR", "fr-CA", "es-ES"]
18280
18292
  };
18281
18293
  const result2 = defaultPrePrompt(config2);
18282
- globalExpect(result2).toContain("You are a translation generator.");
18283
- globalExpect(result2).toContain("Your task is to output **only one valid JSON object**");
18284
- globalExpect(result2).toContain("pt-BR, fr-CA, es-ES");
18294
+ globalExpect(result2).toContain("You are a ultimate translation generator server api.");
18295
+ globalExpect(result2).toContain("Your task is to translate a given text and output **only one valid JSON object**");
18296
+ globalExpect(result2).toContain("pt-BR");
18297
+ globalExpect(result2).toContain("fr-CA");
18298
+ globalExpect(result2).toContain("es-ES");
18285
18299
  globalExpect(result2).toContain('"original": "<original input text>"');
18286
18300
  globalExpect(result2).toContain('"translation": {');
18287
18301
  });
@@ -18319,7 +18333,7 @@ describe("config", () => {
18319
18333
  };
18320
18334
  const result2 = prePrompt(config2, "Additional instructions");
18321
18335
  globalExpect(result2).toContain("extraInstructions: Additional instructions");
18322
- globalExpect(result2).toContain("You are a translation generator.");
18336
+ globalExpect(result2).toContain("You are a ultimate translation generator server api.");
18323
18337
  });
18324
18338
  it("should use prePromptReplace and prePromptAppend together", () => {
18325
18339
  const config2 = {
@@ -18333,7 +18347,7 @@ describe("config", () => {
18333
18347
  ...defaultConfig
18334
18348
  };
18335
18349
  const result2 = prePrompt(config2);
18336
- globalExpect(result2).toContain("You are a translation generator.");
18350
+ globalExpect(result2).toContain("You are a ultimate translation generator server api.");
18337
18351
  globalExpect(result2).toContain("Translate the following text faithfully:");
18338
18352
  });
18339
18353
  });
@@ -10,12 +10,13 @@ var defaultConfig = {
10
10
  prefix: "grw",
11
11
  write: true
12
12
  },
13
- keys: {},
14
13
  sourceLanguage: "en-US",
14
+ defaultLanguage: "pt-BR",
15
15
  languages: ["pt-BR", "fr-CA"],
16
16
  llm: {
17
- choice: "huggingface",
18
- model: "Xenova/nllb-200-distilled-600M",
17
+ provider: "openai",
18
+ apiKey: void 0,
19
+ model: "gpt-4o-mini",
19
20
  temperature: 1,
20
21
  sleep: 0
21
22
  },