# @gringow/gringow

[![npm version](https://img.shields.io/npm/v/@gringow/gringow)](https://www.npmjs.com/package/@gringow/gringow)
[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)

AI-powered translation library for template strings using multiple LLM providers via `multi-llm-ts`. Gringow provides smart caching, deterministic content hashing, and seamless integration for modern JavaScript/TypeScript projects.

## Features

- 🌍 **Multi-language translation** using LLM providers
- 🏷️ **Tagged template literal** syntax for inline translations
- 💾 **Smart caching** with content-based hashing
- 🔌 **Multiple LLM providers** (OpenAI default, Anthropic, Gemini, Groq, Mistral, Ollama, and more)
- ⚙️ **Config-driven behavior** through `gringow.config.*`
- 📦 **Optimized builds** via Vite/Next.js plugins

## Installation

```bash
npm install @gringow/gringow
# or
pnpm add @gringow/gringow
# or
yarn add @gringow/gringow
```

## Quick Start

```typescript
import Gringow from '@gringow/gringow'

// Simple string translation
const { cacheId, translation } = await Gringow`Hello world`
console.log(translation.translation)
// => { "pt-BR": "Olá mundo", "fr-CA": "Bonjour le monde" }

// Template string with dynamic values
const name = 'John'
const { translation: result } = await Gringow`Welcome, ${name}!`
console.log(result.translation)
// => { "pt-BR": "Bem-vindo, John!", "fr-CA": "Bienvenue, John!" }
```

## Usage Examples

### Basic Translation

```typescript
import Gringow from '@gringow/gringow'

// Translate a static string
const { translation } = await Gringow`Hello world`
console.log(translation.translation['pt-BR']) // "Olá mundo"
```

### Dynamic Content

```typescript
// Template literals are flattened before hashing - dynamic values preserved
const user = { name: 'Alice', role: 'admin' }
const { translation } = await Gringow`User ${user.name} has ${user.role} privileges`

console.log(translation.translation['pt-BR'])
// => "Usuário Alice tem privilégios de admin"
```

### Cache Management

```typescript
import Gringow, { rebuild, checkCache } from '@gringow/gringow'

const { cacheId } = await Gringow`Hello world`

// Check if translation exists in cache
const cached = await checkCache(cacheId)
console.log(cached) // GringowCacheItem or undefined

// Force re-translation by rebuilding cache entry
const refreshed = await rebuild(cacheId)
console.log(refreshed.translation.translation)
```

### Browser Usage

For client-side interpolation without Node.js dependencies:

```typescript
import { interpolateTemplate } from '@gringow/gringow/browser'

const template = 'Hello ${name}, you have ${count} messages'
const result = interpolateTemplate(template, ['Alice', 5])
console.log(result) // "Hello Alice, you have 5 messages"
```

## Configuration

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`.

### Default Configuration

```js
// gringow.config.js
export default {
  debug: false,
  log: { level: 'info' },
  cache: {
    dir: './gringow',
    file: 'gringow.json',
    prefix: 'grw',
    write: true,
  },
  sourceLanguage: 'en-US',
  defaultLanguage: 'pt-BR',
  languages: ['pt-BR', 'fr-CA'],
  llm: {
    provider: 'openai',
    apiKey: process.env.OPENAI_API_KEY,
    model: 'gpt-4o-mini',
    temperature: 1.0,
    sleep: 0,
  },
  globby: './src/**/*.{js,jsx,ts,tsx}',
}
```

### Migration from `llm.choice`

`llm.choice` was removed in 0.6.0. Rename the field to `llm.provider` in every Gringow configuration file.

```diff
llm: {
-  choice: 'openai',
+  provider: 'openai',
}
```

### Example: Using Gemini

```js
// gringow.config.js
export default {
  llm: {
    provider: 'gemini',
    apiKey: process.env.GEMINI_API_KEY,
    model: 'gemini-2.0-flash',
    prePromptAppend: 'Please respond in a friendly tone.',
  },
  languages: ['es-ES', 'de-DE', 'ja-JP'],
}
```

### Example: Using Anthropic

```js
// gringow.config.js
export default {
  llm: {
    provider: 'anthropic',
    apiKey: process.env.ANTHROPIC_API_KEY,
    model: 'claude-3-5-sonnet-20241022',
    temperature: 0.7,
  },
}
```

### Prompt Customization

Fine-tune LLM behavior with prompt options:

```js
export default {
  llm: {
    provider: 'openai',
    apiKey: process.env.OPENAI_API_KEY,
    prePrompt: 'Translate the following text:', // Default prompt prefix
    postPrompt: 'Ensure translations are natural.', // Additional context
    prePromptAppend: 'Use formal language.', // Appended to pre-prompt
    postPromptPrepend: 'Maintain original formatting.', // Prepended to post-prompt
    prePromptReplace: 'Custom instruction here', // Replaces entire pre-prompt
  },
}
```

## LLM Providers

### OpenAI (Default)

Uses OpenAI through `multi-llm-ts`. **Requires API key.**

```js
// gringow.config.js
export default {
  llm: {
    provider: 'openai',
    apiKey: process.env.OPENAI_API_KEY,
    model: 'gpt-4o-mini',
  },
}
```

**Pros**: Broad model availability, simple default setup  
**Cons**: API costs, requires internet

### Anthropic

Uses Claude models via Anthropic API. **Requires API key.**

```js
// gringow.config.js
export default {
  llm: {
    provider: 'anthropic',
    apiKey: process.env.ANTHROPIC_API_KEY,
    model: 'claude-3-5-sonnet-20241022',
  },
}
```

**Pros**: High-quality translations, fast  
**Cons**: API costs, requires internet

### Gemini

Uses Google's Gemini models. **Requires API key.**

```js
// gringow.config.js
export default {
  llm: {
    provider: 'gemini',
    apiKey: process.env.GEMINI_API_KEY,
    model: 'gemini-2.0-flash',
  },
}
```

**Pros**: Fast, cost-effective  
**Cons**: API costs, requires internet

## API Reference

### Core Functions

#### `Gringow(strings, ...values): Promise<GringowResponse>`

Main translation function. Accepts tagged template literals or plain strings.

```typescript
const result = await Gringow`Hello ${name}`
```

**Returns**: `Promise<GringowResponse>` with `{ cacheId, translation }`

#### `rebuild(cacheId: string): Promise<GringowResponse>`

Re-translates a cached entry using the current LLM configuration.

```typescript
const refreshed = await rebuild('grw_abc123')
```

### Cache Helpers

```typescript
import {
  checkCache,      // Check if cacheId exists
  getCache,        // Get entire cache object
  getOrCreateCache,// Get cache or create empty one
  writeCacheToDisk,// Manually write cache entry
  deleteCacheItem, // Remove cache entry
  clearCache,      // Clear all cache entries
} from '@gringow/gringow'
```

### Utilities

```typescript
import {
  createCacheId,         // Generate cache ID from string
  flatTemplateString,    // Flatten template literal to string
  awaitedConfig,         // Access resolved configuration
  isLocalConfigFound,    // Check if local config exists
  getConfigSource,       // Get config file path
} from '@gringow/gringow'
```

```typescript
import { interpolateTemplate } from '@gringow/gringow/browser'
```

### Type Definitions

```typescript
type GringowTranslation = Record<string, string>

type GringowCacheItem = {
  original: string
  translation: GringowTranslation
  append?: string
  prepend?: string
  rebuild?: boolean
}

type GringowResponse = {
  cacheId: string
  translation: GringowCacheItem
}
```

## How It Works

1. **Input Processing**: Template strings are flattened to plain text (preserving dynamic values)
2. **Cache ID Generation**: Content-based hash created using `createCacheId()`
3. **Cache Lookup**: Check `./gringow/gringow.json` for existing translation
4. **LLM Query**: If not cached, request translation from configured provider
5. **Response Parsing**: Parse provider response to `GringowCacheItem` format
6. **Cache Storage**: Write to disk when `cache.write` is `true`

**Example cache structure:**

```json
{
  "grw_a1b2c3": {
    "original": "Hello world",
    "translation": {
      "pt-BR": "Olá mundo",
      "fr-CA": "Bonjour le monde"
    }
  }
}
```

## Development

```bash
# Install dependencies
pnpm install

# Build the package
pnpm run build

# Run tests
pnpm run test

# Watch mode
pnpm run test:watch
```

## Related Packages

Gringow provides a complete ecosystem for AI-powered translation:

- **[@gringow/gringow](https://www.npmjs.com/package/@gringow/gringow)** - Core translation library
- **[@gringow/gringow-vite](https://www.npmjs.com/package/@gringow/gringow-vite)** - Vite plugin for build-time extraction
- **[@gringow/gringow-react](https://www.npmjs.com/package/@gringow/gringow-react)** - React hooks and components
- **[@gringow/gringow-shadow](https://www.npmjs.com/package/@gringow/gringow-shadow)** - Web Component layer
- **[@gringow/gringow-cli](https://www.npmjs.com/package/@gringow/gringow-cli)** - CLI tool
- **[@gringow/gringow-nextjs](https://www.npmjs.com/package/@gringow/gringow-nextjs)** - Next.js plugin (experimental)

## Related Resources

- [Documentation](https://gringow.dev)
- [GitHub Repository](https://github.com/rntgspr/gringow)
- [Examples](https://github.com/rntgspr/gringow/tree/main/example-gringow-vite)

## License

MIT © [Renato Gaspar](https://github.com/rntgspr)

---

**Questions or Issues?** Open an issue on [GitHub](https://github.com/rntgspr/gringow/issues)
