mirror of
https://github.com/vrtmrz/obsidian-livesync.git
synced 2026-08-29 06:47:06 +00:00
refactor(i18n): route remaining Obsidian UI text through the message catalogue
Continues the source-key migration inside the application boundary introduced in 1.0.0, where LiveSync owns its catalogue and consumes Commonlib as a published package. - Replace hardcoded user-visible strings in the Obsidian UI (Setup Wizard dialogues, P2P panes, Customisation Sync panes, Global History, the JSON conflict pane and the remote-configuration menu) with `$msg` calls, keeping the English source string as the key. - Wire up strings whose translations already existed in the catalogue but were still rendered as literals, for example the whole Intro dialogue. - Add the new entries to `src/common/messagesYAML/en.yaml` and `es.yaml`, then regenerate `messagesJson/` and `combinedMessages.prod.ts` through the documented `i18n:bake` pipeline. - No Commonlib gitlink or catalogue is involved; every change is LiveSync-owned. Regenerating the catalogue also normalises three pre-existing entries each in `ko.json` and `zh.json`, where the committed JSON kept a trailing space before a newline that YAML cannot represent. Verified with tsc-check, tsc-check:apps, svelte-check and lint. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1362,7 +1362,7 @@ export class ConfigSync extends LiveSyncCommands {
|
||||
async storeCustomizationFiles(path: FilePath, termOverRide?: string) {
|
||||
const term = termOverRide || this.services.setting.getDeviceAndVaultName();
|
||||
if (term == "") {
|
||||
this._log("We have to configure the device name", LOG_LEVEL_NOTICE);
|
||||
this._log($msg("We have to configure the device name"), LOG_LEVEL_NOTICE);
|
||||
return;
|
||||
}
|
||||
if (this.useV2) {
|
||||
@@ -1552,7 +1552,7 @@ export class ConfigSync extends LiveSyncCommands {
|
||||
this._log("Scanning customizing files.", logLevel, "scan-all-config");
|
||||
const term = this.services.setting.getDeviceAndVaultName();
|
||||
if (term == "") {
|
||||
this._log("We have to configure the device name", LOG_LEVEL_NOTICE);
|
||||
this._log($msg("We have to configure the device name"), LOG_LEVEL_NOTICE);
|
||||
return;
|
||||
}
|
||||
const filesAll = await this.scanInternalFiles();
|
||||
@@ -1729,7 +1729,11 @@ export class ConfigSync extends LiveSyncCommands {
|
||||
|
||||
if (mode == "CUSTOMIZE") {
|
||||
if (!this.services.setting.getDeviceAndVaultName()) {
|
||||
let name = await this.core.confirm.askString("Device name", "Please set this device name", `desktop`);
|
||||
let name = await this.core.confirm.askString(
|
||||
$msg("Device name"),
|
||||
$msg("Please set this device name"),
|
||||
`desktop`
|
||||
);
|
||||
if (!name) {
|
||||
if (Platform.isAndroidApp) {
|
||||
name = "android-app";
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
import type ObsidianLiveSyncPlugin from "@/main";
|
||||
// import { askString } from "../../common/utils";
|
||||
import { Menu } from "@/deps.ts";
|
||||
import { $msg as translateMessage } from "@/common/translation";
|
||||
|
||||
export let list: IPluginDataExDisplay[] = [];
|
||||
export let thisTerm = "";
|
||||
@@ -61,25 +62,25 @@
|
||||
// NO OP. what's happened?
|
||||
freshness = "";
|
||||
} else if (local && !remote) {
|
||||
freshness = "Local only";
|
||||
freshness = translateMessage("Local only");
|
||||
} else if (remote && !local) {
|
||||
freshness = "Remote only";
|
||||
freshness = translateMessage("Remote only");
|
||||
canApply = true;
|
||||
} else {
|
||||
const dtDiff = (local?.mtime ?? 0) - (remote?.mtime ?? 0);
|
||||
const diff = timeDeltaToHumanReadable(Math.abs(dtDiff));
|
||||
if (dtDiff / 1000 < -10) {
|
||||
// freshness = "✓ Newer";
|
||||
freshness = `Newer (${diff})`;
|
||||
freshness = translateMessage("Newer (${diff})", { diff });
|
||||
canApply = true;
|
||||
contentCheck = true;
|
||||
} else if (dtDiff / 1000 > 10) {
|
||||
// freshness = "⚠ Older";
|
||||
freshness = `Older (${diff})`;
|
||||
freshness = translateMessage("Older (${diff})", { diff });
|
||||
canApply = true;
|
||||
contentCheck = true;
|
||||
} else {
|
||||
freshness = "Same";
|
||||
freshness = translateMessage("Same");
|
||||
canApply = false;
|
||||
contentCheck = true;
|
||||
}
|
||||
@@ -89,11 +90,17 @@
|
||||
if (local?.version || remote?.version) {
|
||||
const compare = `${localVersionStr}`.localeCompare(remoteVersionStr, undefined, { numeric: true });
|
||||
if (compare == 0) {
|
||||
version = "Same";
|
||||
version = translateMessage("Same");
|
||||
} else if (compare < 0) {
|
||||
version = `Lower (${localVersionStr} < ${remoteVersionStr})`;
|
||||
version = translateMessage("Lower (${local} < ${remote})", {
|
||||
local: localVersionStr,
|
||||
remote: remoteVersionStr,
|
||||
});
|
||||
} else if (compare > 0) {
|
||||
version = `Higher (${localVersionStr} > ${remoteVersionStr})`;
|
||||
version = translateMessage("Higher (${local} > ${remote})", {
|
||||
local: localVersionStr,
|
||||
remote: remoteVersionStr,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,19 +142,19 @@
|
||||
})
|
||||
.reduce((p, c) => p | (c as number), 0 as number);
|
||||
if (matchingStatus == 0b0000100) {
|
||||
equivalency = "Same";
|
||||
equivalency = translateMessage("Same");
|
||||
canApply = false;
|
||||
} else if (matchingStatus <= 0b0000100) {
|
||||
equivalency = "Same or local only";
|
||||
equivalency = translateMessage("Same or local only");
|
||||
canApply = false;
|
||||
} else if (matchingStatus == 0b0010000) {
|
||||
canApply = true;
|
||||
canCompare = true;
|
||||
equivalency = "Different";
|
||||
equivalency = translateMessage("Different");
|
||||
} else {
|
||||
canApply = true;
|
||||
canCompare = true;
|
||||
equivalency = "Mixed";
|
||||
equivalency = translateMessage("Mixed");
|
||||
}
|
||||
return { equivalency, canApply, canCompare };
|
||||
}
|
||||
@@ -244,7 +251,7 @@
|
||||
if (selected == "") {
|
||||
// NO OP.
|
||||
} else if (selected == thisTerm) {
|
||||
freshness = "This device";
|
||||
freshness = translateMessage("This device");
|
||||
canApply = false;
|
||||
} else {
|
||||
const local = list.find((e) => e.term == thisTerm);
|
||||
@@ -304,11 +311,11 @@
|
||||
if (!local) return;
|
||||
if (!selectedItem) return;
|
||||
const menu = new Menu();
|
||||
menu.addItem((item) => item.setTitle("Compare file").setIsLabel(true));
|
||||
menu.addItem((item) => item.setTitle(translateMessage("Compare file")).setIsLabel(true));
|
||||
menu.addSeparator();
|
||||
const files = unique(local.files.map((e) => e.filename).concat(selectedItem.files.map((e) => e.filename)));
|
||||
const convDate = (dt: PluginDataExFile | undefined) => {
|
||||
if (!dt) return "(Missing)";
|
||||
if (!dt) return translateMessage("(Missing)");
|
||||
const d = new Date(dt.mtime);
|
||||
return d.toLocaleString();
|
||||
};
|
||||
@@ -335,10 +342,14 @@
|
||||
Logger(`Could not find local item`, LOG_LEVEL_VERBOSE);
|
||||
return;
|
||||
}
|
||||
const duplicateTermName = await core.confirm.askString("Duplicate", "device name", "");
|
||||
const duplicateTermName = await core.confirm.askString(
|
||||
translateMessage("Duplicate"),
|
||||
translateMessage("device name"),
|
||||
""
|
||||
);
|
||||
if (duplicateTermName) {
|
||||
if (duplicateTermName.contains("/")) {
|
||||
Logger(`We can not use "/" to the device name`, LOG_LEVEL_NOTICE);
|
||||
Logger(translateMessage('We can not use "/" to the device name'), LOG_LEVEL_NOTICE);
|
||||
return;
|
||||
}
|
||||
const key = `${plugin.core.services.API.getSystemConfigDir()}/${local.files[0].filename}`;
|
||||
@@ -391,7 +402,7 @@
|
||||
{/if}
|
||||
{:else}
|
||||
<span class="spacer"></span>
|
||||
<span class="message even">All the same or non-existent</span>
|
||||
<span class="message even">{translateMessage("All the same or non-existent")}</span>
|
||||
<!-- svelte-ignore a11y_consider_explicit_label -->
|
||||
<button disabled></button>
|
||||
<!-- svelte-ignore a11y_consider_explicit_label -->
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
import { HiddenFileSync } from "@/features/HiddenFileSync/CmdHiddenFileSync.ts";
|
||||
import { LOG_LEVEL_NOTICE, Logger } from "octagonal-wheels/common/logger";
|
||||
import type { LiveSyncBaseCore } from "@/LiveSyncBaseCore.ts";
|
||||
import { $msg as translateMessage } from "@/common/translation";
|
||||
export let plugin: ObsidianLiveSyncPlugin;
|
||||
export let core :LiveSyncBaseCore;
|
||||
// $: core = plugin.core;
|
||||
@@ -32,15 +33,17 @@
|
||||
|
||||
const addOn = core.getAddOn<ConfigSync>(ConfigSync.name)!;
|
||||
if (!addOn) {
|
||||
const msg =
|
||||
"AddOn Module (ConfigSync) has not been loaded. This is very unexpected situation. Please report this issue.";
|
||||
const msg = translateMessage(
|
||||
"AddOn Module (ConfigSync) has not been loaded. This is very unexpected situation. Please report this issue."
|
||||
);
|
||||
Logger(msg, LOG_LEVEL_NOTICE);
|
||||
throw new Error(msg);
|
||||
}
|
||||
const addOnHiddenFileSync = core.getAddOn<HiddenFileSync>(HiddenFileSync.name) as HiddenFileSync;
|
||||
if (!addOnHiddenFileSync) {
|
||||
const msg =
|
||||
"AddOn Module (HiddenFileSync) has not been loaded. This is very unexpected situation. Please report this issue.";
|
||||
const msg = translateMessage(
|
||||
"AddOn Module (HiddenFileSync) has not been loaded. This is very unexpected situation. Please report this issue."
|
||||
);
|
||||
Logger(msg, LOG_LEVEL_NOTICE);
|
||||
throw new Error(msg);
|
||||
}
|
||||
@@ -92,9 +95,9 @@
|
||||
}
|
||||
|
||||
const displays = {
|
||||
CONFIG: "Configuration",
|
||||
THEME: "Themes",
|
||||
SNIPPET: "Snippets",
|
||||
CONFIG: translateMessage("Configuration"),
|
||||
THEME: translateMessage("Themes"),
|
||||
SNIPPET: translateMessage("Snippets"),
|
||||
};
|
||||
async function scanAgain() {
|
||||
await addOn.scanAllConfigFiles(true);
|
||||
@@ -156,20 +159,20 @@
|
||||
}
|
||||
function askOverwriteModeForAutomatic(evt: MouseEvent, key: string) {
|
||||
const menu = new Menu();
|
||||
menu.addItem((item) => item.setTitle("Initial Action").setIsLabel(true));
|
||||
menu.addItem((item) => item.setTitle(translateMessage("Initial Action")).setIsLabel(true));
|
||||
menu.addSeparator();
|
||||
menu.addItem((item) => {
|
||||
item.setTitle(`↑: Overwrite Remote`).onClick((e) => {
|
||||
item.setTitle(translateMessage("↑: Overwrite Remote")).onClick((e) => {
|
||||
applyAutomaticSync(key, "pushForce");
|
||||
});
|
||||
})
|
||||
.addItem((item) => {
|
||||
item.setTitle(`↓: Overwrite Local`).onClick((e) => {
|
||||
item.setTitle(translateMessage("↓: Overwrite Local")).onClick((e) => {
|
||||
applyAutomaticSync(key, "pullForce");
|
||||
});
|
||||
})
|
||||
.addItem((item) => {
|
||||
item.setTitle(`⇅: Use newer`).onClick((e) => {
|
||||
item.setTitle(translateMessage("⇅: Use newer")).onClick((e) => {
|
||||
applyAutomaticSync(key, "safe");
|
||||
});
|
||||
});
|
||||
@@ -201,10 +204,10 @@
|
||||
[MODE_SHINY]: ICON_EMOJI_FLAGGED,
|
||||
};
|
||||
const TITLES: { [key: number]: string } = {
|
||||
[MODE_SELECTIVE]: "Selective",
|
||||
[MODE_PAUSED]: "Ignore",
|
||||
[MODE_AUTOMATIC]: "Automatic",
|
||||
[MODE_SHINY]: "Flagged Selective",
|
||||
[MODE_SELECTIVE]: translateMessage("Selective"),
|
||||
[MODE_PAUSED]: translateMessage("Ignore"),
|
||||
[MODE_AUTOMATIC]: translateMessage("Automatic"),
|
||||
[MODE_SHINY]: translateMessage("Flagged Selective"),
|
||||
};
|
||||
const PREFIX_PLUGIN_ALL = "PLUGIN_ALL";
|
||||
const PREFIX_PLUGIN_DATA = "PLUGIN_DATA";
|
||||
@@ -329,28 +332,30 @@
|
||||
|
||||
<div class="buttonsWrap">
|
||||
<div class="buttons">
|
||||
<button on:click={() => scanAgain()}>Scan changes</button>
|
||||
<button on:click={() => replicate()}>Sync once</button>
|
||||
<button on:click={() => requestUpdate()}>Refresh</button>
|
||||
<button on:click={() => scanAgain()}>{translateMessage("Scan changes")}</button>
|
||||
<button on:click={() => replicate()}>{translateMessage("Sync once")}</button>
|
||||
<button on:click={() => requestUpdate()}>{translateMessage("Refresh")}</button>
|
||||
{#if isMaintenanceMode}
|
||||
<button on:click={() => requestReload()}>Reload</button>
|
||||
<button on:click={() => requestReload()}>{translateMessage("Reload")}</button>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<button on:click={() => selectAllNewest(true)}>Select All Shiny</button>
|
||||
<button on:click={() => selectAllNewest(false)}>{ICON_EMOJI_FLAGGED} Select Flagged Shiny</button>
|
||||
<button on:click={() => resetSelectNewest()}>Deselect all</button>
|
||||
<button on:click={() => applyAll()} class="mod-cta">Apply All Selected</button>
|
||||
<button on:click={() => selectAllNewest(true)}>{translateMessage("Select All Shiny")}</button>
|
||||
<button on:click={() => selectAllNewest(false)}
|
||||
>{ICON_EMOJI_FLAGGED} {translateMessage("Select Flagged Shiny")}</button
|
||||
>
|
||||
<button on:click={() => resetSelectNewest()}>{translateMessage("Deselect all")}</button>
|
||||
<button on:click={() => applyAll()} class="mod-cta">{translateMessage("Apply All Selected")}</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="loading">
|
||||
{#if loading || $pluginV2Progress !== 0}
|
||||
<span>Updating list...{$pluginV2Progress == 0 ? "" : ` (${$pluginV2Progress})`}</span>
|
||||
<span>{translateMessage("Updating list...")}{$pluginV2Progress == 0 ? "" : ` (${$pluginV2Progress})`}</span>
|
||||
{/if}
|
||||
</div>
|
||||
<div class="list">
|
||||
{#if list.length == 0}
|
||||
<div class="center">No Items.</div>
|
||||
<div class="center">{translateMessage("No Items.")}</div>
|
||||
{:else}
|
||||
{#each displayEntries as [key, label]}
|
||||
<div>
|
||||
@@ -382,7 +387,7 @@
|
||||
</div>
|
||||
{/each}
|
||||
<div>
|
||||
<h3>Plugins</h3>
|
||||
<h3>{translateMessage("Plugins")}</h3>
|
||||
{#each pluginEntries as [name, listX]}
|
||||
{@const bindKeyAll = `${PREFIX_PLUGIN_ALL}/${name}`}
|
||||
{@const modeAll = automaticListDisp.get(bindKeyAll) ?? MODE_SELECTIVE}
|
||||
@@ -464,7 +469,7 @@
|
||||
>
|
||||
{getIcon(modeEtc)}
|
||||
</button>
|
||||
<span class="name">Other files</span>
|
||||
<span class="name">{translateMessage("Other files")}</span>
|
||||
</div>
|
||||
<div class="body">
|
||||
{#if modeEtc == MODE_SELECTIVE || modeEtc == MODE_SHINY}
|
||||
@@ -492,9 +497,9 @@
|
||||
{#if isMaintenanceMode}
|
||||
<div class="buttons">
|
||||
<div>
|
||||
<h3>Maintenance Commands</h3>
|
||||
<h3>{translateMessage("Maintenance Commands")}</h3>
|
||||
<div class="maintenancerow">
|
||||
<label for="">Delete All of </label>
|
||||
<label for="">{translateMessage("Delete All of")} </label>
|
||||
<select bind:value={deleteTerm}>
|
||||
{#each allTerms as term}
|
||||
<option value={term}>{term}</option>
|
||||
@@ -513,10 +518,20 @@
|
||||
</div>
|
||||
{/if}
|
||||
<div class="buttons">
|
||||
<label><span>Hide not applicable items</span><input type="checkbox" bind:checked={hideEven} /></label>
|
||||
<label
|
||||
><span>{translateMessage("Hide not applicable items")}</span><input
|
||||
type="checkbox"
|
||||
bind:checked={hideEven}
|
||||
/></label
|
||||
>
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<label><span>Maintenance mode</span><input type="checkbox" bind:checked={isMaintenanceMode} /></label>
|
||||
<label
|
||||
><span>{translateMessage("Maintenance mode")}</span><input
|
||||
type="checkbox"
|
||||
bind:checked={isMaintenanceMode}
|
||||
/></label
|
||||
>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
|
||||
Reference in New Issue
Block a user