@intlayer/ai 7.3.0-canary.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 +275 -0
- package/dist/assets/auditDictionaryMetadata/PROMPT.md +73 -0
- package/dist/assets/translateJSON/PROMPT.md +45 -0
- package/dist/cjs/_virtual/_utils_asset.cjs +97 -0
- package/dist/cjs/aiSdk.cjs +93 -0
- package/dist/cjs/aiSdk.cjs.map +1 -0
- package/dist/cjs/auditDictionaryMetadata/index.cjs +37 -0
- package/dist/cjs/auditDictionaryMetadata/index.cjs.map +1 -0
- package/dist/cjs/customQuery.cjs +24 -0
- package/dist/cjs/customQuery.cjs.map +1 -0
- package/dist/cjs/index.cjs +25 -0
- package/dist/cjs/translateJSON/index.cjs +67 -0
- package/dist/cjs/translateJSON/index.cjs.map +1 -0
- package/dist/cjs/utils/extractJSON.cjs +61 -0
- package/dist/cjs/utils/extractJSON.cjs.map +1 -0
- package/dist/esm/_virtual/_utils_asset.mjs +97 -0
- package/dist/esm/aiSdk.mjs +92 -0
- package/dist/esm/aiSdk.mjs.map +1 -0
- package/dist/esm/auditDictionaryMetadata/index.mjs +36 -0
- package/dist/esm/auditDictionaryMetadata/index.mjs.map +1 -0
- package/dist/esm/customQuery.mjs +23 -0
- package/dist/esm/customQuery.mjs.map +1 -0
- package/dist/esm/index.mjs +8 -0
- package/dist/esm/translateJSON/index.mjs +66 -0
- package/dist/esm/translateJSON/index.mjs.map +1 -0
- package/dist/esm/utils/extractJSON.mjs +60 -0
- package/dist/esm/utils/extractJSON.mjs.map +1 -0
- package/dist/types/aiSdk.d.ts +61 -0
- package/dist/types/aiSdk.d.ts.map +1 -0
- package/dist/types/auditDictionaryMetadata/index.d.ts +36 -0
- package/dist/types/auditDictionaryMetadata/index.d.ts.map +1 -0
- package/dist/types/customQuery.d.ts +24 -0
- package/dist/types/customQuery.d.ts.map +1 -0
- package/dist/types/index.d.ts +7 -0
- package/dist/types/translateJSON/index.d.ts +43 -0
- package/dist/types/translateJSON/index.d.ts.map +1 -0
- package/dist/types/utils/extractJSON.d.ts +36 -0
- package/dist/types/utils/extractJSON.d.ts.map +1 -0
- package/package.json +102 -0
package/README.md
ADDED
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<a href="https://intlayer.org" rel="">
|
|
3
|
+
<img src="https://raw.githubusercontent.com/aymericzip/intlayer/main/docs/assets/cover.png" width="60%" alt="Intlayer Logo" />
|
|
4
|
+
</a>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<h1 align="center">
|
|
8
|
+
<strong> Intlayer : an Open-source, per-component i18n toolkit with AI-powered translation & CMS.</strong>
|
|
9
|
+
</h1>
|
|
10
|
+
|
|
11
|
+
<br />
|
|
12
|
+
|
|
13
|
+
<p align="center">
|
|
14
|
+
<a href="https://intlayer.org/doc/concept/content" rel="">Docs</a> •
|
|
15
|
+
<a href="https://intlayer.org/doc/environment/nextjs" rel="">Next.js</a> •
|
|
16
|
+
<a href="https://intlayer.org/doc/environment/vite-and-react" rel="">React + Vite</a> •
|
|
17
|
+
<a href="https://intlayer.org/doc/concept/cms" rel="">CMS</a> •
|
|
18
|
+
<a href="https://discord.gg/7uxamYVeCk" rel="noopener noreferrer nofollow">Discord</a>
|
|
19
|
+
</p>
|
|
20
|
+
<p align="center" style="margin-top:15px;">
|
|
21
|
+
<a href="https://www.npmjs.com/package/intlayer" target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/npm/v/intlayer?style=for-the-badge&labelColor=FFFFFF&color=000000&logoColor=FFFFFF" alt="npm version" height="24"/></a>
|
|
22
|
+
<a href="https://github.com/aymericzip/intlayer/stargazers" target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/github/stars/aymericzip/intlayer?style=for-the-badge&labelColor=000000&color=FFFFFF&logo=github&logoColor=FFD700" alt="GitHub Stars" height="24"/></a>
|
|
23
|
+
<a href="https://www.npmjs.org/package/intlayer" target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/npm/dm/intlayer?style=for-the-badge&labelColor=000000&color=FFFFFF&logoColor=000000&cacheSeconds=86400" alt="monthly downloads" height="24"/></a>
|
|
24
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/LICENSE" target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/github/license/aymericzip/intlayer?style=for-the-badge&labelColor=000000&color=FFFFFF&logoColor=000000&cacheSeconds=86400" alt="license"/></a>
|
|
25
|
+
<a href="https://github.com/aymericzip/intlayer/commits/main" target="_blank" rel="noopener noreferrer nofollow"><img src="https://img.shields.io/github/last-commit/aymericzip/intlayer?style=for-the-badge&labelColor=000000&color=FFFFFF&logoColor=000000&cacheSeconds=86400" alt="last commit"/>
|
|
26
|
+
</a>
|
|
27
|
+
</p>
|
|
28
|
+
|
|
29
|
+

|
|
30
|
+
|
|
31
|
+
<a href="https://intlayer.org/doc/concept/content" rel="">
|
|
32
|
+
<img src="https://img.shields.io/badge/Get_Started-FFFFFF?style=for-the-badge&logo=rocket&logoColor=black" />
|
|
33
|
+
</a>
|
|
34
|
+
|
|
35
|
+
## What is Intlayer?
|
|
36
|
+
|
|
37
|
+
Most i18n libraries are either too complex, too rigid, or not built for modern frameworks.
|
|
38
|
+
|
|
39
|
+
Intlayer is a **modern i18n solution** for web and mobile apps.
|
|
40
|
+
It’s framework-agnostic, **AI-powered**, and includes a free **CMS & visual editor**.
|
|
41
|
+
|
|
42
|
+
With **per-locale content files**, **TypeScript autocompletion**, **tree-shakable dictionaries**, and **CI/CD integration**, Intlayer makes internationalization **faster, cleaner, and smarter**.
|
|
43
|
+
|
|
44
|
+
## Keys benefits of Intlayer:
|
|
45
|
+
|
|
46
|
+
| Feature | Description |
|
|
47
|
+
| --------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
48
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/frameworks.png?raw=true" alt="Feature" width="700"> | **Cross-Frameworks Support**<br><br>Intlayer is compatible with all major frameworks and libraries, including Next.js, React, Vite, Vue.js, Nuxt, Preact, Express, and more. |
|
|
49
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/javascript_content_management.png?raw=true" alt="Feature" width="700"> | **JavaScript-Powered Content Management**<br><br>Harness the flexibility of JavaScript to define and manage your content efficiently. <br><br> - [Content declaration](https://intlayer.org/doc/concept/content) |
|
|
50
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/per_locale_content_declaration_file.png?raw=true" alt="Feature" width="700"> | **Per-Locale Content Declaration File**<br><br>Speed up your development by declaring your content once, before auto generation.<br><br> - [Per-Locale Content Declaration File](https://intlayer.org/doc/concept/per-locale-file) |
|
|
51
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/autocompletion.png?raw=true" alt="Feature" width="700"> | **Type-Safe Environment**<br><br>Leverage TypeScript to ensure your content definitions and code are error-free, while also benefiting from IDE autocompletion.<br><br> - [TypeScript configuration](https://intlayer.org/doc/environment/vite-and-react#configure-typescript) |
|
|
52
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/config_file.png?raw=true" alt="Feature" width="700"> | **Simplified Setup**<br><br>Get up and running quickly with minimal configuration. Adjust settings for internationalization, routing, AI, build, and content handling with ease. <br><br> - [Explore Next.js integration](https://intlayer.org/doc/environment/nextjs) |
|
|
53
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/content_retrieval.png?raw=true" alt="Feature" width="700"> | **Simplified Content Retrieval**<br><br>No need to call your `t` function for each piece of content. Retrieve all your content directly using a single hook.<br><br> - [React integration](https://intlayer.org/doc/environment/create-react-app) |
|
|
54
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/server_component.png?raw=true" alt="Feature" width="700"> | **Consistent Server Component Implementation**<br><br>Perfectly suited for Next.js server components, use the same implementation for both client and server components, no need to pass your `t` function across each server component. <br><br> - [Server Components](https://intlayer.org/doc/environment/nextjs#step-7-utilize-content-in-your-code) |
|
|
55
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/file_tree.png?raw=true" alt="Feature" width="700"> | **Organized Codebase**<br><br>Keep your codebase more organized: 1 component = 1 dictionary in the same folder. Translations close to their respective components, enhance maintainability and clarity. <br><br> - [How Intlayer works](https://intlayer.org/doc/concept/how-works-intlayer) |
|
|
56
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/url_routing.png?raw=true" alt="Feature" width="700"> | **Enhanced Routing**<br><br>Full support of app routing, adapting seamlessly to complex application structures, for Next.js, React, Vite, Vue.js, etc.<br><br> - [Explore Next.js integration](https://intlayer.org/doc/environment/nextjs) |
|
|
57
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/markdown.png?raw=true" alt="Feature" width="700"> | **Markdown Support**<br><br>Import and interpret, locale files and remote Markdown for multilingual content like privacy policies, documentation, etc. Interpret and make Markdown metadata accessible in your code.<br><br> - [Content files](https://intlayer.org/doc/concept/content/file) |
|
|
58
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/visual_editor.png?raw=true" alt="Feature" width="700"> | **Free Visual Editor & CMS**<br><br>A free visual editor and CMS are available for content writers, removing the need for a localization platform. Keep your content synchronized using Git, or externalize it totally or partially with the CMS.<br><br> - [Intlayer Editor](https://intlayer.org/doc/concept/editor) <br> - [Intlayer CMS](https://intlayer.org/doc/concept/cms) |
|
|
59
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/bundle.png?raw=true" alt="Feature" width="700"> | **Tree-shakable Content**<br><br>Tree-shakable content, reducing the size of the final bundle. Loads content per component, excluding any unused content from your bundle. Supports lazy loading to enhance app loading efficiency. <br><br> - [App build optimization](https://intlayer.org/doc/concept/how-works-intlayer#app-build-optimization) |
|
|
60
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/static_rendering.png?raw=true" alt="Feature" width="700"> | **Static Rendering**<br><br>Doesn't block Static Rendering. <br><br> - [Next.js integration](https://intlayer.org/doc/environment/nextjs) |
|
|
61
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/AI_translation.png?raw=true" alt="Feature" width="700"> | **AI-Powered Translation**<br><br>Transform your website into 231 languages with just one click using Intlayer's advanced AI-powered translation tools using your own AI provider / API key. <br><br> - [CI/CD integration](https://intlayer.org/doc/concept/ci-cd) <br> - [Intlayer CLI](https://intlayer.org/doc/concept/cli) <br> - [Auto fill](https://intlayer.org/doc/concept/auto-fill) |
|
|
62
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/mcp.png?raw=true" alt="Feature" width="700"> | **MCP Server Integration**<br><br>Provides an MCP (Model Context Protocol) server for IDE automation, enabling seamless content management and i18n workflows directly within your development environment. <br><br> - [MCP Server](https://github.com/aymericzip/intlayer/blob/main/docs/docs/en/mcp_server.md) |
|
|
63
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/vscode_extension.png?raw=true" alt="Feature" width="700"> | **VSCode Extension**<br><br>Intlayer provides a VSCode extension to help you manage your content and translations, building your dictionaries, translating your content, and more. <br><br> - [VSCode Extension](https://intlayer.org/doc/vs-code-extension) |
|
|
64
|
+
| <img src="https://github.com/aymericzip/intlayer/blob/main/docs/assets/interoperability.png?raw=true" alt="Feature" width="700"> | **Interoperability**<br><br>Allow interoperability with react-i18next, next-i18next, next-intl, and react-intl. <br><br> - [Intlayer and react-intl](https://intlayer.org/blog/intlayer-with-react-intl) <br> - [Intlayer and next-intl](https://intlayer.org/blog/intlayer-with-next-intl) <br> - [Intlayer and next-i18next](https://intlayer.org/blog/intlayer-with-next-i18next) |
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 📦 Installation
|
|
69
|
+
|
|
70
|
+
Start your journey with Intlayer today and experience a smoother, more powerful approach to internationalization.
|
|
71
|
+
|
|
72
|
+
<a href="https://intlayer.org/doc/concept/content" rel="">
|
|
73
|
+
<img src="https://img.shields.io/badge/Get_Started-FFFFFF?style=for-the-badge&logo=rocket&logoColor=black" />
|
|
74
|
+
</a>
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
npm install intlayer react-intlayer
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
⚡ Quick Start (Next.js)
|
|
81
|
+
|
|
82
|
+
```ts
|
|
83
|
+
// intlayer.config.ts
|
|
84
|
+
import { Locales, type IntlayerConfig } from "intlayer";
|
|
85
|
+
|
|
86
|
+
const config: IntlayerConfig = {
|
|
87
|
+
internationalization: {
|
|
88
|
+
locales: [Locales.ENGLISH, Locales.FRENCH, Locales.SPANISH],
|
|
89
|
+
defaultLocale: Locales.ENGLISH,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
export default config;
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
// app/home.content.ts
|
|
98
|
+
import { t, type Dictionary } from "intlayer";
|
|
99
|
+
|
|
100
|
+
const content = {
|
|
101
|
+
key: "home",
|
|
102
|
+
content: {
|
|
103
|
+
title: t({
|
|
104
|
+
en: "Home",
|
|
105
|
+
fr: "Accueil",
|
|
106
|
+
es: "Inicio",
|
|
107
|
+
}),
|
|
108
|
+
},
|
|
109
|
+
} satisfies Dictionary;
|
|
110
|
+
|
|
111
|
+
export default content;
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
```tsx
|
|
115
|
+
// app/page.tsx
|
|
116
|
+
import { useIntlayer } from "react-intlayer";
|
|
117
|
+
|
|
118
|
+
const HomePage = () => {
|
|
119
|
+
const { title } = useIntlayer("home");
|
|
120
|
+
|
|
121
|
+
return <h1>{title}</h1>;
|
|
122
|
+
};
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
<a href="https://intlayer.org/doc/environment/nextjs"> Get the full guide → </a>
|
|
126
|
+
|
|
127
|
+
## 🎥 Live tutorial on YouTube
|
|
128
|
+
|
|
129
|
+
[](https://youtu.be/e_PPG7PTqGU?si=GyU_KpVhr61razRw)
|
|
130
|
+
|
|
131
|
+
<a href="https://intlayer.org/doc/concept/content" rel="">
|
|
132
|
+
<img src="https://img.shields.io/badge/Get_Started-FFFFFF?style=for-the-badge&logo=rocket&logoColor=black" />
|
|
133
|
+
</a>
|
|
134
|
+
|
|
135
|
+
## Table of Contents
|
|
136
|
+
|
|
137
|
+
Explore our comprehensive documentation to get started with Intlayer and learn how to integrate it into your projects.
|
|
138
|
+
|
|
139
|
+
<details open>
|
|
140
|
+
<summary style="font-size:16px; font-weight:bold;">📘 Get Started</summary>
|
|
141
|
+
<ul>
|
|
142
|
+
<li><a href="https://intlayer.org/doc/why" rel=''>Why Intlayer?</a></li>
|
|
143
|
+
<li><a href="https://intlayer.org/doc" rel=''>Introduction</a></li>
|
|
144
|
+
</ul>
|
|
145
|
+
</details>
|
|
146
|
+
|
|
147
|
+
<details>
|
|
148
|
+
<summary style="font-size:16px; font-weight:bold;">⚙️ Concept</summary>
|
|
149
|
+
<ul>
|
|
150
|
+
<li><a href="https://intlayer.org/doc/concept/how-works-intlayer" rel=''>How Intlayer Works</a></li>
|
|
151
|
+
<li><a href="https://intlayer.org/doc/concept/configuration" rel=''>Configuration</a></li>
|
|
152
|
+
<li><a href="https://intlayer.org/doc/concept/cli" rel=''>Intlayer CLI</a></li>
|
|
153
|
+
<li><a href="https://intlayer.org/doc/concept/editor" rel=''>Intlayer Editor</a></li>
|
|
154
|
+
<li><a href="https://intlayer.org/doc/concept/cms" rel=''>Intlayer CMS</a></li>
|
|
155
|
+
<li><a href="https://intlayer.org/doc/concept/content" rel=''>Dictionary</a>
|
|
156
|
+
<ul>
|
|
157
|
+
<li><a href="https://intlayer.org/doc/concept/content/per-locale-file" rel=''>Per-Locale Content Declaration File</a></li>
|
|
158
|
+
<li><a href="https://intlayer.org/doc/concept/content/translation" rel=''>Translation</a></li>
|
|
159
|
+
<li><a href="https://intlayer.org/doc/concept/content/enumeration" rel=''>Enumeration</a></li>
|
|
160
|
+
<li><a href="https://intlayer.org/doc/concept/content/condition" rel=''>Condition</a></li>
|
|
161
|
+
<li><a href="https://intlayer.org/doc/concept/content/nesting" rel=''>Nesting</a></li>
|
|
162
|
+
<li><a href="https://intlayer.org/doc/concept/content/markdown" rel=''>Markdown</a></li>
|
|
163
|
+
<li><a href="https://intlayer.org/doc/concept/content/function-fetching" rel=''>Function Fetching</a></li>
|
|
164
|
+
<li><a href="https://intlayer.org/doc/concept/content/insertion" rel=''>Insertion</a></li>
|
|
165
|
+
<li><a href="https://intlayer.org/doc/concept/content/file" rel=''>File</a></li>
|
|
166
|
+
</ul>
|
|
167
|
+
</li>
|
|
168
|
+
</ul>
|
|
169
|
+
</details>
|
|
170
|
+
|
|
171
|
+
<details open>
|
|
172
|
+
<summary style="font-size:16px; font-weight:bold;">🌐 Environment</summary>
|
|
173
|
+
<ul>
|
|
174
|
+
<li><a href="https://intlayer.org/doc/environment/nextjs" rel=''>Intlayer with Next.js 16</a>
|
|
175
|
+
<ul>
|
|
176
|
+
<li><a href="https://intlayer.org/doc/environment/nextjs/15" rel=''>Next.js 15</a></li>
|
|
177
|
+
<li><a href="https://intlayer.org/doc/environment/nextjs/14" rel=''>Next.js 14 (App Router)</a></li>
|
|
178
|
+
<li><a href="https://intlayer.org/doc/environment/nextjs/next-with-Page-Router" rel=''>Next.js Page Router</a></li>
|
|
179
|
+
</ul>
|
|
180
|
+
</li>
|
|
181
|
+
<li><a href="https://intlayer.org/doc/environment/create-react-app" rel=''>React CRA</a></li>
|
|
182
|
+
<li><a href="https://intlayer.org/doc/environment/vite-and-react" rel=''>Vite + React</a>
|
|
183
|
+
<ul>
|
|
184
|
+
<li><a href="https://intlayer.org/doc/environment/vite-and-react/react-router-v7" rel=''>React-router-v7</a></li>
|
|
185
|
+
<li><a href="https://intlayer.org/doc/environment/vite-and-react/tanstack-start" rel=''>Tanstack start</a></li>
|
|
186
|
+
</ul>
|
|
187
|
+
</li>
|
|
188
|
+
<li><a href="https://intlayer.org/doc/environment/react-native-and-expo" rel=''>React Native</a></li>
|
|
189
|
+
<li><a href="https://intlayer.org/doc/environment/lynx-and-react" rel=''>Lynx + React</a></li>
|
|
190
|
+
<li><a href="https://intlayer.org/doc/environment/vite-and-svelte" rel=''>Vite + Svelte</a></li>
|
|
191
|
+
<li><a href="https://intlayer.org/doc/environment/sveltekit" rel=''>SvelteKit</a></li>
|
|
192
|
+
<li><a href="https://intlayer.org/doc/environment/vite-and-preact" rel=''>Vite + Preact</a></li>
|
|
193
|
+
<li><a href="https://intlayer.org/doc/environment/vite-and-vue" rel=''>Vite + Vue</a></li>
|
|
194
|
+
<li><a href="https://intlayer.org/doc/environment/vite-and-nuxt" rel=''>Vite + Nuxt</a></li>
|
|
195
|
+
<li><a href="https://intlayer.org/doc/environment/vite-and-solid" rel=''>Vite + Solid</a></li>
|
|
196
|
+
<li><a href="https://intlayer.org/doc/environment/angular" rel=''>Angular</a></li>
|
|
197
|
+
<li><a href="https://intlayer.org/doc/environment/express" rel=''>Express</a></li>
|
|
198
|
+
<li><a href="https://intlayer.org/doc/environment/nest" rel=''>NestJS</a></li>
|
|
199
|
+
</ul>
|
|
200
|
+
</details>
|
|
201
|
+
|
|
202
|
+
<details>
|
|
203
|
+
<summary style="font-size:16px; font-weight:bold;">📰 Blog</summary>
|
|
204
|
+
<ul>
|
|
205
|
+
<li><a href="https://github.com/aymericzip/intlayer/blob/main/docs/blog/en/what_is_internationalization.md" rel=''>What is i18n</a></li>
|
|
206
|
+
<li><a href="https://intlayer.org/blog/SEO-and-i18n" rel=''>i18n and SEO</a></li>
|
|
207
|
+
<li><a href="https://intlayer.org/blog/intlayer-with-next-i18next" rel=''>Intlayer and i18next</a></li>
|
|
208
|
+
<li><a href="https://intlayer.org/blog/intlayer-with-react-i18next" rel=''>Intlayer and react-intl</a></li>
|
|
209
|
+
<li><a href="https://intlayer.org/blog/intlayer-with-next-intl" rel=''>Intlayer and next-intl</a></li>
|
|
210
|
+
</ul>
|
|
211
|
+
</details>
|
|
212
|
+
|
|
213
|
+
## 🌐 Readme in other languages
|
|
214
|
+
|
|
215
|
+
<p align="center">
|
|
216
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/readme.md">English</a> •
|
|
217
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/zh/readme.md">简体中文</a> •
|
|
218
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/ru/readme.md">Русский</a> •
|
|
219
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/ja/readme.md">日本語</a> •
|
|
220
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/fr/readme.md">Français</a> •
|
|
221
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/ko/readme.md">한국어</a> •
|
|
222
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/es/readme.md">Español</a> •
|
|
223
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/de/readme.md">Deutsch</a> •
|
|
224
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/ar/readme.md">العربية</a> •
|
|
225
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/it/readme.md">Italiano</a> •
|
|
226
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/en-GB/readme.md">English (UK)</a> •
|
|
227
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/pt/readme.md">Português</a> •
|
|
228
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/hi/readme.md">हिन्दी</a> •
|
|
229
|
+
<a href="https://github.com/aymericzip/intlayer/blob/main/docs/docs/tr/readme.md">Türkçe</a>
|
|
230
|
+
</p>
|
|
231
|
+
|
|
232
|
+
## 🤝 Community
|
|
233
|
+
|
|
234
|
+
Intlayer is built with and for the community and we’d love your input!
|
|
235
|
+
|
|
236
|
+
- Have a suggestion? [Open an issue](https://github.com/aymericzip/intlayer/issues)
|
|
237
|
+
- Found a bug or improvement? [Submit a PR](https://github.com/aymericzip/intlayer/pulls)
|
|
238
|
+
- Need help or want to connect? [Join our Discord](https://discord.gg/7uxamYVeCk)
|
|
239
|
+
|
|
240
|
+
You can also follow us on :
|
|
241
|
+
|
|
242
|
+
<div>
|
|
243
|
+
<br/>
|
|
244
|
+
<p align="center">
|
|
245
|
+
<a href="https://discord.gg/528mBV4N" target="blank" rel='noopener noreferrer nofollow'><img align="center"
|
|
246
|
+
src="https://img.shields.io/badge/discord-5865F2.svg?style=for-the-badge&logo=discord&logoColor=white"
|
|
247
|
+
alt="Intlayer Discord" height="30"/></a>
|
|
248
|
+
<a href="https://www.linkedin.com/company/intlayerorg" target="blank" rel='noopener noreferrer nofollow'><img align="center"
|
|
249
|
+
src="https://img.shields.io/badge/linkedin-%231DA1F2.svg?style=for-the-badge&logo=linkedin&logoColor=white"
|
|
250
|
+
alt="Intlayer LinkedIn" height="30"/></a>
|
|
251
|
+
<a href="https://www.instagram.com/intlayer/" target="blank" rel='noopener noreferrer nofollow'><img align="center"
|
|
252
|
+
src="https://img.shields.io/badge/instagram-%23E4405F.svg?style=for-the-badge&logo=Instagram&logoColor=white"
|
|
253
|
+
alt="Intlayer Instagram" height="30"/></a>
|
|
254
|
+
<a href="https://x.com/Intlayer183096" target="blank" rel='noopener noreferrer nofollow'><img align="center"
|
|
255
|
+
src="https://img.shields.io/badge/x-1DA1F2.svg?style=for-the-badge&logo=x&logoColor=white"
|
|
256
|
+
alt="Intlayer X" height="30"/></a>
|
|
257
|
+
<a href="https://www.youtube.com/@intlayer" target="blank" rel='noopener noreferrer nofollow'><img align="center"
|
|
258
|
+
src="https://img.shields.io/badge/youtube-FF0000.svg?style=for-the-badge&logo=youtube&logoColor=white"
|
|
259
|
+
alt="Intlayer YouTube" height="30"/></a>
|
|
260
|
+
<a href="https://www.tiktok.com/@intlayer" target="blank" rel='noopener noreferrer nofollow'><img align="center"
|
|
261
|
+
src="https://img.shields.io/badge/tiktok-000000.svg?style=for-the-badge&logo=tiktok&logoColor=white"
|
|
262
|
+
alt="Intlayer TikTok" height="30"/></a>
|
|
263
|
+
<br>
|
|
264
|
+
</p>
|
|
265
|
+
</div>
|
|
266
|
+
|
|
267
|
+
### Contribution
|
|
268
|
+
|
|
269
|
+
For more detailed guidelines on contributing to this project, please refer to the [`CONTRIBUTING.md`](https://github.com/aymericzip/intlayer/blob/main/CONTRIBUTING.md) file. It contains essential information on our development process, commit message conventions, and release procedures. Your contributions are valuable to us, and we appreciate your efforts in making this project better!
|
|
270
|
+
|
|
271
|
+
### Thank You for the Support
|
|
272
|
+
|
|
273
|
+
If you like Intlayer, give us a ⭐ on GitHub. It helps others discover the project! [See why GitHub Stars matter](https://github.com/aymericzip/intlayer/blob/main/CONTRIBUTING.md#why-github-stars-matter-).
|
|
274
|
+
|
|
275
|
+
[](https://star-history.com/#aymericzip/intlayer&Date)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
Your role is to describe a content declaration.
|
|
2
|
+
|
|
3
|
+
1. **Terminology:**
|
|
4
|
+
|
|
5
|
+
- **Dictionary:** A content declaration is a is a file (.ts, .js or .json) that contains the multilingual declaration related to a specific content. A content declaration file is usually related to a specific component, or page or section of a website.
|
|
6
|
+
- **Tag:** A tag is attached to a content declaration and is used to group content declaration and harmonize them.
|
|
7
|
+
|
|
8
|
+
2. **Audit Requirements:**
|
|
9
|
+
- **Do Not Alter Structure:** If the file structure is correct, do not modify it. Only add, update, or remove content declarations as necessary.
|
|
10
|
+
- **Misspelled Content:** If declared, detect each `title`, `description` and `tags` are not misspelled. If some content is misspelled, correct it.
|
|
11
|
+
|
|
12
|
+
3. **Fields functions:**
|
|
13
|
+
|
|
14
|
+
- **Title:** The title of the content declaration allows to easily identify it. It should be considered as a readable way to represent the `key` (example: `page-metadata` -> `Page metadata`). It should be a short and descriptive title that accurately reflects the dictionary.
|
|
15
|
+
- **Description:** The description of the content declaration provides a brief summary of the content declaration. It should be a concise and informative description that explains the purpose and content of the dictionary.
|
|
16
|
+
- **Tags:** The tags is an array of strings that represent the key of the tags associated with the content declaration.
|
|
17
|
+
|
|
18
|
+
**Expected Response:**
|
|
19
|
+
|
|
20
|
+
After completion, provide only the final title, description and tags fields in a JSON without any Markdown, code block formatting or any additional comments or explanations.
|
|
21
|
+
|
|
22
|
+
Correct this fields if they are misspelled or do not match the expected content, and / or complete missing title / description / tags.
|
|
23
|
+
|
|
24
|
+
**Example of expected response:**
|
|
25
|
+
|
|
26
|
+
The following case is just an example of expected behavior:
|
|
27
|
+
|
|
28
|
+
- Example of entry:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
import { t, type Dictionary } from "intlayer";
|
|
32
|
+
import { Metadata } from "next";
|
|
33
|
+
|
|
34
|
+
const metadataContent = {
|
|
35
|
+
key: "pricing-metadata",
|
|
36
|
+
title: "",
|
|
37
|
+
description:
|
|
38
|
+
"here a description that doesn't make any sense and should be replaced",
|
|
39
|
+
content: {
|
|
40
|
+
title: t({
|
|
41
|
+
en: "Pricing | Intlayer",
|
|
42
|
+
}),
|
|
43
|
+
description: t({
|
|
44
|
+
en: "Discover our pricing plans and get access to premium features with Intlayer. Choose the plan that suits you best.",
|
|
45
|
+
}),
|
|
46
|
+
keywords: t<string[]>({
|
|
47
|
+
en: ["Pricing", "Subscription"],
|
|
48
|
+
}),
|
|
49
|
+
},
|
|
50
|
+
} satisfies Dictionary<Metadata>;
|
|
51
|
+
|
|
52
|
+
export default metadataContent;
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
- Example of response:
|
|
56
|
+
|
|
57
|
+
```json
|
|
58
|
+
{
|
|
59
|
+
"title": "Pricing page metadata",
|
|
60
|
+
"description": "Metadata related to the pricing page, includes title, description, keywords, metadata for SEO purpose. It will help search engines understand the content of the page.",
|
|
61
|
+
"tags": ["page metadata", "pricing page"]
|
|
62
|
+
}
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
**Application Context**
|
|
66
|
+
|
|
67
|
+
{{applicationContext}}
|
|
68
|
+
|
|
69
|
+
**List of existing Tags:**
|
|
70
|
+
|
|
71
|
+
Here the list of existing tags as a context to help you to pick related ones.
|
|
72
|
+
|
|
73
|
+
{{tags}}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
You are an expert in internationalization, copy writing and content management. Your task is to audit the content declaration files in the project and identify any potential issues or inconsistencies. Provide a detailed report of any issues found, including the file path, line number, and a brief explanation of the issue.
|
|
2
|
+
|
|
3
|
+
**Instructions:**
|
|
4
|
+
|
|
5
|
+
2. **Audit Requirements:**
|
|
6
|
+
- **Consistency:** The dictionary format should be the same as the one provided in entry. You should not rename or translate the entry keys.
|
|
7
|
+
- **Missing Content:** Identify any missing translations and specify the expected content.
|
|
8
|
+
- **Misplaced Content:** Detect if any translations are placed under incorrect keys.
|
|
9
|
+
- **Type Compliance:** Verify that the content types match the declarations (e.g., strings, string arrays).
|
|
10
|
+
|
|
11
|
+
3. **Modification Guidelines:**
|
|
12
|
+
- **Do Not Alter Structure:** If the file structure is correct, do not modify it. Only add, update, or remove content declarations as necessary.
|
|
13
|
+
- **Missing Content:** If one key is missing from the Preset Output Content, or if the Preset Output Content is empty, the output content should be completed by translating the Entry Content to Translate into the output locale.
|
|
14
|
+
- **Return Only Final File Content:** Provide the updated file content without any additional comments or explanations.
|
|
15
|
+
- **Manage Localizations:** If the output languages targeted is a variant contains similar languages, as `en` and `en-GB`, consider `en` as English US, and adapt it into `en-GB` as English UK.
|
|
16
|
+
- **Escape Special Characters:** If the translations contain special characters, escape them using the appropriate escape sequence.
|
|
17
|
+
- **Respect the tags and description instructions:** If the tags and description instructions are provided, ensure that the audited file adheres to them.
|
|
18
|
+
- **Consider the Preset Output Content** If Preset Output Content is provided, and coherent with the entry, you can consider reuse it to fill the output file content.
|
|
19
|
+
- **TypeNode field should not be translated** A value as `{ 'nodeType': 'XXX', ...}` should not be translated.
|
|
20
|
+
|
|
21
|
+
**Application Context**
|
|
22
|
+
|
|
23
|
+
{{applicationContext}}
|
|
24
|
+
|
|
25
|
+
**Mode Instruction:**
|
|
26
|
+
|
|
27
|
+
{{modeInstructions}}
|
|
28
|
+
|
|
29
|
+
**Tags Instructions:**
|
|
30
|
+
|
|
31
|
+
{{tagsInstructions}}
|
|
32
|
+
|
|
33
|
+
**Dictionary Description:**
|
|
34
|
+
|
|
35
|
+
{{dictionaryDescription}}
|
|
36
|
+
|
|
37
|
+
**Preset Output Content:**
|
|
38
|
+
|
|
39
|
+
- Target Language: {{outputLocale}}
|
|
40
|
+
|
|
41
|
+
{{presetOutputContent}}
|
|
42
|
+
|
|
43
|
+
**Expected Response:**
|
|
44
|
+
|
|
45
|
+
After auditing, provide only the final content of the file as plain text without any Markdown or code block formatting. If no changes are needed, return the file content exactly as it is.
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
let node_fs = require("node:fs");
|
|
2
|
+
let node_path = require("node:path");
|
|
3
|
+
let node_url = require("node:url");
|
|
4
|
+
|
|
5
|
+
//#region \0utils:asset
|
|
6
|
+
const hereDirname = () => {
|
|
7
|
+
try {
|
|
8
|
+
return (0, node_path.dirname)((0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href));
|
|
9
|
+
} catch {
|
|
10
|
+
return typeof __dirname !== "undefined" ? __dirname : process.cwd();
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
const findDistRoot = (startDir) => {
|
|
14
|
+
let dir = startDir;
|
|
15
|
+
for (let i = 0; i < 12; i++) {
|
|
16
|
+
if ((0, node_path.basename)(dir) === "dist") return dir;
|
|
17
|
+
const parent = (0, node_path.resolve)(dir, "..");
|
|
18
|
+
if (parent === dir) break;
|
|
19
|
+
dir = parent;
|
|
20
|
+
}
|
|
21
|
+
return null;
|
|
22
|
+
};
|
|
23
|
+
const normalizeFrameFile = (file) => {
|
|
24
|
+
if (!file) return null;
|
|
25
|
+
try {
|
|
26
|
+
if (file.startsWith("file://")) return (0, node_url.fileURLToPath)(file);
|
|
27
|
+
} catch {}
|
|
28
|
+
return file;
|
|
29
|
+
};
|
|
30
|
+
/**
|
|
31
|
+
* Returns the directory of the *caller* module that invoked readAsset.
|
|
32
|
+
* Prefers non-virtual frames; falls back to the first real frame.
|
|
33
|
+
*/
|
|
34
|
+
const getCallerDir = () => {
|
|
35
|
+
const prev = Error.prepareStackTrace;
|
|
36
|
+
try {
|
|
37
|
+
Error.prepareStackTrace = (_, structured) => structured;
|
|
38
|
+
const err = /* @__PURE__ */ new Error();
|
|
39
|
+
Error.captureStackTrace(err, getCallerDir);
|
|
40
|
+
/** @type {import('node:vm').CallSite[]} */
|
|
41
|
+
const frames = err.stack || [];
|
|
42
|
+
const isVirtualPath = (p) => p.includes(`${node_path.sep}_virtual${node_path.sep}`) || p.includes("/_virtual/");
|
|
43
|
+
for (const frame of frames) {
|
|
44
|
+
const file = normalizeFrameFile(typeof frame.getFileName === "function" ? frame.getFileName() : null);
|
|
45
|
+
if (!file) continue;
|
|
46
|
+
if (file.includes("node:internal") || file.includes(`${node_path.sep}internal${node_path.sep}modules${node_path.sep}`)) continue;
|
|
47
|
+
if (!isVirtualPath(file)) return (0, node_path.dirname)(file);
|
|
48
|
+
}
|
|
49
|
+
for (const frame of frames) {
|
|
50
|
+
const file = normalizeFrameFile(typeof frame.getFileName === "function" ? frame.getFileName() : null);
|
|
51
|
+
if (file) return (0, node_path.dirname)(file);
|
|
52
|
+
}
|
|
53
|
+
} catch {} finally {
|
|
54
|
+
Error.prepareStackTrace = prev;
|
|
55
|
+
}
|
|
56
|
+
return hereDirname();
|
|
57
|
+
};
|
|
58
|
+
/**
|
|
59
|
+
* Read an asset copied from src/** to dist/assets/**.
|
|
60
|
+
* - './' or '../' is resolved relative to the *caller module's* emitted directory.
|
|
61
|
+
* - otherwise, treat as src-relative.
|
|
62
|
+
*
|
|
63
|
+
* @param {string} relPath - e.g. './PROMPT.md' or 'utils/AI/askDocQuestion/embeddings/<fileKey>.json'
|
|
64
|
+
* @param {BufferEncoding} [encoding='utf8']
|
|
65
|
+
*/
|
|
66
|
+
const readAsset = (relPath, encoding = "utf8") => {
|
|
67
|
+
const here = hereDirname();
|
|
68
|
+
const distRoot = findDistRoot(here) ?? (0, node_path.resolve)(here, "..", "..", "dist");
|
|
69
|
+
const assetsRoot = (0, node_path.join)(distRoot, "assets");
|
|
70
|
+
const tried = [];
|
|
71
|
+
/**
|
|
72
|
+
* Transform dist/(esm|cjs)/... and _virtual/ prefix to clean subpath (Windows-safe)
|
|
73
|
+
*/
|
|
74
|
+
const callerSubpath = (0, node_path.relative)(distRoot, getCallerDir()).split("\\").join("/").replace(/^(?:dist\/)?(?:esm|cjs)\//, "").replace(/^_virtual\//, "");
|
|
75
|
+
if (relPath.startsWith("./") || relPath.startsWith("../")) {
|
|
76
|
+
const fromCallerAbs = (0, node_path.resolve)(assetsRoot, callerSubpath, relPath);
|
|
77
|
+
tried.push(fromCallerAbs);
|
|
78
|
+
if ((0, node_fs.existsSync)(fromCallerAbs)) return (0, node_fs.readFileSync)(fromCallerAbs, encoding);
|
|
79
|
+
}
|
|
80
|
+
const directPath = (0, node_path.join)(assetsRoot, relPath);
|
|
81
|
+
tried.push(directPath);
|
|
82
|
+
if ((0, node_fs.existsSync)(directPath)) return (0, node_fs.readFileSync)(directPath, encoding);
|
|
83
|
+
if (callerSubpath) {
|
|
84
|
+
const nested = (0, node_path.join)(assetsRoot, callerSubpath, relPath);
|
|
85
|
+
tried.push(nested);
|
|
86
|
+
if ((0, node_fs.existsSync)(nested)) return (0, node_fs.readFileSync)(nested, encoding);
|
|
87
|
+
}
|
|
88
|
+
const msg = [
|
|
89
|
+
"readAsset: file not found.",
|
|
90
|
+
"Searched:",
|
|
91
|
+
...tried.map((p) => `- ${p}`)
|
|
92
|
+
].join("\n");
|
|
93
|
+
throw new Error(msg);
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
//#endregion
|
|
97
|
+
exports.readAsset = readAsset;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
let __ai_sdk_anthropic = require("@ai-sdk/anthropic");
|
|
2
|
+
let __ai_sdk_deepseek = require("@ai-sdk/deepseek");
|
|
3
|
+
let __ai_sdk_google = require("@ai-sdk/google");
|
|
4
|
+
let __ai_sdk_mistral = require("@ai-sdk/mistral");
|
|
5
|
+
let __ai_sdk_openai = require("@ai-sdk/openai");
|
|
6
|
+
|
|
7
|
+
//#region src/aiSdk.ts
|
|
8
|
+
/**
|
|
9
|
+
* Supported AI SDK providers
|
|
10
|
+
*/
|
|
11
|
+
let AIProvider = /* @__PURE__ */ function(AIProvider$1) {
|
|
12
|
+
AIProvider$1["OPENAI"] = "openai";
|
|
13
|
+
AIProvider$1["ANTHROPIC"] = "anthropic";
|
|
14
|
+
AIProvider$1["MISTRAL"] = "mistral";
|
|
15
|
+
AIProvider$1["DEEPSEEK"] = "deepseek";
|
|
16
|
+
AIProvider$1["GEMINI"] = "gemini";
|
|
17
|
+
return AIProvider$1;
|
|
18
|
+
}({});
|
|
19
|
+
const getAPIKey = (accessType, aiOptions, isAuthenticated = false) => {
|
|
20
|
+
const defaultApiKey = process.env.OPENAI_API_KEY;
|
|
21
|
+
if (accessType.includes("public")) return aiOptions?.apiKey ?? defaultApiKey;
|
|
22
|
+
if (accessType.includes("apiKey") && aiOptions?.apiKey) return aiOptions?.apiKey;
|
|
23
|
+
if (accessType.includes("registered_user") && isAuthenticated) return aiOptions?.apiKey ?? defaultApiKey;
|
|
24
|
+
if (accessType.includes("premium_user") && isAuthenticated) return aiOptions?.apiKey ?? defaultApiKey;
|
|
25
|
+
};
|
|
26
|
+
const getModel = (provider, userApiKey, userModel, defaultModel = "gpt-5-mini") => {
|
|
27
|
+
if (userApiKey) {
|
|
28
|
+
if (provider && provider === AIProvider.OPENAI) return userModel ?? defaultModel;
|
|
29
|
+
switch (provider) {
|
|
30
|
+
case AIProvider.ANTHROPIC: return "claude-sonnet-4-5-20250929";
|
|
31
|
+
case AIProvider.MISTRAL: return "mistral-large-latest";
|
|
32
|
+
case AIProvider.DEEPSEEK: return "deepseek-coder";
|
|
33
|
+
case AIProvider.GEMINI: return "gemini-2.5-flash";
|
|
34
|
+
default: return defaultModel;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (userModel || provider) throw new Error("The user should use his own API key to use a custom model");
|
|
38
|
+
return defaultModel;
|
|
39
|
+
};
|
|
40
|
+
const DEFAULT_PROVIDER = AIProvider.OPENAI;
|
|
41
|
+
const DEFAULT_TEMPERATURE = 1;
|
|
42
|
+
/**
|
|
43
|
+
* Get AI model configuration based on the selected provider and options
|
|
44
|
+
* This function handles the configuration for different AI providers
|
|
45
|
+
*
|
|
46
|
+
* @param options Configuration options including provider, API keys, models and temperature
|
|
47
|
+
* @returns Configured AI model ready to use with generateText
|
|
48
|
+
*/
|
|
49
|
+
const getAIConfig = async (options, isAuthenticated = false) => {
|
|
50
|
+
const { userOptions, defaultOptions, accessType = ["registered_user"] } = options;
|
|
51
|
+
const aiOptions = {
|
|
52
|
+
provider: DEFAULT_PROVIDER,
|
|
53
|
+
temperature: DEFAULT_TEMPERATURE,
|
|
54
|
+
...defaultOptions,
|
|
55
|
+
...userOptions
|
|
56
|
+
};
|
|
57
|
+
const apiKey = getAPIKey(accessType, aiOptions, isAuthenticated);
|
|
58
|
+
if (!apiKey) throw new Error(`API key for ${aiOptions.provider} is missing`);
|
|
59
|
+
const selectedModel = getModel(aiOptions.provider, apiKey, aiOptions.model, defaultOptions?.model);
|
|
60
|
+
const protectedOptions = {
|
|
61
|
+
...aiOptions,
|
|
62
|
+
apiKey,
|
|
63
|
+
model: selectedModel
|
|
64
|
+
};
|
|
65
|
+
let languageModel;
|
|
66
|
+
switch (protectedOptions.provider) {
|
|
67
|
+
case AIProvider.OPENAI:
|
|
68
|
+
languageModel = (0, __ai_sdk_openai.createOpenAI)({ apiKey })(selectedModel);
|
|
69
|
+
break;
|
|
70
|
+
case AIProvider.ANTHROPIC:
|
|
71
|
+
languageModel = (0, __ai_sdk_anthropic.createAnthropic)({ apiKey })(selectedModel);
|
|
72
|
+
break;
|
|
73
|
+
case AIProvider.MISTRAL:
|
|
74
|
+
languageModel = (0, __ai_sdk_mistral.createMistral)({ apiKey })(selectedModel);
|
|
75
|
+
break;
|
|
76
|
+
case AIProvider.DEEPSEEK:
|
|
77
|
+
languageModel = (0, __ai_sdk_deepseek.createDeepSeek)({ apiKey })(selectedModel);
|
|
78
|
+
break;
|
|
79
|
+
case AIProvider.GEMINI:
|
|
80
|
+
languageModel = (0, __ai_sdk_google.createGoogleGenerativeAI)({ apiKey })(selectedModel);
|
|
81
|
+
break;
|
|
82
|
+
default: throw new Error(`Provider ${protectedOptions.provider} not supported`);
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
model: languageModel,
|
|
86
|
+
temperature: protectedOptions.temperature
|
|
87
|
+
};
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
//#endregion
|
|
91
|
+
exports.AIProvider = AIProvider;
|
|
92
|
+
exports.getAIConfig = getAIConfig;
|
|
93
|
+
//# sourceMappingURL=aiSdk.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aiSdk.cjs","names":["DEFAULT_PROVIDER: AIProvider","DEFAULT_TEMPERATURE: number","languageModel: AIConfig['model']"],"sources":["../../src/aiSdk.ts"],"sourcesContent":["import { type anthropic, createAnthropic } from '@ai-sdk/anthropic';\nimport { createDeepSeek, type deepseek } from '@ai-sdk/deepseek';\nimport { createGoogleGenerativeAI, type google } from '@ai-sdk/google';\nimport { createMistral, type mistral } from '@ai-sdk/mistral';\nimport { createOpenAI, type openai } from '@ai-sdk/openai';\nimport type {\n AssistantModelMessage,\n generateText,\n SystemModelMessage,\n ToolModelMessage,\n UserModelMessage,\n} from 'ai';\n\ntype AnthropicModel = Parameters<typeof anthropic>[0];\ntype DeepSeekModel = Parameters<typeof deepseek>[0];\ntype MistralModel = Parameters<typeof mistral>[0];\ntype OpenAIModel = Parameters<typeof openai>[0];\ntype GoogleModel = Parameters<typeof google>[0];\n\nexport type Messages = (\n | SystemModelMessage\n | UserModelMessage\n | AssistantModelMessage\n | ToolModelMessage\n)[];\n\n/**\n * Supported AI models\n */\nexport type Model =\n | AnthropicModel\n | DeepSeekModel\n | MistralModel\n | OpenAIModel\n | GoogleModel\n | (string & {});\n\n/**\n * Supported AI SDK providers\n */\nexport enum AIProvider {\n OPENAI = 'openai',\n ANTHROPIC = 'anthropic',\n MISTRAL = 'mistral',\n DEEPSEEK = 'deepseek',\n GEMINI = 'gemini',\n}\n\n/**\n * Common options for all AI providers\n */\nexport type AIOptions = {\n provider?: AIProvider;\n model?: Model;\n temperature?: number;\n apiKey?: string;\n applicationContext?: string;\n};\n\n// Define the structure of messages used in chat completions\nexport type ChatCompletionRequestMessage = {\n role: 'system' | 'user' | 'assistant'; // The role of the message sender\n content: string; // The text content of the message\n timestamp?: Date; // The timestamp of the message\n};\n\ntype AccessType = 'apiKey' | 'registered_user' | 'premium_user' | 'public';\n\nconst getAPIKey = (\n accessType: AccessType[],\n aiOptions?: AIOptions,\n isAuthenticated: boolean = false\n) => {\n const defaultApiKey = process.env.OPENAI_API_KEY;\n\n if (accessType.includes('public')) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n if (accessType.includes('apiKey') && aiOptions?.apiKey) {\n return aiOptions?.apiKey;\n }\n\n if (accessType.includes('registered_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n // TODO: Implement premium user access\n if (accessType.includes('premium_user') && isAuthenticated) {\n return aiOptions?.apiKey ?? defaultApiKey;\n }\n\n return undefined;\n};\n\nconst getModel = (\n provider: AIProvider,\n userApiKey: string,\n userModel?: Model,\n defaultModel: Model = 'gpt-5-mini'\n): Model => {\n // If the user uses their own API key, allow custom model selection\n if (userApiKey) {\n if (provider && provider === AIProvider.OPENAI) {\n return userModel ?? defaultModel;\n }\n\n switch (provider) {\n case AIProvider.ANTHROPIC:\n return 'claude-sonnet-4-5-20250929';\n case AIProvider.MISTRAL:\n return 'mistral-large-latest';\n case AIProvider.DEEPSEEK:\n return 'deepseek-coder';\n case AIProvider.GEMINI:\n return 'gemini-2.5-flash';\n default:\n return defaultModel;\n }\n }\n\n // Guard: Prevent custom model usage without a user API key\n if (userModel || provider) {\n throw new Error(\n 'The user should use his own API key to use a custom model'\n );\n }\n\n return defaultModel;\n};\n\nexport type AIConfig = Omit<Parameters<typeof generateText>[0], 'prompt'>;\n\nconst DEFAULT_PROVIDER: AIProvider = AIProvider.OPENAI as AIProvider;\nconst DEFAULT_TEMPERATURE: number = 1; // ChatGPT 5 accept only temperature 1\n\nexport type AIConfigOptions = {\n userOptions?: AIOptions;\n defaultOptions?: AIOptions;\n accessType?: AccessType[];\n};\n\n/**\n * Get AI model configuration based on the selected provider and options\n * This function handles the configuration for different AI providers\n *\n * @param options Configuration options including provider, API keys, models and temperature\n * @returns Configured AI model ready to use with generateText\n */\nexport const getAIConfig = async (\n options: AIConfigOptions,\n isAuthenticated: boolean = false\n): Promise<AIConfig> => {\n const {\n userOptions,\n defaultOptions,\n accessType = ['registered_user'],\n } = options;\n\n const aiOptions = {\n provider: DEFAULT_PROVIDER,\n temperature: DEFAULT_TEMPERATURE,\n ...defaultOptions,\n ...userOptions,\n } satisfies AIOptions;\n\n const apiKey = getAPIKey(accessType, aiOptions, isAuthenticated);\n\n // Check if API key is provided\n if (!apiKey) {\n throw new Error(`API key for ${aiOptions.provider} is missing`);\n }\n\n const selectedModel = getModel(\n aiOptions.provider,\n apiKey,\n aiOptions.model,\n defaultOptions?.model\n );\n\n const protectedOptions = {\n ...aiOptions,\n apiKey,\n model: selectedModel,\n } satisfies AIOptions;\n\n let languageModel: AIConfig['model'];\n\n switch (protectedOptions.provider) {\n case AIProvider.OPENAI: {\n languageModel = createOpenAI({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.ANTHROPIC: {\n languageModel = createAnthropic({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.MISTRAL: {\n languageModel = createMistral({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.DEEPSEEK: {\n languageModel = createDeepSeek({\n apiKey,\n })(selectedModel);\n break;\n }\n\n case AIProvider.GEMINI: {\n languageModel = createGoogleGenerativeAI({\n apiKey,\n })(selectedModel);\n break;\n }\n\n default: {\n throw new Error(`Provider ${protectedOptions.provider} not supported`);\n }\n }\n\n return {\n model: languageModel,\n temperature: protectedOptions.temperature,\n };\n};\n"],"mappings":";;;;;;;;;;AAwCA,IAAY,oDAAL;AACL;AACA;AACA;AACA;AACA;;;AAuBF,MAAM,aACJ,YACA,WACA,kBAA2B,UACxB;CACH,MAAM,gBAAgB,QAAQ,IAAI;AAElC,KAAI,WAAW,SAAS,SAAS,CAC/B,QAAO,WAAW,UAAU;AAG9B,KAAI,WAAW,SAAS,SAAS,IAAI,WAAW,OAC9C,QAAO,WAAW;AAGpB,KAAI,WAAW,SAAS,kBAAkB,IAAI,gBAC5C,QAAO,WAAW,UAAU;AAI9B,KAAI,WAAW,SAAS,eAAe,IAAI,gBACzC,QAAO,WAAW,UAAU;;AAMhC,MAAM,YACJ,UACA,YACA,WACA,eAAsB,iBACZ;AAEV,KAAI,YAAY;AACd,MAAI,YAAY,aAAa,WAAW,OACtC,QAAO,aAAa;AAGtB,UAAQ,UAAR;GACE,KAAK,WAAW,UACd,QAAO;GACT,KAAK,WAAW,QACd,QAAO;GACT,KAAK,WAAW,SACd,QAAO;GACT,KAAK,WAAW,OACd,QAAO;GACT,QACE,QAAO;;;AAKb,KAAI,aAAa,SACf,OAAM,IAAI,MACR,4DACD;AAGH,QAAO;;AAKT,MAAMA,mBAA+B,WAAW;AAChD,MAAMC,sBAA8B;;;;;;;;AAepC,MAAa,cAAc,OACzB,SACA,kBAA2B,UACL;CACtB,MAAM,EACJ,aACA,gBACA,aAAa,CAAC,kBAAkB,KAC9B;CAEJ,MAAM,YAAY;EAChB,UAAU;EACV,aAAa;EACb,GAAG;EACH,GAAG;EACJ;CAED,MAAM,SAAS,UAAU,YAAY,WAAW,gBAAgB;AAGhE,KAAI,CAAC,OACH,OAAM,IAAI,MAAM,eAAe,UAAU,SAAS,aAAa;CAGjE,MAAM,gBAAgB,SACpB,UAAU,UACV,QACA,UAAU,OACV,gBAAgB,MACjB;CAED,MAAM,mBAAmB;EACvB,GAAG;EACH;EACA,OAAO;EACR;CAED,IAAIC;AAEJ,SAAQ,iBAAiB,UAAzB;EACE,KAAK,WAAW;AACd,qDAA6B,EAC3B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,2DAAgC,EAC9B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,uDAA8B,EAC5B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,yDAA+B,EAC7B,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,KAAK,WAAW;AACd,iEAAyC,EACvC,QACD,CAAC,CAAC,cAAc;AACjB;EAGF,QACE,OAAM,IAAI,MAAM,YAAY,iBAAiB,SAAS,gBAAgB;;AAI1E,QAAO;EACL,OAAO;EACP,aAAa,iBAAiB;EAC/B"}
|