Full Polish localization — route remaining hardcoded UI strings through i18n t().

- main.ts: command names (new chat, analyze, re-index) and notices (select text, empty note, indexing, RAG done) now translated
- ChatView.ts: message author label, Copy tooltip, Stop button and 'generation stopped' notice translated
- SettingsTab.ts: external-storage 'no sync', 'Location:' label and folder path placeholder translated
- ProjectsView.ts: project modal title and name placeholder (were hardcoded Polish, broke EN) now react to language
- HistoryManager.ts: default chat title translated (added i18n import)
- i18n.ts: added 14 new keys in both en and pl dictionaries
- Bump version to 1.0.8 (manifest.json, package.json, versions.json)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
JamJan05 2026-06-03 11:59:24 +02:00
parent c5c2ee8a01
commit 4a4ab3e867
9 changed files with 52 additions and 20 deletions

View file

@ -1,7 +1,7 @@
{
"id": "ai-vault",
"name": "AI-Vault",
"version": "1.0.2",
"version": "1.0.8",
"minAppVersion": "1.7.2",
"description": "Chat with GPT and Claude directly inside your notes — RAG from your vault, history, projects and smart modes.",
"author": "JamJan05",

View file

@ -1,6 +1,6 @@
{
"name": "ai-vault",
"version": "1.0.2",
"version": "1.0.8",
"description": "AI-Vault — chat with GPT & Claude inside Obsidian, powered by your vault",
"main": "main.js",
"scripts": {

View file

@ -609,10 +609,10 @@ export class GPTSettingsTab extends PluginSettingTab {
info.empty();
info.createEl("strong", { text: t("settings_storage_active") });
info.createEl("br");
info.appendChild(info.ownerDocument.createTextNode("Obsidian Sync does not sync this data."));
info.appendChild(info.ownerDocument.createTextNode(t("settings_storage_no_sync")));
info.createEl("br");
info.createEl("br");
info.createEl("strong", { text: "Location:" });
info.createEl("strong", { text: t("settings_storage_location") });
info.createEl("br");
const pathEl = info.createEl("code", { text: currentPath });
pathEl.addClass("gpt-settings-storage-path");
@ -641,7 +641,7 @@ export class GPTSettingsTab extends PluginSettingTab {
.setName(t("settings_storage_path_name"))
.setDesc(t("settings_storage_path_desc", defaultPath))
.addText(txt => {
txt.setPlaceholder("/path/to/folder (empty = auto)")
txt.setPlaceholder(t("settings_storage_path_placeholder"))
.setValue(this.plugin.settings.externalStoragePath ?? "")
.setDisabled(!isDesktop);
txt.inputEl.addClass("gpt-settings-input-full");

View file

@ -1,4 +1,5 @@
import { DIR_HISTORY, FILE_HISTORY_INDEX } from "../constants";
import { t } from "../i18n";
import type { ExternalStorage } from "../storage/ExternalStorage";
import type { ChatMessage, ChatSession, SessionMeta } from "../types";
@ -88,7 +89,7 @@ export class HistoryManager {
const now = Date.now();
return {
id: now.toString(),
title: "New conversation",
title: t("chat_default_title"),
createdAt: now,
updatedAt: now,
messages: [],

View file

@ -58,6 +58,9 @@ const en: TranslationDict = {
settings_storage_open_name: "Open folder in explorer",
settings_storage_open_btn: "Open folder",
settings_storage_open_desc: "Shows the history folder in the system file manager.",
settings_storage_no_sync: "Obsidian Sync does not sync this data.",
settings_storage_location: "Location:",
settings_storage_path_placeholder: "/path/to/folder (empty = auto)",
settings_storage_active: "✅ Active — history saved OUTSIDE vault",
settings_storage_inactive: "⚠️ Disabled — history saved inside vault",
settings_storage_inactive_html: "⚠️ <strong>Disabled — history saved inside vault</strong><br>Obsidian Sync may synchronize chat history (uses up your GB limit).",
@ -120,6 +123,9 @@ const en: TranslationDict = {
chat_copy: "Copy",
chat_copied: "Copied!",
chat_interrupted: "⏹ Interrupted by user",
chat_generation_stopped: "⏹ Generation stopped",
chat_role_you: "You",
chat_default_title: "New conversation",
chat_btn_rag: "RAG",
chat_btn_index: "Index",
chat_btn_notes: "Notes",
@ -215,6 +221,9 @@ const en: TranslationDict = {
projects_prompt_hint: "If set, this prompt REPLACES the global system prompt. Leave empty to use the global prompt.",
projects_create_btn: "Create",
projects_custom_prompt_badge:"· ✏️ custom prompt",
projects_modal_new_title: "New project:",
projects_modal_edit_title: (name: string) => `Edit project: ${name}`,
projects_name_placeholder: "Project name…",
// RAG
rag_ready_short: (f: number, e: number) => `🗄️ RAG ready — ${f} notes (${e} embeddings)`,
@ -295,6 +304,12 @@ const en: TranslationDict = {
cmd_open_history: "Open chat history",
cmd_open_projects: "Open projects",
cmd_summarize: "Summarize current note",
cmd_new_chat: "New conversation",
cmd_analyze: "Analyze selected text",
cmd_reindex: "Re-index vault (RAG)",
cmd_select_text_first: "Select text first.",
cmd_note_empty: "Note is empty.",
cmd_indexing: "⏳ Indexing…",
// Quiz
quiz_error: "Error!",
@ -375,6 +390,9 @@ const pl: TranslationDict = {
settings_storage_open_name: "Otwórz folder w eksploratorze",
settings_storage_open_btn: "Otwórz folder",
settings_storage_open_desc: "Pokazuje folder z historią w systemowym menedżerze plików.",
settings_storage_no_sync: "Obsidian Sync nie synchronizuje tych danych.",
settings_storage_location: "Lokalizacja:",
settings_storage_path_placeholder: "/ścieżka/do/folderu (puste = auto)",
settings_storage_active: "✅ Aktywny — historia zapisywana POZA vaultem",
settings_storage_inactive: "⚠️ Wyłączony — historia zapisywana w vaulcie",
settings_storage_inactive_html: "⚠️ <strong>Wyłączony — historia zapisywana w vaulcie</strong><br>Obsidian Sync może synchronizować historię rozmów (zjada limit GB).",
@ -437,6 +455,9 @@ const pl: TranslationDict = {
chat_copy: "Kopiuj",
chat_copied: "Skopiowano!",
chat_interrupted: "⏹ Przerwane przez użytkownika",
chat_generation_stopped: "⏹ Przerwano generowanie",
chat_role_you: "Ty",
chat_default_title: "Nowa rozmowa",
chat_btn_rag: "RAG",
chat_btn_index: "Indeksuj",
chat_btn_notes: "Notatki",
@ -532,6 +553,9 @@ const pl: TranslationDict = {
projects_prompt_hint: "Gdy ustawisz ten prompt, ZASTĄPI on globalny prompt systemowy. Jeśli zostawisz puste — użyty będzie domyślny prompt.",
projects_create_btn: "Utwórz",
projects_custom_prompt_badge:"· ✏️ własny prompt",
projects_modal_new_title: "Nowy projekt:",
projects_modal_edit_title: (name: string) => `Edytuj projekt: ${name}`,
projects_name_placeholder: "Nazwa projektu…",
// RAG
rag_ready_short: (f: number, e: number) => `🗄️ RAG gotowy — ${f} notatek (${e} embeddingów)`,
@ -612,6 +636,12 @@ const pl: TranslationDict = {
cmd_open_history: "Otwórz historię rozmów",
cmd_open_projects: "Otwórz projekty",
cmd_summarize: "Podsumuj aktualną notatkę",
cmd_new_chat: "Nowa rozmowa",
cmd_analyze: "Analizuj zaznaczony tekst",
cmd_reindex: "Przeindeksuj vault (RAG)",
cmd_select_text_first: "Najpierw zaznacz tekst.",
cmd_note_empty: "Notatka jest pusta.",
cmd_indexing: "⏳ Indeksowanie…",
// Quiz
quiz_error: "Błąd!",

View file

@ -82,14 +82,14 @@ export default class GPTPlugin extends Plugin {
this.addCommand({ id: "open-gpt-chat", name: t("cmd_open_chat"), callback: () => void this.activateChatView() });
this.addCommand({ id: "open-gpt-history", name: t("cmd_open_history"), callback: () => void this.activateHistoryView() });
this.addCommand({ id: "open-gpt-projects", name: t("cmd_open_projects"),callback: () => void this.activateProjectsView() });
this.addCommand({ id: "new-gpt-chat", name: "New conversation", callback: () => this.newChat() });
this.addCommand({ id: "new-gpt-chat", name: t("cmd_new_chat"), callback: () => this.newChat() });
this.addCommand({
id: "analyze-selection",
name: "Analyze selected text",
name: t("cmd_analyze"),
editorCallback: async editor => {
const sel = editor.getSelection();
if (!sel) { new Notice("Select text first."); return; }
if (!sel) { new Notice(t("cmd_select_text_first")); return; }
const view = await this.activateChatView();
await new Promise(r => window.setTimeout(r, 300));
void view?.sendMessage(`Analyze:\n\n${sel}`);
@ -101,7 +101,7 @@ export default class GPTPlugin extends Plugin {
name: t("cmd_summarize"),
editorCallback: async editor => {
const c = editor.getValue();
if (!c.trim()) { new Notice("Note is empty."); return; }
if (!c.trim()) { new Notice(t("cmd_note_empty")); return; }
const view = await this.activateChatView();
await new Promise(r => window.setTimeout(r, 300));
void view?.sendMessage(`Summarize in 5 points:\n\n${c.slice(0, 8000)}`);
@ -110,12 +110,12 @@ export default class GPTPlugin extends Plugin {
this.addCommand({
id: "reindex-vault",
name: "Re-index vault (RAG)",
name: t("cmd_reindex"),
callback: async () => {
new Notice("⏳ Indexing…");
new Notice(t("cmd_indexing"));
await this.rag.buildIndex();
const s = this.rag.stats;
new Notice(`✅ RAG: ${s.files} notes`);
new Notice(t("rag_done", s.files));
},
});

View file

@ -1172,9 +1172,9 @@ export class GPTChatView extends ItemView {
// Footer with copy button
const footer = msgEl.createEl("div", { cls: "gpt-msg-footer" });
const assistLabel = this.getProviderLabel(this.getEffectiveProvider());
footer.createEl("span", { cls: "gpt-msg-label", text: role === "user" ? "You" : assistLabel });
footer.createEl("span", { cls: "gpt-msg-label", text: role === "user" ? t("chat_role_you") : assistLabel });
const copyBtn = footer.createEl("button", { cls: "gpt-copy-btn", attr: { title: "Copy", "aria-label": "Copy" } });
const copyBtn = footer.createEl("button", { cls: "gpt-copy-btn", attr: { title: t("chat_copy"), "aria-label": t("chat_copy") } });
this.setButtonIcon(copyBtn, "copy");
copyBtn.onclick = async () => {
await navigator.clipboard.writeText(bubble.dataset.raw ?? contentEl.innerText);
@ -1209,11 +1209,11 @@ export class GPTChatView extends ItemView {
if (this.stopBtn) return;
this.stopBtn = this.sendBtn.parentElement!.createEl("button", {
cls: "gpt-stop-btn",
text: "⏹ Stop",
text: `${t("chat_stop")}`,
});
this.stopBtn.onclick = () => {
this.abortController?.abort();
new Notice("⏹ Generation stopped");
new Notice(t("chat_generation_stopped"));
};
this.sendBtn.addClass("gpt-ctx-hidden");
} else {

View file

@ -252,12 +252,12 @@ export class GPTProjectsView extends ItemView {
box.createEl("p", {
cls: "gpt-modal-title",
text: isEdit ? `Edytuj projekt: ${editProject!.name}` : "Nowy projekt:",
text: isEdit ? t("projects_modal_edit_title", editProject!.name) : t("projects_modal_new_title"),
});
const nameInput = box.createEl("input", {
cls: "gpt-modal-input",
attr: { type: "text", placeholder: "Nazwa projektu…" },
attr: { type: "text", placeholder: t("projects_name_placeholder") },
}) as HTMLInputElement;
if (isEdit) nameInput.value = editProject!.name;

View file

@ -1,4 +1,5 @@
{
"1.0.0": "1.4.0",
"1.0.2": "1.7.2"
"1.0.2": "1.7.2",
"1.0.8": "1.7.2"
}