mirror of
https://github.com/svemagie/obsidian-micropub.git
synced 2026-05-14 19:38:50 +02:00
build: rebuild main.js and add i18n plan doc
This commit is contained in:
@@ -0,0 +1,526 @@
|
||||
# i18n (en + de) Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Add English and German translations to obsidian-micropub by extracting all hardcoded UI strings into locale files and wiring them through a tiny `t()` helper.
|
||||
|
||||
**Architecture:** A `src/i18n.ts` module exports a single `t(key, vars?)` function that reads `window.moment.locale()` (Obsidian's own locale) at call time, looks up the key in the matching locale map (falling back to `en`), and does `{var}` substitution. Locale maps live in `src/lang/en.ts` and `src/lang/de.ts`. No external dependencies, no build changes.
|
||||
|
||||
**Tech Stack:** TypeScript, Obsidian API (`window.moment.locale()`), esbuild (existing)
|
||||
|
||||
---
|
||||
|
||||
## File Map
|
||||
|
||||
| Action | Path | Responsibility |
|
||||
|--------|------|---------------|
|
||||
| Create | `src/lang/en.ts` | English string map (source of truth) |
|
||||
| Create | `src/lang/de.ts` | German string map |
|
||||
| Create | `src/i18n.ts` | `t()` helper — locale detection + lookup + interpolation |
|
||||
| Modify | `src/main.ts` | Replace hardcoded strings with `t()` calls |
|
||||
| Modify | `src/SettingsTab.ts` | Replace hardcoded strings with `t()` calls |
|
||||
| Modify | `src/SyndicationDialog.ts` | Replace hardcoded strings with `t()` calls |
|
||||
| Modify | `src/IndieAuth.ts` | Replace one hardcoded error string with `t()` call |
|
||||
| Modify | `README.md` | Note i18n support under Configuration |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: English locale file
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lang/en.ts`
|
||||
|
||||
- [ ] **Step 1: Create `src/lang/en.ts` with all UI strings**
|
||||
|
||||
```typescript
|
||||
// src/lang/en.ts
|
||||
export const en: Record<string, string> = {
|
||||
// Commands & ribbon
|
||||
cmdPublish: "Publish to Micropub",
|
||||
cmdUpdate: "Update existing Micropub post",
|
||||
|
||||
// Notices — main.ts
|
||||
noticeOpenNote: "Open a Markdown note to publish.",
|
||||
noticeNoEndpoint: "⚠️ Micropub endpoint not configured. Open plugin settings to add it.",
|
||||
noticeNoToken: "⚠️ Access token not configured. Open plugin settings to add it.",
|
||||
noticePublishing: "Publishing…",
|
||||
noticePublished: "✅ Published!",
|
||||
noticePublishFailed: "❌ Publish failed: {error}",
|
||||
noticeError: "❌ Error: {error}",
|
||||
noticeNoSyndTargets: "⚠️ Could not fetch syndication targets. Publishing without dialog.",
|
||||
|
||||
// Settings headings
|
||||
settingsTitle: "Micropub Publisher",
|
||||
settingsAccount: "Account",
|
||||
settingsEndpoints: "Endpoints",
|
||||
settingsEndpointsHint: "These are filled automatically when you sign in. Only edit them manually if your server uses non-standard paths.",
|
||||
settingsPublishBehaviour:"Publish Behaviour",
|
||||
settingsDigitalGarden: "Digital Garden",
|
||||
|
||||
// Settings — endpoints
|
||||
settingMicropubEndpoint: "Micropub endpoint",
|
||||
settingMicropubEndpointDesc: "e.g. https://example.com/micropub", // intentional: replaces personal domain in source
|
||||
settingMediaEndpoint: "Media endpoint",
|
||||
settingMediaEndpointDesc:"For image uploads. Auto-discovered if blank.",
|
||||
|
||||
// Settings — publish behaviour
|
||||
settingVisibility: "Default visibility",
|
||||
settingVisibilityDesc: "Applies when the note has no explicit visibility property.",
|
||||
visibilityPublic: "Public",
|
||||
visibilityUnlisted: "Unlisted",
|
||||
visibilityPrivate: "Private",
|
||||
|
||||
settingWriteUrl: "Write URL back to note",
|
||||
settingWriteUrlDesc: "After publishing, store the post URL as `mp-url` in frontmatter. Subsequent publishes will update the existing post instead of creating a new one.",
|
||||
|
||||
settingSyndDialog: "Syndication dialog",
|
||||
settingSyndDialogDesc: "When to show the cross-posting dialog before publishing. 'When needed' shows it only if the note has no mp-syndicate-to frontmatter.",
|
||||
syndDialogWhenNeeded: "When needed",
|
||||
syndDialogAlways: "Always",
|
||||
syndDialogNever: "Never",
|
||||
|
||||
settingSyndDefaults: "Default syndication targets",
|
||||
settingSyndDefaultsNone: "None configured. Targets checked by default in the publish dialog.",
|
||||
btnClearDefaults: "Clear defaults",
|
||||
|
||||
// Settings — digital garden
|
||||
settingGardenTags: "Map #garden/* tags to gardenStage",
|
||||
settingGardenTagsDesc: "Obsidian tags like #garden/plant become a `garden-stage: plant` Micropub property. The blog renders these as growth stage badges at /garden/.",
|
||||
settingGardenStages: "Stages: plant 🌱 · cultivate 🌿 · question ❓ · repot 🪴 · revitalize ✨ · revisit 🔄",
|
||||
|
||||
// Settings — sign-in / sign-out
|
||||
settingSiteUrl: "Site URL",
|
||||
settingSiteUrlDesc: "Your site's home page. Clicking Sign in opens your blog's login page in the browser — the same flow iA Writer uses.",
|
||||
settingSiteUrlPlaceholder: "https://example.com", // intentional: replaces personal domain in source
|
||||
btnSignIn: "Sign in",
|
||||
btnOpeningBrowser: "Opening browser…",
|
||||
noticeEnterSiteUrl: "Enter your site URL first.",
|
||||
noticeSignedInAs: "✅ Signed in as {me}",
|
||||
noticeSignInFailed: "Sign-in failed: {error}",
|
||||
lblSignedIn: "Signed in",
|
||||
btnSignOut: "Sign out",
|
||||
manualTokenSummary: "Or paste a token manually",
|
||||
settingAccessToken: "Access token",
|
||||
settingAccessTokenDesc: "Bearer token from your Indiekit admin panel.",
|
||||
btnVerify: "Verify",
|
||||
noticeSetEndpointFirst: "Set the Micropub endpoint and token first.",
|
||||
noticeTokenValid: "✅ Token is valid!",
|
||||
noticeTokenCheckFailed: "Token check failed: {error}",
|
||||
|
||||
// Syndication dialog
|
||||
syndDialogTitle: "Syndication targets",
|
||||
syndDialogSubtitle: "Choose where to cross-post this note.",
|
||||
btnCancel: "Cancel",
|
||||
btnPublish: "Publish",
|
||||
|
||||
// IndieAuth
|
||||
errSignInTimeout: "Sign-in timed out (5 min). Please try again.",
|
||||
};
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Build to confirm no TypeScript errors**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub" && npm run build
|
||||
```
|
||||
Expected: exits 0.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub"
|
||||
git add src/lang/en.ts
|
||||
git commit -m "feat(i18n): add English locale file with all UI strings"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: German locale file
|
||||
|
||||
**Files:**
|
||||
- Create: `src/lang/de.ts`
|
||||
|
||||
- [ ] **Step 1: Create `src/lang/de.ts`**
|
||||
|
||||
```typescript
|
||||
// src/lang/de.ts
|
||||
export const de: Record<string, string> = {
|
||||
// Commands & ribbon
|
||||
cmdPublish: "An Micropub veröffentlichen",
|
||||
cmdUpdate: "Bestehenden Micropub-Beitrag aktualisieren",
|
||||
|
||||
// Notices — main.ts
|
||||
noticeOpenNote: "Öffne eine Markdown-Notiz zum Veröffentlichen.",
|
||||
noticeNoEndpoint: "⚠️ Micropub-Endpunkt nicht konfiguriert. Bitte in den Plugin-Einstellungen eintragen.",
|
||||
noticeNoToken: "⚠️ Zugriffstoken nicht konfiguriert. Bitte in den Plugin-Einstellungen eintragen.",
|
||||
noticePublishing: "Wird veröffentlicht…",
|
||||
noticePublished: "✅ Veröffentlicht!",
|
||||
noticePublishFailed: "❌ Veröffentlichung fehlgeschlagen: {error}",
|
||||
noticeError: "❌ Fehler: {error}",
|
||||
noticeNoSyndTargets: "⚠️ Syndizierungsziele konnten nicht abgerufen werden. Veröffentlichung ohne Dialog.",
|
||||
|
||||
// Settings headings
|
||||
settingsTitle: "Micropub Publisher",
|
||||
settingsAccount: "Konto",
|
||||
settingsEndpoints: "Endpunkte",
|
||||
settingsEndpointsHint: "Diese werden beim Anmelden automatisch ausgefüllt. Nur manuell bearbeiten, wenn der Server nicht standardmäßige Pfade verwendet.",
|
||||
settingsPublishBehaviour:"Veröffentlichungsverhalten",
|
||||
settingsDigitalGarden: "Digitaler Garten",
|
||||
|
||||
// Settings — endpoints
|
||||
settingMicropubEndpoint: "Micropub-Endpunkt",
|
||||
settingMicropubEndpointDesc: "z. B. https://example.com/micropub",
|
||||
settingMediaEndpoint: "Medien-Endpunkt",
|
||||
settingMediaEndpointDesc:"Für Bild-Uploads. Wird automatisch ermittelt, wenn leer.",
|
||||
|
||||
// Settings — publish behaviour
|
||||
settingVisibility: "Standard-Sichtbarkeit",
|
||||
settingVisibilityDesc: "Gilt, wenn die Notiz keine explizite Sichtbarkeits-Eigenschaft hat.",
|
||||
visibilityPublic: "Öffentlich",
|
||||
visibilityUnlisted: "Nicht gelistet",
|
||||
visibilityPrivate: "Privat",
|
||||
|
||||
settingWriteUrl: "URL zurück in Notiz schreiben",
|
||||
settingWriteUrlDesc: "Nach der Veröffentlichung wird die Beitrags-URL als `mp-url` im Frontmatter gespeichert. Spätere Veröffentlichungen aktualisieren den Beitrag statt einen neuen zu erstellen.",
|
||||
|
||||
settingSyndDialog: "Syndizierungsdialog",
|
||||
settingSyndDialogDesc: "Wann der Dialog zum Querverweis vor der Veröffentlichung angezeigt wird. 'Bei Bedarf' zeigt ihn nur, wenn kein mp-syndicate-to im Frontmatter vorhanden ist.",
|
||||
syndDialogWhenNeeded: "Bei Bedarf",
|
||||
syndDialogAlways: "Immer",
|
||||
syndDialogNever: "Nie",
|
||||
|
||||
settingSyndDefaults: "Standard-Syndizierungsziele",
|
||||
settingSyndDefaultsNone: "Keine konfiguriert. Im Veröffentlichungsdialog standardmäßig aktivierte Ziele.",
|
||||
btnClearDefaults: "Standards löschen",
|
||||
|
||||
// Settings — digital garden
|
||||
settingGardenTags: "#garden/*-Tags zu gardenStage zuordnen",
|
||||
settingGardenTagsDesc: "Obsidian-Tags wie #garden/plant werden zur Micropub-Eigenschaft `garden-stage: plant`. Der Blog zeigt diese als Wachstumsstufen-Abzeichen unter /garden/ an.",
|
||||
settingGardenStages: "Stufen: plant 🌱 · cultivate 🌿 · question ❓ · repot 🪴 · revitalize ✨ · revisit 🔄",
|
||||
|
||||
// Settings — sign-in / sign-out
|
||||
settingSiteUrl: "Website-URL",
|
||||
settingSiteUrlDesc: "Startseite deiner Website. Klick auf Anmelden öffnet die Login-Seite deines Blogs im Browser.",
|
||||
settingSiteUrlPlaceholder: "https://example.com",
|
||||
btnSignIn: "Anmelden",
|
||||
btnOpeningBrowser: "Browser wird geöffnet…",
|
||||
noticeEnterSiteUrl: "Bitte zuerst die Website-URL eingeben.",
|
||||
noticeSignedInAs: "✅ Angemeldet als {me}",
|
||||
noticeSignInFailed: "Anmeldung fehlgeschlagen: {error}",
|
||||
lblSignedIn: "Angemeldet",
|
||||
btnSignOut: "Abmelden",
|
||||
manualTokenSummary: "Oder Token manuell einfügen",
|
||||
settingAccessToken: "Zugriffstoken",
|
||||
settingAccessTokenDesc: "Bearer-Token aus deinem Indiekit-Adminbereich.",
|
||||
btnVerify: "Prüfen",
|
||||
noticeSetEndpointFirst: "Bitte zuerst Micropub-Endpunkt und Token eingeben.",
|
||||
noticeTokenValid: "✅ Token ist gültig!",
|
||||
noticeTokenCheckFailed: "Token-Prüfung fehlgeschlagen: {error}",
|
||||
|
||||
// Syndication dialog
|
||||
syndDialogTitle: "Syndizierungsziele",
|
||||
syndDialogSubtitle: "Wo soll diese Notiz gleichzeitig veröffentlicht werden?",
|
||||
btnCancel: "Abbrechen",
|
||||
btnPublish: "Veröffentlichen",
|
||||
|
||||
// IndieAuth
|
||||
errSignInTimeout: "Anmeldung abgelaufen (5 Min.). Bitte erneut versuchen.",
|
||||
};
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Build**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub" && npm run build
|
||||
```
|
||||
Expected: exits 0.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub"
|
||||
git add src/lang/de.ts
|
||||
git commit -m "feat(i18n): add German locale file"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: i18n helper
|
||||
|
||||
**Files:**
|
||||
- Create: `src/i18n.ts`
|
||||
|
||||
- [ ] **Step 1: Create `src/i18n.ts`**
|
||||
|
||||
```typescript
|
||||
// src/i18n.ts
|
||||
import { en } from "./lang/en";
|
||||
import { de } from "./lang/de";
|
||||
|
||||
const locales: Record<string, Record<string, string>> = { en, de };
|
||||
|
||||
/**
|
||||
* Returns the translated string for `key` in the active Obsidian locale.
|
||||
* Falls back to English if the locale or key is missing.
|
||||
*
|
||||
* Supports `{var}` interpolation:
|
||||
* t("noticePublishFailed", { error: "500" })
|
||||
* → "❌ Publish failed: 500"
|
||||
*/
|
||||
export function t(key: string, vars?: Record<string, string>): string {
|
||||
const lang = (window.moment?.locale() ?? "en").split("-")[0];
|
||||
const map = locales[lang] ?? locales["en"];
|
||||
let str = map[key] ?? locales["en"][key] ?? key;
|
||||
|
||||
if (vars) {
|
||||
for (const [k, v] of Object.entries(vars)) {
|
||||
str = str.split(`{${k}}`).join(v); // replaceAll not available in ES2018
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Build**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub" && npm run build
|
||||
```
|
||||
Expected: exits 0.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub"
|
||||
git add src/i18n.ts
|
||||
git commit -m "feat(i18n): add t() helper with locale detection and interpolation"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Wire `t()` into `main.ts`
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/main.ts`
|
||||
|
||||
- [ ] **Step 1: Add import and replace all strings**
|
||||
|
||||
At the top of `main.ts`, add:
|
||||
```typescript
|
||||
import { t } from "./i18n";
|
||||
```
|
||||
|
||||
Then replace each hardcoded string:
|
||||
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `"Publish to Micropub"` (command name, line 36) | `t("cmdPublish")` |
|
||||
| `"Update existing Micropub post"` (line 49) | `t("cmdUpdate")` |
|
||||
| `"Publish to Micropub"` (ribbon tooltip, line 75) | `t("cmdPublish")` |
|
||||
| `"Open a Markdown note to publish."` (line 78) | `t("noticeOpenNote")` |
|
||||
| `"⚠️ Micropub endpoint not configured…"` (line 93) | `t("noticeNoEndpoint")` |
|
||||
| `"⚠️ Access token not configured…"` (line 100) | `t("noticeNoToken")` |
|
||||
| `"Publishing…"` (line 114) | `t("noticePublishing")` |
|
||||
| `` `✅ Published!${urlDisplay}` `` (line 126) | `` `${t("noticePublished")}${urlDisplay}` `` |
|
||||
| `` `❌ Publish failed: ${result.error}` `` (line 128) | `t("noticePublishFailed", { error: result.error ?? "" })` |
|
||||
| `` `❌ Error: ${msg}` `` (line 134) | `t("noticeError", { error: msg })` |
|
||||
| `"⚠️ Could not fetch syndication targets…"` (line 167) | `t("noticeNoSyndTargets")` |
|
||||
|
||||
- [ ] **Step 2: Build**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub" && npm run build
|
||||
```
|
||||
Expected: exits 0.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub"
|
||||
git add src/main.ts
|
||||
git commit -m "feat(i18n): wire t() into main.ts"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Wire `t()` into `SettingsTab.ts`
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/SettingsTab.ts`
|
||||
|
||||
- [ ] **Step 1: Add import**
|
||||
|
||||
```typescript
|
||||
import { t } from "./i18n";
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Replace strings in `display()`**
|
||||
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `"Micropub Publisher"` (h2) | `t("settingsTitle")` |
|
||||
| `"Account"` (h3) | `t("settingsAccount")` |
|
||||
| `"Endpoints"` (h3) | `t("settingsEndpoints")` |
|
||||
| `"These are filled automatically…"` (p) | `t("settingsEndpointsHint")` |
|
||||
| `"Micropub endpoint"` (setName) | `t("settingMicropubEndpoint")` |
|
||||
| `"e.g. https://blog.giersig.eu/micropub"` (setDesc) | `t("settingMicropubEndpointDesc")` |
|
||||
| `"Media endpoint"` (setName) | `t("settingMediaEndpoint")` |
|
||||
| `"For image uploads…"` (setDesc) | `t("settingMediaEndpointDesc")` |
|
||||
| `"Publish Behaviour"` (h3) | `t("settingsPublishBehaviour")` |
|
||||
| `"Default visibility"` (setName) | `t("settingVisibility")` |
|
||||
| `"Applies when the note…"` (setDesc) | `t("settingVisibilityDesc")` |
|
||||
| `"Public"` | `t("visibilityPublic")` |
|
||||
| `"Unlisted"` | `t("visibilityUnlisted")` |
|
||||
| `"Private"` | `t("visibilityPrivate")` |
|
||||
| `"Write URL back to note"` (setName) | `t("settingWriteUrl")` |
|
||||
| `"After publishing, store…"` (setDesc) | `t("settingWriteUrlDesc")` |
|
||||
| `"Syndication dialog"` (setName) | `t("settingSyndDialog")` |
|
||||
| `"When to show the cross-posting…"` (setDesc) | `t("settingSyndDialogDesc")` |
|
||||
| `"When needed"` | `t("syndDialogWhenNeeded")` |
|
||||
| `"Always"` | `t("syndDialogAlways")` |
|
||||
| `"Never"` | `t("syndDialogNever")` |
|
||||
| `"Default syndication targets"` (setName) | `t("settingSyndDefaults")` |
|
||||
| `"None configured…"` (false branch of setDesc — when `defaults.length === 0`) | `t("settingSyndDefaultsNone")` |
|
||||
| `"Clear defaults"` (btn) | `t("btnClearDefaults")` |
|
||||
| `"Digital Garden"` (h3) | `t("settingsDigitalGarden")` |
|
||||
| `"Map #garden/* tags…"` (setName) | `t("settingGardenTags")` |
|
||||
| `"Obsidian tags like…"` (setDesc) | `t("settingGardenTagsDesc")` |
|
||||
| `"Stages: plant 🌱…"` (p) | `t("settingGardenStages")` |
|
||||
|
||||
- [ ] **Step 3: Replace strings in `renderSignedOut()`**
|
||||
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `"Site URL"` (setName) | `t("settingSiteUrl")` |
|
||||
| `"Your site's home page…"` (setDesc) | `t("settingSiteUrlDesc")` |
|
||||
| `"https://blog.giersig.eu"` (placeholder) | `t("settingSiteUrlPlaceholder")` |
|
||||
| `"Sign in"` (btn) | `t("btnSignIn")` |
|
||||
| `"Enter your site URL first."` (Notice) | `t("noticeEnterSiteUrl")` |
|
||||
| `"Opening browser…"` (btn) | `t("btnOpeningBrowser")` |
|
||||
| `` `✅ Signed in as ${result.me}` `` | `t("noticeSignedInAs", { me: result.me })` |
|
||||
| `` `Sign-in failed: ${String(err)}` `` | `t("noticeSignInFailed", { error: String(err) })` |
|
||||
| `"Sign in"` (catch btn reset) | `t("btnSignIn")` |
|
||||
| `"Or paste a token manually"` (summary) | `t("manualTokenSummary")` |
|
||||
| `"Access token"` (setName) | `t("settingAccessToken")` |
|
||||
| `"Bearer token from your Indiekit admin panel."` (setDesc) | `t("settingAccessTokenDesc")` |
|
||||
| `"Verify"` (btn) | `t("btnVerify")` |
|
||||
| `"Set the Micropub endpoint and token first."` (Notice) | `t("noticeSetEndpointFirst")` |
|
||||
| `"✅ Token is valid!"` (Notice) | `t("noticeTokenValid")` |
|
||||
| `` `Token check failed: ${String(err)}` `` | `t("noticeTokenCheckFailed", { error: String(err) })` |
|
||||
|
||||
- [ ] **Step 4: Replace strings in `renderSignedIn()`**
|
||||
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `"Signed in"` (label) | `t("lblSignedIn")` |
|
||||
| `"Site URL"` (setName) | `t("settingSiteUrl")` |
|
||||
| `"Sign out"` (btn) | `t("btnSignOut")` |
|
||||
|
||||
- [ ] **Step 5: Build**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub" && npm run build
|
||||
```
|
||||
Expected: exits 0.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub"
|
||||
git add src/SettingsTab.ts
|
||||
git commit -m "feat(i18n): wire t() into SettingsTab.ts"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Wire `t()` into `SyndicationDialog.ts` and `IndieAuth.ts`
|
||||
|
||||
**Files:**
|
||||
- Modify: `src/SyndicationDialog.ts`
|
||||
- Modify: `src/IndieAuth.ts`
|
||||
|
||||
- [ ] **Step 1: Update `SyndicationDialog.ts`**
|
||||
|
||||
Add import:
|
||||
```typescript
|
||||
import { t } from "./i18n";
|
||||
```
|
||||
|
||||
Replace:
|
||||
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `"Syndication targets"` (h2) | `t("syndDialogTitle")` |
|
||||
| `"Choose where to cross-post this note."` (p) | `t("syndDialogSubtitle")` |
|
||||
| `"Cancel"` (btn) | `t("btnCancel")` |
|
||||
| `"Publish"` (btn) | `t("btnPublish")` |
|
||||
|
||||
- [ ] **Step 2: Update `IndieAuth.ts`**
|
||||
|
||||
Add import at top:
|
||||
```typescript
|
||||
import { t } from "./i18n";
|
||||
```
|
||||
|
||||
Replace:
|
||||
|
||||
| Old | New |
|
||||
|-----|-----|
|
||||
| `"Sign-in timed out (5 min). Please try again."` | `t("errSignInTimeout")` |
|
||||
|
||||
- [ ] **Step 3: Build**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub" && npm run build
|
||||
```
|
||||
Expected: exits 0.
|
||||
|
||||
- [ ] **Step 4: Commit**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub"
|
||||
git add src/SyndicationDialog.ts src/IndieAuth.ts
|
||||
git commit -m "feat(i18n): wire t() into SyndicationDialog and IndieAuth"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 7: README update
|
||||
|
||||
**Files:**
|
||||
- Modify: `README.md`
|
||||
|
||||
- [ ] **Step 1: Add i18n note to Configuration section**
|
||||
|
||||
After the Settings reference table, add:
|
||||
|
||||
```markdown
|
||||
### Language
|
||||
|
||||
The plugin follows Obsidian's display language. Set it in **Settings → About → Language**. Currently supported: English (`en`), German (`de`).
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Add `SyndicationDialog.ts` already done in prior session (verify)**
|
||||
|
||||
Architecture table should already show `SyndicationDialog.ts` from the prior README update.
|
||||
|
||||
- [ ] **Step 3: Commit**
|
||||
|
||||
```bash
|
||||
cd "/Users/sven/PARA/1. Projects/obsidian-micropub"
|
||||
git add README.md
|
||||
git commit -m "docs: note i18n support (en/de) in README"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Manual verification checklist
|
||||
|
||||
After all tasks, load the plugin in Obsidian and verify:
|
||||
|
||||
- [ ] With Obsidian in English: all UI labels, notices, and dialog text appear in English
|
||||
- [ ] With Obsidian in German (`de`): all UI labels, notices, and dialog text appear in German
|
||||
- [ ] Publishing a note shows the correct locale notice (`Publishing…` / `Wird veröffentlicht…`)
|
||||
- [ ] The syndication dialog title and buttons are translated
|
||||
- [ ] Sign-in flow button text and error notices are translated
|
||||
- [ ] Switching locale and restarting Obsidian picks up the new language
|
||||
Reference in New Issue
Block a user