@scopeact/autoi18n 1.1.2 → 1.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 (46) hide show
  1. package/dist/chunk-36HQJSGI.cjs +40 -0
  2. package/dist/chunk-36HQJSGI.cjs.map +1 -0
  3. package/dist/chunk-NYRK5OWZ.js +40 -0
  4. package/dist/chunk-NYRK5OWZ.js.map +1 -0
  5. package/dist/chunk-RLNUAAKC.js +296 -0
  6. package/dist/chunk-RLNUAAKC.js.map +1 -0
  7. package/dist/chunk-TJT6ONON.cjs +41 -0
  8. package/dist/chunk-TJT6ONON.cjs.map +1 -0
  9. package/dist/chunk-TWTG4RTI.cjs +296 -0
  10. package/dist/chunk-TWTG4RTI.cjs.map +1 -0
  11. package/dist/chunk-VBBY4GSW.js +41 -0
  12. package/dist/chunk-VBBY4GSW.js.map +1 -0
  13. package/dist/cli.cjs +18 -0
  14. package/dist/cli.cjs.map +1 -0
  15. package/dist/cli.d.cts +1 -0
  16. package/dist/cli.d.ts +1 -0
  17. package/dist/cli.js +18 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/client.cjs +10 -0
  20. package/dist/client.cjs.map +1 -0
  21. package/dist/client.d.cts +17 -0
  22. package/dist/client.d.ts +17 -0
  23. package/dist/client.js +10 -0
  24. package/dist/client.js.map +1 -0
  25. package/dist/core/index.cjs +9 -0
  26. package/dist/core/index.cjs.map +1 -0
  27. package/dist/core/index.d.cts +4 -0
  28. package/dist/core/index.d.ts +4 -0
  29. package/dist/core/index.js +9 -0
  30. package/dist/core/index.js.map +1 -0
  31. package/dist/index.cjs +21 -0
  32. package/dist/index.cjs.map +1 -0
  33. package/dist/index.d.cts +5 -0
  34. package/dist/index.d.ts +5 -3
  35. package/dist/index.js +20 -18
  36. package/dist/index.js.map +1 -1
  37. package/dist/server.cjs +9 -0
  38. package/dist/server.cjs.map +1 -0
  39. package/dist/server.d.cts +10 -0
  40. package/dist/server.d.ts +10 -0
  41. package/dist/server.js +9 -0
  42. package/dist/server.js.map +1 -0
  43. package/package.json +79 -26
  44. package/schema.json +51 -0
  45. package/README.md +0 -256
  46. package/dist/index.d.ts.map +0 -1
@@ -0,0 +1,40 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }// src/runtime/client.tsx
2
+ var _react = require('react'); var _react2 = _interopRequireDefault(_react);
3
+ var _navigation = require('next/navigation');
4
+ var _jsxruntime = require('react/jsx-runtime');
5
+ var I18nContext = _react.createContext.call(void 0, void 0);
6
+ function I18nProvider({
7
+ children,
8
+ locale: initialLocale,
9
+ messages: initialMessages
10
+ }) {
11
+ const [locale, setLocaleState] = _react.useState.call(void 0, initialLocale);
12
+ const [messages, setMessages] = _react.useState.call(void 0, initialMessages);
13
+ const router = _navigation.useRouter.call(void 0, );
14
+ _react2.default.useEffect(() => {
15
+ setLocaleState(initialLocale);
16
+ setMessages(initialMessages);
17
+ }, [initialLocale, initialMessages]);
18
+ const t = (key) => {
19
+ return messages[key] || key;
20
+ };
21
+ const setLocale = (newLocale) => {
22
+ document.cookie = `NEXT_LOCALE=${newLocale}; path=/; max-age=31536000`;
23
+ setLocaleState(newLocale);
24
+ router.refresh();
25
+ };
26
+ return /* @__PURE__ */ _jsxruntime.jsx.call(void 0, I18nContext.Provider, { value: { locale, messages, t, setLocale }, children });
27
+ }
28
+ function useI18n() {
29
+ const context = _react.useContext.call(void 0, I18nContext);
30
+ if (!context) {
31
+ throw new Error("useI18n deve ser usado dentro de um I18nProvider");
32
+ }
33
+ return context;
34
+ }
35
+
36
+
37
+
38
+
39
+ exports.I18nProvider = I18nProvider; exports.useI18n = useI18n;
40
+ //# sourceMappingURL=chunk-36HQJSGI.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/auto-i18n/auto-i18n/packages/autoi18n/dist/chunk-36HQJSGI.cjs","../src/runtime/client.tsx"],"names":[],"mappings":"AAAA;ACGA,4EAAsE;AAEtE,6CAA0B;AAwClB,+CAAA;AA/BR,IAAM,YAAA,EAAc,kCAAA,KAA2C,CAAS,CAAA;AAEjE,SAAS,YAAA,CAAa;AAAA,EACzB,QAAA;AAAA,EACA,MAAA,EAAQ,aAAA;AAAA,EACR,QAAA,EAAU;AACd,CAAA,EAIG;AACC,EAAA,MAAM,CAAC,MAAA,EAAQ,cAAc,EAAA,EAAI,6BAAA,aAAsB,CAAA;AACvD,EAAA,MAAM,CAAC,QAAA,EAAU,WAAW,EAAA,EAAI,6BAAA,eAAwB,CAAA;AACxD,EAAA,MAAM,OAAA,EAAS,mCAAA,CAAU;AAEzB,EAAA,eAAA,CAAM,SAAA,CAAU,CAAA,EAAA,GAAM;AAClB,IAAA,cAAA,CAAe,aAAa,CAAA;AAC5B,IAAA,WAAA,CAAY,eAAe,CAAA;AAAA,EAC/B,CAAA,EAAG,CAAC,aAAA,EAAe,eAAe,CAAC,CAAA;AAEnC,EAAA,MAAM,EAAA,EAAI,CAAC,GAAA,EAAA,GAAgB;AACvB,IAAA,OAAO,QAAA,CAAS,GAAG,EAAA,GAAK,GAAA;AAAA,EAC5B,CAAA;AAEA,EAAA,MAAM,UAAA,EAAY,CAAC,SAAA,EAAA,GAAsB;AACrC,IAAA,QAAA,CAAS,OAAA,EAAS,CAAA,YAAA,EAAe,SAAS,CAAA,0BAAA,CAAA;AAC1C,IAAA,cAAA,CAAe,SAAS,CAAA;AACxB,IAAA,MAAA,CAAO,OAAA,CAAQ,CAAA;AAAA,EACnB,CAAA;AAEA,EAAA,uBACI,6BAAA,WAAC,CAAY,QAAA,EAAZ,EAAqB,KAAA,EAAO,EAAE,MAAA,EAAQ,QAAA,EAAU,CAAA,EAAG,UAAU,CAAA,EACzD,SAAA,CACL,CAAA;AAER;AAEO,SAAS,OAAA,CAAA,EAAU;AACtB,EAAA,MAAM,QAAA,EAAU,+BAAA,WAAsB,CAAA;AACtC,EAAA,GAAA,CAAI,CAAC,OAAA,EAAS;AACV,IAAA,MAAM,IAAI,KAAA,CAAM,kDAAkD,CAAA;AAAA,EACtE;AACA,EAAA,OAAO,OAAA;AACX;ADvBA;AACA;AACE;AACA;AACF,+DAAC","file":"/home/runner/work/auto-i18n/auto-i18n/packages/autoi18n/dist/chunk-36HQJSGI.cjs","sourcesContent":[null,"'use client';\n\n// @ts-ignore\nimport React, { createContext, useContext, useState, ReactNode } from 'react';\n// @ts-ignore\nimport { useRouter } from 'next/navigation';\n\ntype I18nContextType = {\n locale: string;\n messages: Record<string, string>;\n t: (key: string) => string;\n setLocale: (newLocale: string) => void;\n};\n\nconst I18nContext = createContext<I18nContextType | undefined>(undefined);\n\nexport function I18nProvider({\n children,\n locale: initialLocale,\n messages: initialMessages\n}: {\n children: ReactNode;\n locale: string;\n messages: Record<string, string>;\n}) {\n const [locale, setLocaleState] = useState(initialLocale);\n const [messages, setMessages] = useState(initialMessages);\n const router = useRouter();\n\n React.useEffect(() => {\n setLocaleState(initialLocale);\n setMessages(initialMessages);\n }, [initialLocale, initialMessages]);\n\n const t = (key: string) => {\n return messages[key] || key;\n };\n\n const setLocale = (newLocale: string) => {\n document.cookie = `NEXT_LOCALE=${newLocale}; path=/; max-age=31536000`;\n setLocaleState(newLocale);\n router.refresh();\n };\n\n return (\n <I18nContext.Provider value={{ locale, messages, t, setLocale }}>\n {children}\n </I18nContext.Provider>\n );\n}\n\nexport function useI18n() {\n const context = useContext(I18nContext);\n if (!context) {\n throw new Error('useI18n deve ser usado dentro de um I18nProvider');\n }\n return context;\n}"]}
@@ -0,0 +1,40 @@
1
+ // src/runtime/client.tsx
2
+ import React, { createContext, useContext, useState } from "react";
3
+ import { useRouter } from "next/navigation";
4
+ import { jsx } from "react/jsx-runtime";
5
+ var I18nContext = createContext(void 0);
6
+ function I18nProvider({
7
+ children,
8
+ locale: initialLocale,
9
+ messages: initialMessages
10
+ }) {
11
+ const [locale, setLocaleState] = useState(initialLocale);
12
+ const [messages, setMessages] = useState(initialMessages);
13
+ const router = useRouter();
14
+ React.useEffect(() => {
15
+ setLocaleState(initialLocale);
16
+ setMessages(initialMessages);
17
+ }, [initialLocale, initialMessages]);
18
+ const t = (key) => {
19
+ return messages[key] || key;
20
+ };
21
+ const setLocale = (newLocale) => {
22
+ document.cookie = `NEXT_LOCALE=${newLocale}; path=/; max-age=31536000`;
23
+ setLocaleState(newLocale);
24
+ router.refresh();
25
+ };
26
+ return /* @__PURE__ */ jsx(I18nContext.Provider, { value: { locale, messages, t, setLocale }, children });
27
+ }
28
+ function useI18n() {
29
+ const context = useContext(I18nContext);
30
+ if (!context) {
31
+ throw new Error("useI18n deve ser usado dentro de um I18nProvider");
32
+ }
33
+ return context;
34
+ }
35
+
36
+ export {
37
+ I18nProvider,
38
+ useI18n
39
+ };
40
+ //# sourceMappingURL=chunk-NYRK5OWZ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/runtime/client.tsx"],"sourcesContent":["'use client';\n\n// @ts-ignore\nimport React, { createContext, useContext, useState, ReactNode } from 'react';\n// @ts-ignore\nimport { useRouter } from 'next/navigation';\n\ntype I18nContextType = {\n locale: string;\n messages: Record<string, string>;\n t: (key: string) => string;\n setLocale: (newLocale: string) => void;\n};\n\nconst I18nContext = createContext<I18nContextType | undefined>(undefined);\n\nexport function I18nProvider({\n children,\n locale: initialLocale,\n messages: initialMessages\n}: {\n children: ReactNode;\n locale: string;\n messages: Record<string, string>;\n}) {\n const [locale, setLocaleState] = useState(initialLocale);\n const [messages, setMessages] = useState(initialMessages);\n const router = useRouter();\n\n React.useEffect(() => {\n setLocaleState(initialLocale);\n setMessages(initialMessages);\n }, [initialLocale, initialMessages]);\n\n const t = (key: string) => {\n return messages[key] || key;\n };\n\n const setLocale = (newLocale: string) => {\n document.cookie = `NEXT_LOCALE=${newLocale}; path=/; max-age=31536000`;\n setLocaleState(newLocale);\n router.refresh();\n };\n\n return (\n <I18nContext.Provider value={{ locale, messages, t, setLocale }}>\n {children}\n </I18nContext.Provider>\n );\n}\n\nexport function useI18n() {\n const context = useContext(I18nContext);\n if (!context) {\n throw new Error('useI18n deve ser usado dentro de um I18nProvider');\n }\n return context;\n}"],"mappings":";AAGA,OAAO,SAAS,eAAe,YAAY,gBAA2B;AAEtE,SAAS,iBAAiB;AAwClB;AA/BR,IAAM,cAAc,cAA2C,MAAS;AAEjE,SAAS,aAAa;AAAA,EACzB;AAAA,EACA,QAAQ;AAAA,EACR,UAAU;AACd,GAIG;AACC,QAAM,CAAC,QAAQ,cAAc,IAAI,SAAS,aAAa;AACvD,QAAM,CAAC,UAAU,WAAW,IAAI,SAAS,eAAe;AACxD,QAAM,SAAS,UAAU;AAEzB,QAAM,UAAU,MAAM;AAClB,mBAAe,aAAa;AAC5B,gBAAY,eAAe;AAAA,EAC/B,GAAG,CAAC,eAAe,eAAe,CAAC;AAEnC,QAAM,IAAI,CAAC,QAAgB;AACvB,WAAO,SAAS,GAAG,KAAK;AAAA,EAC5B;AAEA,QAAM,YAAY,CAAC,cAAsB;AACrC,aAAS,SAAS,eAAe,SAAS;AAC1C,mBAAe,SAAS;AACxB,WAAO,QAAQ;AAAA,EACnB;AAEA,SACI,oBAAC,YAAY,UAAZ,EAAqB,OAAO,EAAE,QAAQ,UAAU,GAAG,UAAU,GACzD,UACL;AAER;AAEO,SAAS,UAAU;AACtB,QAAM,UAAU,WAAW,WAAW;AACtC,MAAI,CAAC,SAAS;AACV,UAAM,IAAI,MAAM,kDAAkD;AAAA,EACtE;AACA,SAAO;AACX;","names":[]}
@@ -0,0 +1,296 @@
1
+ // src/core/scanner.ts
2
+ import ora2 from "ora";
3
+ import { Project, SyntaxKind } from "ts-morph";
4
+
5
+ // src/core/config.ts
6
+ import fs from "fs";
7
+ import path from "path";
8
+ import ora from "ora";
9
+ var configPath = path.join(process.cwd(), "auto-i18n.config.json");
10
+ function readConfig(key) {
11
+ if (!fs.existsSync(configPath)) {
12
+ createConfig();
13
+ }
14
+ const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
15
+ return config[key];
16
+ }
17
+ function createConfig() {
18
+ const spinner = ora("Criando arquivos de configura\xE7\xE3o...").start();
19
+ const defaultConfig = {
20
+ $schema: `https://unpkg.com/@scopeact/autoi18n@latest/schema.json`,
21
+ sourceLang: "pt",
22
+ targetLangs: ["en", "es"],
23
+ autoInject: false,
24
+ i18nLibrary: "react-i18next",
25
+ provider: "openai",
26
+ localesDir: "./locales",
27
+ model: "gpt-3.5-turbo",
28
+ files: ["src/**/*.tsx", "app/**/*.tsx"]
29
+ };
30
+ fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));
31
+ spinner.succeed();
32
+ }
33
+
34
+ // src/core/utils.ts
35
+ import fs2 from "fs";
36
+ import path2 from "path";
37
+ function createExtractionPrompt(itens, contexto) {
38
+ return `
39
+ Voc\xEA \xE9 um especialista em i18n. Recebi uma lista de textos de uma interface React.
40
+ Sua tarefa \xE9 gerar chaves (keys) sem\xE2nticas e curtas em ingl\xEAs (snake_case) para cada item.
41
+
42
+ REGRAS:
43
+ 1. Retorne APENAS um array de objetos JSON.
44
+ 2. Cada objeto deve ter: "id" (o mesmo enviado) e "key" (a chave sugerida).
45
+ 3. As chaves devem ser curtas (max 4 palavras).
46
+ 4. Textos longos devem ter chaves que resumam o sentido.
47
+
48
+ EXEMPLO DE ENTRADA:
49
+ [ { "id": 1, "text": "Salvar altera\xE7\xF5es" } ]
50
+
51
+ EXEMPLO DE SA\xCDDA:
52
+ [ { "id": 1, "key": "button_save_changes" } ]
53
+
54
+ ITENS PARA PROCESSAR:
55
+ ${JSON.stringify(itens, null, 2)}
56
+
57
+ ${contexto ? `Contexto do projeto: ${contexto}` : ""}
58
+ `.trim();
59
+ }
60
+ function createTranslationPrompt(delta, from, to, contexto) {
61
+ return `
62
+ Voc\xEA \xE9 um tradutor s\xEAnior de software especializado em localiza\xE7\xE3o (i18n).
63
+ Sua tarefa \xE9 traduzir os VALORES das novas chaves de interface que foram adicionadas ao projeto.
64
+
65
+ IDIOMAS: De "${from}" para "${to}".
66
+
67
+ REGRAS CR\xCDTICAS:
68
+ 1. MANUTEN\xC7\xC3O DE CHAVES: Mantenha as chaves (keys) EXATAMENTE como est\xE3o. N\xE3o as traduza nem as altere.
69
+ 2. TRADU\xC7\xC3O DE VALORES: Traduza apenas os valores para o idioma de destino.
70
+ 3. VARI\xC1VEIS E PLACEHOLDERS: Preserve placeholders como {{name}}, {0}, %s ou qualquer texto entre chaves. Eles N\xC3O devem ser traduzidos.
71
+ 4. TOM DE VOZ: Use um tom profissional e conciso, adequado para interfaces de usu\xE1rio (bot\xF5es, labels, mensagens de erro).
72
+ 5. FORMATO: Retorne APENAS o objeto JSON puro, sem explica\xE7\xF5es ou blocos de c\xF3digo markdown.
73
+
74
+ ${contexto ? `CONTEXTO DO PROJETO: ${contexto}` : ""}
75
+
76
+ DADOS PARA TRADUZIR:
77
+ ${JSON.stringify(delta, null, 2)}
78
+ `.trim();
79
+ }
80
+ function cleanJsonResponse(text) {
81
+ return text.replace(/```json|```/g, "").trim();
82
+ }
83
+ function lerJson(caminho) {
84
+ if (!fs2.existsSync(caminho)) {
85
+ fs2.mkdirSync(path2.dirname(caminho), { recursive: true });
86
+ fs2.writeFileSync(caminho, "{}");
87
+ return {};
88
+ }
89
+ return JSON.parse(fs2.readFileSync(caminho, "utf-8"));
90
+ }
91
+ function salvarJson(caminho, json) {
92
+ if (!fs2.existsSync(caminho)) {
93
+ fs2.mkdirSync(path2.dirname(caminho), { recursive: true });
94
+ }
95
+ fs2.writeFileSync(caminho, JSON.stringify(json, null, 2));
96
+ }
97
+
98
+ // src/core/ai.ts
99
+ import dotenv from "dotenv";
100
+ import { OpenAI } from "openai";
101
+ import { GoogleGenerativeAI } from "@google/generative-ai";
102
+ dotenv.config();
103
+ async function askLLM(prompt, mode = "text") {
104
+ const provider = readConfig("provider") || "openai";
105
+ const model = readConfig("model");
106
+ checkEnv(provider);
107
+ switch (provider) {
108
+ case "openai":
109
+ return askOpenAI(prompt, model || "gpt-4o", mode);
110
+ case "google":
111
+ return askGemini(prompt, model || "gemini-2.5-flash", mode);
112
+ case "deepseek":
113
+ return askDeepSeek(prompt, model || "deepseek-chat", mode);
114
+ case "openrouter":
115
+ return askOpenRouter(prompt, model || "google/gemini-2.0-flash-001", mode);
116
+ case "ollama":
117
+ return askOllama(prompt, model || "llama3", mode);
118
+ default:
119
+ throw new Error(`Provedor de IA desconhecido: ${provider}`);
120
+ }
121
+ }
122
+ function checkEnv(provider) {
123
+ if (!process.env[`${provider.toUpperCase()}_API_KEY`]) {
124
+ throw new Error(`${provider.toUpperCase()}_API_KEY n\xE3o foi definido`);
125
+ }
126
+ }
127
+ async function askOpenAI(prompt, model, mode) {
128
+ const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
129
+ const response = await openai.chat.completions.create({
130
+ response_format: mode === "json" ? { type: "json_object" } : { type: "text" },
131
+ messages: [{ role: "user", content: prompt }],
132
+ model
133
+ });
134
+ return response?.choices?.[0]?.message?.content || "";
135
+ }
136
+ async function askGemini(prompt, model, mode) {
137
+ const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY || "");
138
+ const gemini = genAI.getGenerativeModel({ model, generationConfig: { responseMimeType: mode === "json" ? "application/json" : "text/plain" } });
139
+ const result = await gemini.generateContent(prompt);
140
+ return result.response.text();
141
+ }
142
+ async function askDeepSeek(prompt, model, mode) {
143
+ const client = new OpenAI({
144
+ apiKey: process.env.DEEPSEEK_API_KEY,
145
+ baseURL: "https://api.deepseek.com"
146
+ });
147
+ const response = await client.chat.completions.create({
148
+ response_format: mode === "json" ? { type: "json_object" } : { type: "text" },
149
+ messages: [{ role: "user", content: prompt }],
150
+ model
151
+ });
152
+ return response?.choices?.[0]?.message?.content || "";
153
+ }
154
+ async function askOpenRouter(prompt, model, mode) {
155
+ const client = new OpenAI({
156
+ apiKey: process.env.OPENROUTER_API_KEY,
157
+ baseURL: "https://openrouter.ai/api/v1",
158
+ defaultHeaders: {
159
+ "HTTP-Referer": "https://github.com/felipevetter/auto-i18n"
160
+ }
161
+ });
162
+ const response = await client.chat.completions.create({
163
+ response_format: mode === "json" ? { type: "json_object" } : { type: "text" },
164
+ messages: [{ role: "user", content: prompt }],
165
+ model
166
+ });
167
+ return response?.choices?.[0]?.message?.content || "";
168
+ }
169
+ async function askOllama(prompt, model, mode) {
170
+ const response = await fetch("http://localhost:11434/api/generate", {
171
+ method: "POST",
172
+ body: JSON.stringify({
173
+ model,
174
+ prompt,
175
+ format: mode === "json" ? "json" : "text",
176
+ stream: false
177
+ })
178
+ });
179
+ const data = await response.json();
180
+ return data.response;
181
+ }
182
+
183
+ // src/core/scanner.ts
184
+ import chalk from "chalk";
185
+
186
+ // src/core/dependecies.ts
187
+ import "ts-morph";
188
+ function ensureI18nImport(sourceFile) {
189
+ const importDeclaration = sourceFile.getImportDeclaration("react-i18next");
190
+ if (!importDeclaration) {
191
+ sourceFile.addImportDeclaration({
192
+ moduleSpecifier: "react-i18next",
193
+ namedImports: ["useTranslation"]
194
+ });
195
+ } else {
196
+ const namedImports = importDeclaration.getNamedImports().map((i) => i.getName());
197
+ if (!namedImports.includes("useTranslation")) {
198
+ importDeclaration.addNamedImport("useTranslation");
199
+ }
200
+ }
201
+ }
202
+
203
+ // src/core/scanner.ts
204
+ async function scanFilesAndRun() {
205
+ const sourceLang = readConfig("sourceLang") || "pt";
206
+ const targetLangs = readConfig("targetLangs") || ["en"];
207
+ const localesDir = readConfig("localesDir") || "./locales";
208
+ const pendentes = [];
209
+ const stringsUnicas = /* @__PURE__ */ new Set();
210
+ const novasChavesParaSalvar = {};
211
+ const mapaTextoParaChave = {};
212
+ const project = new Project({
213
+ skipAddingFilesFromTsConfig: true
214
+ });
215
+ const spinner = ora2("\u{1F4C2} Carregando e analisando arquivos...").start();
216
+ project.addSourceFilesAtPaths(readConfig("files"));
217
+ const arquivos = project.getSourceFiles();
218
+ for (const arquivo of arquivos) {
219
+ const shouldInject = readConfig("autoInject") || false;
220
+ if (shouldInject) {
221
+ ensureI18nImport(arquivo);
222
+ }
223
+ arquivo.forEachDescendant((node) => {
224
+ if (node.getKind() === SyntaxKind.JsxText) {
225
+ const textoOriginal = node.getText();
226
+ if (textoOriginal.trim().length > 0) {
227
+ pendentes.push({ node, text: textoOriginal.trim() });
228
+ stringsUnicas.add(textoOriginal.trim());
229
+ }
230
+ }
231
+ });
232
+ }
233
+ const fileCount = arquivos.length;
234
+ const strCount = stringsUnicas.size;
235
+ const sFiles = fileCount === 1 ? "" : "s";
236
+ const sStr = strCount === 1 ? "" : "s";
237
+ spinner.succeed(`Encontrado(s) ${chalk.cyan(strCount)} texto${sStr} \xFAnico${sStr} em ${chalk.cyan(fileCount)} arquivo${sFiles}.`);
238
+ const spinnerLLM = ora2(`\u{1F9E0} Gerando chaves inteligentes para ${strCount} textos...`).start();
239
+ const listaParaIA = Array.from(stringsUnicas).map((text, index) => ({
240
+ id: index,
241
+ text
242
+ }));
243
+ const respostaIA = JSON.parse(cleanJsonResponse(await askLLM(createExtractionPrompt(listaParaIA), "json")));
244
+ respostaIA.forEach((item) => {
245
+ const originalText = listaParaIA.find((l) => l.id === item.id)?.text;
246
+ if (originalText) mapaTextoParaChave[originalText] = item.key;
247
+ });
248
+ pendentes.forEach(({ node, text }) => {
249
+ const key = mapaTextoParaChave[text];
250
+ if (key) {
251
+ node.replaceWithText(`{t('${key}')}`);
252
+ }
253
+ });
254
+ project.saveSync();
255
+ spinnerLLM.succeed(chalk.green("C\xF3digo atualizado com as novas chaves i18n!"));
256
+ const spinnerSave = ora2("\u{1F4BE} Gerando arquivos de tradu\xE7\xE3o...").start();
257
+ for (const [textoOriginal, chaveGerada] of Object.entries(mapaTextoParaChave)) {
258
+ novasChavesParaSalvar[chaveGerada] = textoOriginal;
259
+ }
260
+ const pathPt = `${localesDir}/${sourceLang}.json`;
261
+ const jsonPtAtual = lerJson(pathPt);
262
+ const jsonPtFinal = { ...jsonPtAtual, ...novasChavesParaSalvar };
263
+ salvarJson(pathPt, jsonPtFinal);
264
+ for (const idioma of targetLangs) {
265
+ const pathIdioma = `${localesDir}/${idioma}.json`;
266
+ const jsonIdiomaAtual = lerJson(pathIdioma);
267
+ const deltaParaTraduzir = {};
268
+ for (const [key, value] of Object.entries(novasChavesParaSalvar)) {
269
+ if (!jsonIdiomaAtual[key]) {
270
+ deltaParaTraduzir[key] = value;
271
+ }
272
+ }
273
+ if (Object.keys(deltaParaTraduzir).length > 0) {
274
+ const prompt = createTranslationPrompt(deltaParaTraduzir, sourceLang, idioma);
275
+ const respostaIA2 = cleanJsonResponse(await askLLM(prompt, "json"));
276
+ const traducoesEn = JSON.parse(respostaIA2);
277
+ const jsonIdiomaFinal = { ...jsonIdiomaAtual, ...traducoesEn };
278
+ salvarJson(pathIdioma, jsonIdiomaFinal);
279
+ }
280
+ }
281
+ spinnerSave.succeed("Tradu\xE7\xE3o conclu\xEDda e chaves salvas com sucesso!");
282
+ }
283
+
284
+ // src/core/index.ts
285
+ var run = () => {
286
+ scanFilesAndRun();
287
+ };
288
+ var init = () => {
289
+ createConfig();
290
+ };
291
+
292
+ export {
293
+ run,
294
+ init
295
+ };
296
+ //# sourceMappingURL=chunk-RLNUAAKC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/scanner.ts","../src/core/config.ts","../src/core/utils.ts","../src/core/ai.ts","../src/core/dependecies.ts","../src/core/index.ts"],"sourcesContent":["import ora from \"ora\";\nimport { Node, Project, SyntaxKind } from \"ts-morph\";\nimport { readConfig } from \"./config.js\";\nimport { cleanJsonResponse, createExtractionPrompt, createTranslationPrompt, lerJson, salvarJson, type ExtractionItem } from \"./utils.js\";\nimport { askLLM } from \"./ai.js\";\nimport chalk from \"chalk\";\nimport { ensureI18nImport } from \"./dependecies.js\";\n\ninterface JsonTranslation {\n [key: string]: string;\n}\n\nexport async function scanFilesAndRun() {\n const sourceLang = readConfig('sourceLang') || 'pt';\n const targetLangs = readConfig('targetLangs') || ['en'];\n const localesDir = readConfig('localesDir') || './locales';\n\n const pendentes: { node: Node, text: string }[] = [];\n const stringsUnicas = new Set<string>();\n const novasChavesParaSalvar: Record<string, string> = {};\n const mapaTextoParaChave: Record<string, string> = {};\n\n const project = new Project({\n skipAddingFilesFromTsConfig: true,\n });\n\n const spinner = ora(\"📂 Carregando e analisando arquivos...\").start();\n project.addSourceFilesAtPaths(readConfig(\"files\"));\n\n const arquivos = project.getSourceFiles();\n\n for (const arquivo of arquivos) {\n const shouldInject = readConfig(\"autoInject\") || false;\n if(shouldInject) {\n ensureI18nImport(arquivo);\n }\n arquivo.forEachDescendant((node) => {\n if (node.getKind() === SyntaxKind.JsxText) {\n const textoOriginal = node.getText();\n if (textoOriginal.trim().length > 0) {\n pendentes.push({ node, text: textoOriginal.trim() });\n stringsUnicas.add(textoOriginal.trim());\n }\n }\n });\n }\n\n //pluralização elegante\n const fileCount = arquivos.length;\n const strCount = stringsUnicas.size;\n const sFiles = fileCount === 1 ? '' : 's';\n const sStr = strCount === 1 ? '' : 's';\n spinner.succeed(`Encontrado(s) ${chalk.cyan(strCount)} texto${sStr} único${sStr} em ${chalk.cyan(fileCount)} arquivo${sFiles}.`);\n const spinnerLLM = ora(`🧠 Gerando chaves inteligentes para ${strCount} textos...`).start();\n const listaParaIA = Array.from(stringsUnicas).map((text, index) => ({\n id: index,\n text\n })) as ExtractionItem[];\n\n const respostaIA = JSON.parse(cleanJsonResponse(await askLLM(createExtractionPrompt(listaParaIA), 'json')));\n\n respostaIA.forEach((item: any) => {\n const originalText = listaParaIA.find(l => l.id === item.id)?.text;\n if (originalText) mapaTextoParaChave[originalText] = item.key;\n });\n\n pendentes.forEach(({ node, text }) => {\n const key = mapaTextoParaChave[text];\n if (key) {\n node.replaceWithText(`{t('${key}')}`);\n }\n });\n project.saveSync();\n spinnerLLM.succeed(chalk.green(\"Código atualizado com as novas chaves i18n!\"));\n\n const spinnerSave = ora(\"💾 Gerando arquivos de tradução...\").start();\n\n for (const [textoOriginal, chaveGerada] of Object.entries(mapaTextoParaChave)) {\n novasChavesParaSalvar[chaveGerada] = textoOriginal;\n }\n\n const pathPt = `${localesDir}/${sourceLang}.json`;\n const jsonPtAtual = lerJson(pathPt);\n const jsonPtFinal = { ...jsonPtAtual, ...novasChavesParaSalvar };\n\n salvarJson(pathPt, jsonPtFinal);\n\n // Salvar em outros idiomas\n for (const idioma of targetLangs) {\n const pathIdioma = `${localesDir}/${idioma}.json`;\n const jsonIdiomaAtual = lerJson(pathIdioma) as JsonTranslation;\n\n const deltaParaTraduzir: Record<string, string> = {};\n\n for (const [key, value] of Object.entries(novasChavesParaSalvar)) {\n if (!jsonIdiomaAtual[key]) {\n deltaParaTraduzir[key] = value;\n }\n }\n\n if (Object.keys(deltaParaTraduzir).length > 0) {\n const prompt = createTranslationPrompt(deltaParaTraduzir, sourceLang, idioma);\n\n const respostaIA = cleanJsonResponse(await askLLM(prompt, 'json'));\n const traducoesEn = JSON.parse(respostaIA);\n\n const jsonIdiomaFinal = { ...jsonIdiomaAtual, ...traducoesEn };\n salvarJson(pathIdioma, jsonIdiomaFinal);\n }\n }\n\n spinnerSave.succeed('Tradução concluída e chaves salvas com sucesso!');\n}","import fs from \"fs\";\nimport path from \"path\";\nimport ora from \"ora\";\n\nconst configPath = path.join(process.cwd(), \"auto-i18n.config.json\");\n\nexport function readConfig(key: string) {\n if (!fs.existsSync(configPath)) {\n createConfig();\n }\n const config = JSON.parse(fs.readFileSync(configPath, \"utf-8\"));\n return config[key];\n}\n\nexport function createConfig() {\n const spinner = ora('Criando arquivos de configuração...').start();\n const defaultConfig = {\n $schema: `https://unpkg.com/@scopeact/autoi18n@latest/schema.json`,\n sourceLang: \"pt\",\n targetLangs: [\"en\", \"es\"],\n autoInject: false,\n i18nLibrary: \"react-i18next\",\n provider: \"openai\",\n localesDir: \"./locales\",\n model: \"gpt-3.5-turbo\",\n files: [\"src/**/*.tsx\", \"app/**/*.tsx\"]\n };\n\n fs.writeFileSync(configPath, JSON.stringify(defaultConfig, null, 2));\n spinner.succeed();\n}","import fs from 'fs';\nimport path from 'path';\n\nexport interface ExtractionItem {\n id: number;\n text: string;\n}\n\nexport function createExtractionPrompt(itens: ExtractionItem[], contexto?: string): string {\n return `\nVocê é um especialista em i18n. Recebi uma lista de textos de uma interface React.\nSua tarefa é gerar chaves (keys) semânticas e curtas em inglês (snake_case) para cada item.\n\nREGRAS:\n1. Retorne APENAS um array de objetos JSON.\n2. Cada objeto deve ter: \"id\" (o mesmo enviado) e \"key\" (a chave sugerida).\n3. As chaves devem ser curtas (max 4 palavras). \n4. Textos longos devem ter chaves que resumam o sentido.\n\nEXEMPLO DE ENTRADA:\n[ { \"id\": 1, \"text\": \"Salvar alterações\" } ]\n\nEXEMPLO DE SAÍDA:\n[ { \"id\": 1, \"key\": \"button_save_changes\" } ]\n\nITENS PARA PROCESSAR:\n${JSON.stringify(itens, null, 2)}\n\n${contexto ? `Contexto do projeto: ${contexto}` : ''}\n`.trim();\n}\n\nexport function createTranslationPrompt(\n delta: object, \n from: string, \n to: string, \n contexto?: string\n): string {\n return `\nVocê é um tradutor sênior de software especializado em localização (i18n).\nSua tarefa é traduzir os VALORES das novas chaves de interface que foram adicionadas ao projeto.\n\nIDIOMAS: De \"${from}\" para \"${to}\".\n\nREGRAS CRÍTICAS:\n1. MANUTENÇÃO DE CHAVES: Mantenha as chaves (keys) EXATAMENTE como estão. Não as traduza nem as altere.\n2. TRADUÇÃO DE VALORES: Traduza apenas os valores para o idioma de destino.\n3. VARIÁVEIS E PLACEHOLDERS: Preserve placeholders como {{name}}, {0}, %s ou qualquer texto entre chaves. Eles NÃO devem ser traduzidos.\n4. TOM DE VOZ: Use um tom profissional e conciso, adequado para interfaces de usuário (botões, labels, mensagens de erro).\n5. FORMATO: Retorne APENAS o objeto JSON puro, sem explicações ou blocos de código markdown.\n\n${contexto ? `CONTEXTO DO PROJETO: ${contexto}` : ''}\n\nDADOS PARA TRADUZIR:\n${JSON.stringify(delta, null, 2)}\n`.trim();\n}\n\nexport function cleanJsonResponse(text: string): string {\n return text.replace(/```json|```/g, '').trim();\n}\n\nexport function lerJson(caminho: string): object {\n if (!fs.existsSync(caminho)) {\n fs.mkdirSync(path.dirname(caminho), { recursive: true });\n fs.writeFileSync(caminho, '{}');\n return {};\n }\n \n return JSON.parse(fs.readFileSync(caminho, 'utf-8'));\n}\n\nexport function salvarJson(caminho: string, json: object): void {\n if(!fs.existsSync(caminho)) {\n fs.mkdirSync(path.dirname(caminho), { recursive: true });\n }\n fs.writeFileSync(caminho, JSON.stringify(json, null, 2));\n}","import dotenv from 'dotenv';\ndotenv.config();\nimport { OpenAI } from 'openai';\nimport { GoogleGenerativeAI } from '@google/generative-ai';\nimport { readConfig } from \"./config.js\";\n\nexport type AIProvider = 'openai' | 'google' | 'deepseek' | 'openrouter' | 'ollama';\n\nexport async function askLLM(prompt: string, mode = 'text'): Promise<string> {\n const provider = readConfig('provider') || 'openai' as AIProvider;\n const model = readConfig('model');\n checkEnv(provider);\n switch (provider) {\n case 'openai':\n return askOpenAI(prompt, model || 'gpt-4o', mode);\n case 'google':\n return askGemini(prompt, model || 'gemini-2.5-flash', mode);\n case 'deepseek':\n return askDeepSeek(prompt, model || 'deepseek-chat', mode);\n case 'openrouter':\n return askOpenRouter(prompt, model || 'google/gemini-2.0-flash-001', mode);\n case 'ollama':\n return askOllama(prompt, model || 'llama3', mode);\n default:\n throw new Error(`Provedor de IA desconhecido: ${provider}`);\n }\n}\n\nexport function checkEnv(provider: string) {\n if (!process.env[`${provider.toUpperCase()}_API_KEY`]) {\n throw new Error(`${provider.toUpperCase()}_API_KEY não foi definido`);\n }\n}\n\nasync function askOpenAI(prompt: string, model: string, mode: string) {\n const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });\n const response = await openai.chat.completions.create({\n response_format: mode === 'json' ? { type: 'json_object' } : { type: 'text' },\n messages: [{ role: 'user', content: prompt }],\n model,\n });\n return response?.choices?.[0]?.message?.content || '';\n}\n\nasync function askGemini(prompt: string, model: string, mode: string) {\n const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY || '');\n const gemini = genAI.getGenerativeModel({ model, generationConfig: { responseMimeType: mode === 'json' ? 'application/json' : 'text/plain' } });\n const result = await gemini.generateContent(prompt);\n return result.response.text();\n}\n\nasync function askDeepSeek(prompt: string, model: string, mode: string) {\n const client = new OpenAI({\n apiKey: process.env.DEEPSEEK_API_KEY,\n baseURL: 'https://api.deepseek.com'\n });\n const response = await client.chat.completions.create({\n response_format: mode === 'json' ? { type: 'json_object' } : { type: 'text' },\n messages: [{ role: 'user', content: prompt }],\n model,\n });\n return response?.choices?.[0]?.message?.content || '';\n}\n\nasync function askOpenRouter(prompt: string, model: string, mode: string) {\n const client = new OpenAI({\n apiKey: process.env.OPENROUTER_API_KEY,\n baseURL: 'https://openrouter.ai/api/v1',\n defaultHeaders: {\n \"HTTP-Referer\": \"https://github.com/felipevetter/auto-i18n\",\n }\n });\n const response = await client.chat.completions.create({\n response_format: mode === 'json' ? { type: 'json_object' } : { type: 'text' },\n messages: [{ role: 'user', content: prompt }],\n model,\n });\n return response?.choices?.[0]?.message?.content || '';\n}\n\nasync function askOllama(prompt: string, model: string, mode: string) {\n const response = await fetch('http://localhost:11434/api/generate', {\n method: 'POST',\n body: JSON.stringify({\n model,\n prompt,\n format: mode === 'json' ? 'json' : 'text',\n stream: false,\n }),\n });\n const data = await response.json() as { response: string };\n return data.response;\n}","import { SourceFile } from \"ts-morph\";\n\nexport function ensureI18nImport(sourceFile: SourceFile) {\n const importDeclaration = sourceFile.getImportDeclaration(\"react-i18next\");\n \n if (!importDeclaration) {\n sourceFile.addImportDeclaration({\n moduleSpecifier: \"react-i18next\",\n namedImports: [\"useTranslation\"]\n });\n } else {\n const namedImports = importDeclaration.getNamedImports().map(i => i.getName());\n if (!namedImports.includes(\"useTranslation\")) {\n importDeclaration.addNamedImport(\"useTranslation\");\n }\n }\n}","import { scanFilesAndRun } from \"./scanner.js\";\nimport { createConfig } from \"./config.js\";\n\nexport const run = () => {\n scanFilesAndRun();\n};\n\nexport const init = () => {\n createConfig();\n}"],"mappings":"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","names":["ora","fs","path","ora","respostaIA"]}
@@ -0,0 +1,41 @@
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; }// src/runtime/server.ts
2
+ var _promises = require('fs/promises'); var _promises2 = _interopRequireDefault(_promises);
3
+ var _path = require('path'); var _path2 = _interopRequireDefault(_path);
4
+ var _headers = require('next/headers');
5
+ async function detectLocale(sourceLang) {
6
+ const cookieStore = await _headers.cookies.call(void 0, );
7
+ const localeCookie = _optionalChain([cookieStore, 'access', _ => _.get, 'call', _2 => _2("NEXT_LOCALE"), 'optionalAccess', _3 => _3.value]);
8
+ if (localeCookie) return localeCookie;
9
+ const headersList = await _headers.headers.call(void 0, );
10
+ const acceptLanguage = headersList.get("accept-language");
11
+ if (acceptLanguage) {
12
+ return acceptLanguage.split(",")[0].split("-")[0];
13
+ }
14
+ return sourceLang;
15
+ }
16
+ async function getI18nConfig(defaultLang = "en") {
17
+ const locale = await detectLocale(defaultLang);
18
+ const localesDir = _path2.default.join(process.cwd(), "./locales");
19
+ const filePath = _path2.default.join(localesDir, `${locale}.json`);
20
+ let messages = {};
21
+ try {
22
+ const content = await _promises2.default.readFile(filePath, "utf-8");
23
+ messages = JSON.parse(content);
24
+ } catch (err) {
25
+ console.warn(`[auto-i18n] Arquivo de tradu\xE7\xE3o n\xE3o encontrado para: ${locale}`);
26
+ }
27
+ return { locale, messages };
28
+ }
29
+ async function getI18n() {
30
+ const { messages, locale } = await getI18nConfig();
31
+ const t = (key) => {
32
+ return messages[key] || key;
33
+ };
34
+ return { t, locale };
35
+ }
36
+
37
+
38
+
39
+
40
+ exports.getI18nConfig = getI18nConfig; exports.getI18n = getI18n;
41
+ //# sourceMappingURL=chunk-TJT6ONON.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["/home/runner/work/auto-i18n/auto-i18n/packages/autoi18n/dist/chunk-TJT6ONON.cjs","../src/runtime/server.ts"],"names":[],"mappings":"AAAA;ACAA,2FAAe;AACf,wEAAiB;AAGjB,uCAAiC;AAEjC,MAAA,SAAe,YAAA,CAAa,UAAA,EAAoB;AAC5C,EAAA,MAAM,YAAA,EAAc,MAAM,8BAAA,CAAQ;AAClC,EAAA,MAAM,aAAA,kBAAe,WAAA,mBAAY,GAAA,mBAAI,aAAa,CAAA,6BAAG,OAAA;AACrD,EAAA,GAAA,CAAI,YAAA,EAAc,OAAO,YAAA;AAEzB,EAAA,MAAM,YAAA,EAAc,MAAM,8BAAA,CAAQ;AAClC,EAAA,MAAM,eAAA,EAAiB,WAAA,CAAY,GAAA,CAAI,iBAAiB,CAAA;AACxD,EAAA,GAAA,CAAI,cAAA,EAAgB;AAChB,IAAA,OAAO,cAAA,CAAe,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA,CAAE,KAAA,CAAM,GAAG,CAAA,CAAE,CAAC,CAAA;AAAA,EACpD;AAEA,EAAA,OAAO,UAAA;AACX;AAEA,MAAA,SAAsB,aAAA,CAAc,YAAA,EAAsB,IAAA,EAAM;AAC5D,EAAA,MAAM,OAAA,EAAS,MAAM,YAAA,CAAa,WAAW,CAAA;AAE7C,EAAA,MAAM,WAAA,EAAa,cAAA,CAAK,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,CAAA,EAAG,WAAW,CAAA;AACvD,EAAA,MAAM,SAAA,EAAW,cAAA,CAAK,IAAA,CAAK,UAAA,EAAY,CAAA,EAAA;AAEC,EAAA;AACpC,EAAA;AACkC,IAAA;AACL,IAAA;AACnB,EAAA;AACG,IAAA;AACjB,EAAA;AAE0B,EAAA;AAC9B;AAOgC;AACO,EAAA;AAER,EAAA;AACC,IAAA;AAC5B,EAAA;AAEmB,EAAA;AACvB;ADf0C;AACA;AACA;AACA;AACA","file":"/home/runner/work/auto-i18n/auto-i18n/packages/autoi18n/dist/chunk-TJT6ONON.cjs","sourcesContent":[null,"import fs from 'node:fs/promises';\nimport path from 'node:path';\n\n// @ts-ignore\nimport { cookies, headers } from 'next/headers';\n\nasync function detectLocale(sourceLang: string) {\n const cookieStore = await cookies();\n const localeCookie = cookieStore.get('NEXT_LOCALE')?.value;\n if (localeCookie) return localeCookie;\n\n const headersList = await headers();\n const acceptLanguage = headersList.get('accept-language');\n if (acceptLanguage) {\n return acceptLanguage.split(',')[0].split('-')[0];\n }\n\n return sourceLang;\n}\n\nexport async function getI18nConfig(defaultLang: string = \"en\") {\n const locale = await detectLocale(defaultLang);\n\n const localesDir = path.join(process.cwd(), \"./locales\");\n const filePath = path.join(localesDir, `${locale}.json`);\n\n let messages: Record<string, string> = {};\n try {\n const content = await fs.readFile(filePath, 'utf-8');\n messages = JSON.parse(content);\n } catch (err) {\n console.warn(`[auto-i18n] Arquivo de tradução não encontrado para: ${locale}`);\n }\n\n return { locale, messages };\n}\n\n/*\n * Retorna um objeto com a função de tradução e o locale atual.\n * @param defaultLang: { defaultLocale: string }\n * @returns { t: (key: string) => string, locale: string }\n*/\nexport async function getI18n() {\n const { messages, locale } = await getI18nConfig();\n\n const t = (key: string) => {\n return messages[key] || key;\n };\n\n return { t, locale };\n}"]}