diff --git a/CHANGELOG.md b/CHANGELOG.md index eb99f34..e572ccc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.2.1] — 2026-07-13 + +- Usage details are added to the Translation complete notification + ## [1.2.0] — 2026-06-24 - The plugin interface is translated into 11 languages diff --git a/README.md b/README.md index a633509..f3cb201 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,10 @@ Combined with AI Glossaries, they give much more control over localization quali Manage your saved linguistic Instructions at [l10n.dev/ws/linguistic-instructions](https://l10n.dev/ws/linguistic-instructions). +## AI Localization Agent + +Turn your coding agent into a localization specialist. Add our MCP server to GitHub Copilot, Cursor, Claude, Codex, or Windsurf and let your agent translate i18n files without dumping unnecessary data to its context. See [AI Localization Agent Setup Guide](https://l10n.dev/help/ai-localization-agent) + ## Localization The plugin interface is translated into the following languages: diff --git a/manifest.json b/manifest.json index 2bf8d0c..3ec5b64 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "note-ai-translator", "name": "L10n.dev - AI Translator", - "version": "1.2.0", + "version": "1.2.1", "minAppVersion": "1.1.7", "description": "Translate notes into any of 165 languages with AI. Preserves Markdown formatting and structure. Powered by L10n.dev's AI translation API. Supports json, yaml, other plain-text formats.", "author": "l10n.dev", diff --git a/package-lock.json b/package-lock.json index 316725a..5db4149 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "obsidian-plugin-ai-translator", - "version": "1.2.0", + "version": "1.2.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "obsidian-plugin-ai-translator", - "version": "1.2.0", + "version": "1.2.1", "license": "MIT", "dependencies": { "obsidian": "latest" diff --git a/package.json b/package.json index 0d70a74..2eefcae 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "obsidian-plugin-ai-translator", - "version": "1.2.0", + "version": "1.2.1", "description": "Obsidian plugin to translate notes with AI using l10n.dev", "main": "main.js", "type": "module", diff --git a/src/i18n/de.json b/src/i18n/de.json index f5eed99..dab58f6 100644 --- a/src/i18n/de.json +++ b/src/i18n/de.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "Ungültiger API-Schlüssel. Erhalten Sie Ihren Schlüssel unter {{url}}", "noticeInsufficientBalance": "Guthaben nicht ausreichend. Laden Sie es unter {{url}} auf.", "noticeTranslationFailed": "Übersetzung fehlgeschlagen. Bitte versuchen Sie es erneut.", - "noticeTranslationComplete": "Übersetzung abgeschlossen. {{count}} Zeichen verwendet.", + "noticeTranslationComplete": "Übersetzung abgeschlossen. Es wurden {{count}} Zeichen verwendet (Inhalt {{sourceCount}}, Lexikon {{glossaryCount}}, Anweisung {{instructionCount}}, Terminologie {{terminologyCount}})", "noticeRemainingBalance": " {{count}} Zeichen verbleibend.", "noticeSaveFailed": "Übersetzte Notiz konnte nicht gespeichert werden.", "noticeSetApiKey": "Bitte legen Sie Ihren l10n.dev API-Schlüssel in den Einstellungen fest.", @@ -39,4 +39,4 @@ "modalPlaceholderDefault": "Geben Sie einen Sprachennamen ein (z. B. Spanisch, Deutsch)...", "modalSuggestion": "{{name}} — {{code}}", "modalLastUsedBadge": "Zuletzt verwendet" -} \ No newline at end of file +} diff --git a/src/i18n/en.json b/src/i18n/en.json index 89fd815..fc36ea8 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "Invalid API key. Get your key at {{url}}", "noticeInsufficientBalance": "Insufficient balance. Top up at {{url}}", "noticeTranslationFailed": "Translation failed. Please try again.", - "noticeTranslationComplete": "Translation complete. Used {{count}} characters.", + "noticeTranslationComplete": "Translation complete. Used {{count}} characters (content {{sourceCount}}, glossary {{glossaryCount}}, instruction {{instructionCount}}, terminology {{terminologyCount}})", "noticeRemainingBalance": " {{count}} characters remaining.", "noticeSaveFailed": "Failed to save the translated note.", "noticeSetApiKey": "Please set your l10n.dev API key in settings.", diff --git a/src/i18n/es.json b/src/i18n/es.json index bfe2828..566762d 100644 --- a/src/i18n/es.json +++ b/src/i18n/es.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "API key no válida. Obtén tu clave en {{url}}", "noticeInsufficientBalance": "Saldo insuficiente. Recarga en {{url}}", "noticeTranslationFailed": "Error en la traducción. Por favor, inténtalo de nuevo.", - "noticeTranslationComplete": "Traducción completada. Se han utilizado {{count}} caracteres.", + "noticeTranslationComplete": "Traducción completada. Se utilizaron {{count}} caracteres (contenido {{sourceCount}}, glosario {{glossaryCount}}, instrucción {{instructionCount}}, terminología {{terminologyCount}})", "noticeRemainingBalance": " {{count}} caracteres restantes.", "noticeSaveFailed": "Error al guardar la nota traducida.", "noticeSetApiKey": "Por favor, configura tu API key de l10n.dev en los ajustes.", diff --git a/src/i18n/fr.json b/src/i18n/fr.json index 34cd30e..3fbd086 100644 --- a/src/i18n/fr.json +++ b/src/i18n/fr.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "Clé API invalide. Obtenez votre clé sur {{url}}", "noticeInsufficientBalance": "Solde insuffisant. Rechargez sur {{url}}", "noticeTranslationFailed": "La traduction a échoué. Veuillez réessayer.", - "noticeTranslationComplete": "Traduction terminée. {{count}} caractères utilisés.", + "noticeTranslationComplete": "Traduction terminée. Utilisé {{count}} caractères (contenu {{sourceCount}}, glossaire {{glossaryCount}}, instruction {{instructionCount}}, terminologie {{terminologyCount}})", "noticeRemainingBalance": " {{count}} caractères restants.", "noticeSaveFailed": "Échec de l'enregistrement de la note traduite.", "noticeSetApiKey": "Veuillez définir votre clé API l10n.dev dans les paramètres.", diff --git a/src/i18n/id.json b/src/i18n/id.json index cb5defa..354ff47 100644 --- a/src/i18n/id.json +++ b/src/i18n/id.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "API key tidak valid. Dapatkan key Anda di {{url}}", "noticeInsufficientBalance": "Saldo tidak mencukupi. Isi ulang di {{url}}", "noticeTranslationFailed": "Terjemahan gagal. Silakan coba lagi.", - "noticeTranslationComplete": "Terjemahan selesai. Menggunakan {{count}} karakter.", + "noticeTranslationComplete": "Terjemahan selesai. Menggunakan {{count}} karakter (konten {{sourceCount}}, glosarium {{glossaryCount}}, instruksi {{instructionCount}}, terminologi {{terminologyCount}})", "noticeRemainingBalance": " {{count}} karakter tersisa.", "noticeSaveFailed": "Gagal menyimpan catatan yang diterjemahkan.", "noticeSetApiKey": "Harap atur API key l10n.dev Anda di pengaturan.", diff --git a/src/i18n/it.json b/src/i18n/it.json index c52ea8a..204bc65 100644 --- a/src/i18n/it.json +++ b/src/i18n/it.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "Chiave API non valida. Ottieni la tua chiave su {{url}}", "noticeInsufficientBalance": "Saldo insufficiente. Ricarica su {{url}}", "noticeTranslationFailed": "Traduzione non riuscita. Riprova.", - "noticeTranslationComplete": "Traduzione completata. Utilizzati {{count}} caratteri.", + "noticeTranslationComplete": "Traduzione completata. Utilizzati {{count}} caratteri (contenuto {{sourceCount}}, glossario {{glossaryCount}}, istruzione {{instructionCount}}, terminologia {{terminologyCount}})", "noticeRemainingBalance": " {{count}} caratteri rimanenti.", "noticeSaveFailed": "Salvataggio della nota tradotta non riuscito.", "noticeSetApiKey": "Imposta la tua chiave API l10n.dev nelle impostazioni.", diff --git a/src/i18n/ja.json b/src/i18n/ja.json index e53f33b..5be064d 100644 --- a/src/i18n/ja.json +++ b/src/i18n/ja.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "無効なAPIキーです。キーの取得はこちら: {{url}}", "noticeInsufficientBalance": "残高不足です。チャージはこちら: {{url}}", "noticeTranslationFailed": "翻訳に失敗しました。もう一度お試しください。", - "noticeTranslationComplete": "翻訳が完了しました。{{count}}文字使用しました。", + "noticeTranslationComplete": "翻訳が完了しました。{{count}}文字を使用しました(コンテンツ {{sourceCount}}、用語集 {{glossaryCount}}、指示 {{instructionCount}}、用語 {{terminologyCount}})", "noticeRemainingBalance": " 残り{{count}}文字です。", "noticeSaveFailed": "翻訳されたノートの保存に失敗しました。", "noticeSetApiKey": "設定でl10n.devのAPIキーを設定してください。", diff --git a/src/i18n/ko.json b/src/i18n/ko.json index 2f199d5..0925257 100644 --- a/src/i18n/ko.json +++ b/src/i18n/ko.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "유효하지 않은 API 키입니다. 다음에서 키를 발급받으세요: {{url}}", "noticeInsufficientBalance": "잔액이 부족합니다. 다음에서 충전하세요: {{url}}", "noticeTranslationFailed": "번역에 실패했습니다. 다시 시도해 주세요.", - "noticeTranslationComplete": "번역이 완료되었습니다. {{count}} 문자가 사용되었습니다.", + "noticeTranslationComplete": "번역이 완료되었습니다. {{count}}개의 문자를 사용했습니다 (콘텐츠 {{sourceCount}}, 용어집 {{glossaryCount}}, 지침 {{instructionCount}}, 용어 {{terminologyCount}})", "noticeRemainingBalance": " {{count}} 문자 남음.", "noticeSaveFailed": "번역된 노트를 저장하지 못했습니다.", "noticeSetApiKey": "설정에서 l10n.dev API 키를 설정해 주세요.", diff --git a/src/i18n/pt.json b/src/i18n/pt.json index e318568..79fbb65 100644 --- a/src/i18n/pt.json +++ b/src/i18n/pt.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "Chave de API inválida. Obtenha sua chave em {{url}}", "noticeInsufficientBalance": "Saldo insuficiente. Recarregue em {{url}}", "noticeTranslationFailed": "Falha na tradução. Tente novamente.", - "noticeTranslationComplete": "Tradução concluída. {{count}} caracteres usados.", + "noticeTranslationComplete": "Tradução concluída. Foram usados {{count}} caracteres (conteúdo {{sourceCount}}, glossário {{glossaryCount}}, instrução {{instructionCount}}, terminologia {{terminologyCount}})", "noticeRemainingBalance": " {{count}} caracteres restantes.", "noticeSaveFailed": "Falha ao salvar a nota traduzida.", "noticeSetApiKey": "Por favor, defina sua chave de API l10n.dev nas configurações.", diff --git a/src/i18n/zh-CN.json b/src/i18n/zh-CN.json index 38c7b49..43ca442 100644 --- a/src/i18n/zh-CN.json +++ b/src/i18n/zh-CN.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "API密钥无效。请在 {{url}} 获取您的密钥", "noticeInsufficientBalance": "余额不足。请在 {{url}} 充值", "noticeTranslationFailed": "翻译失败。请重试。", - "noticeTranslationComplete": "翻译完成。已使用 {{count}} 个字符。", + "noticeTranslationComplete": "翻译完成。已使用 {{count}} 个字符(内容 {{sourceCount}},词汇表 {{glossaryCount}},指令 {{instructionCount}},术语 {{terminologyCount}})", "noticeRemainingBalance": " 剩余 {{count}} 个字符。", "noticeSaveFailed": "保存翻译后的笔记失败。", "noticeSetApiKey": "请在设置中配置您的l10n.dev API密钥。", @@ -39,4 +39,4 @@ "modalPlaceholderDefault": "输入语言名称(例如:西班牙语、德语)...", "modalSuggestion": "{{name}} — {{code}}", "modalLastUsedBadge": "上次使用" -} \ No newline at end of file +} diff --git a/src/i18n/zh-TW.json b/src/i18n/zh-TW.json index 54dd752..606c376 100644 --- a/src/i18n/zh-TW.json +++ b/src/i18n/zh-TW.json @@ -30,7 +30,7 @@ "noticeInvalidKey": "API 金鑰無效。請至 {{url}} 取得您的金鑰", "noticeInsufficientBalance": "餘額不足。請至 {{url}} 加值", "noticeTranslationFailed": "翻譯失敗。請再試一次。", - "noticeTranslationComplete": "翻譯完成。已使用 {{count}} 字元。", + "noticeTranslationComplete": "翻譯完成。已使用 {{count}} 個字元(內容 {{sourceCount}}、詞彙表 {{glossaryCount}}、指令 {{instructionCount}}、術語 {{terminologyCount}})", "noticeRemainingBalance": "剩餘 {{count}} 字元。", "noticeSaveFailed": "儲存翻譯後的筆記失敗。", "noticeSetApiKey": "請在設定中設定您的 l10n.dev API 金鑰。", @@ -39,4 +39,4 @@ "modalPlaceholderDefault": "輸入語言名稱(例如:西班牙語、德語)...", "modalSuggestion": "{{name}} — {{code}}", "modalLastUsedBadge": "上次使用" -} \ No newline at end of file +} diff --git a/src/translator.ts b/src/translator.ts index 48b02ea..8fba2ea 100644 --- a/src/translator.ts +++ b/src/translator.ts @@ -1,7 +1,7 @@ import { Notice, TFile } from "obsidian"; import { LanguageSuggestModal } from "./LanguageSuggestModal"; import { TranslationService } from "./TranslationService"; -import { Language, PluginWithSettings } from "./types"; +import { Language, PluginWithSettings, TranslationUsage } from "./types"; import { t, localizeUrl, getLocale, URLS } from "./i18n"; const FRONTMATTER_REGEX = /^(---\r?\n[\s\S]*?\r?\n---\r?\n?)([\s\S]*)$/; @@ -38,7 +38,15 @@ async function doTranslate( } let translated: string; - let charsUsed = 0; + let usage: TranslationUsage = { + charsUsed: 0, + details: { + sourceStringsCharCount: 0, + terminologyCharCount: 0, + glossaryCharCount: 0, + instructionCharCount: 0, + }, + }; let remainingBalance: number | null | undefined; const progressNotice = new Notice(t("noticeTranslating"), 0); try { @@ -55,7 +63,7 @@ async function doTranslate( }, ); translated = result.translations; - charsUsed = result.usage.charsUsed; + usage = result.usage; remainingBalance = result.remainingBalance; } catch (err) { progressNotice.hide(); @@ -111,8 +119,18 @@ async function doTranslate( : ""; new Notice( t("noticeTranslationComplete", { - count: charsUsed.toLocaleString(), - }) + balanceText, + count: usage.charsUsed.toLocaleString(), + sourceCount: + usage.details.sourceStringsCharCount.toLocaleString(), + glossaryCount: usage.details.glossaryCharCount.toLocaleString(), + instructionCount: + usage.details.instructionCharCount.toLocaleString(), + terminologyCount: + usage.details.terminologyCharCount.toLocaleString(), + }) + + "\r\n\r\n" + + balanceText, + 20000, ); } catch { new Notice(t("noticeSaveFailed")); diff --git a/src/types.ts b/src/types.ts index e70f46c..59f41d0 100644 --- a/src/types.ts +++ b/src/types.ts @@ -23,10 +23,20 @@ export interface TranslateRequest { client?: string; } +export interface TranslationUsage { + charsUsed: number; + details: { + sourceStringsCharCount: number; + terminologyCharCount: number; + glossaryCharCount: number; + instructionCharCount: number; + }; +} + export interface TranslateResponse { translations: string; finishReason: string; - usage: { charsUsed: number }; + usage: TranslationUsage; remainingBalance?: number | null; } diff --git a/versions.json b/versions.json index 8f5c910..24a41f5 100644 --- a/versions.json +++ b/versions.json @@ -7,5 +7,6 @@ "1.1.0": "0.15.0", "1.1.1": "1.1.7", "1.1.2": "1.1.7", - "1.2.0": "1.1.7" + "1.2.0": "1.1.7", + "1.2.1": "1.1.7" }