Merge pull request #1123 from nimula/fix/settings-manifest-translator

Wire the display-language translator into the settings manifest
This commit is contained in:
vorotamoroz
2026-08-21 17:25:13 +09:00
committed by GitHub
4 changed files with 127 additions and 6 deletions
@@ -4,7 +4,8 @@ import {
TweakValuesShouldMatchedTemplate,
TweakValuesTemplate,
IncompatibleChanges,
confName,
configurationNames,
statusDisplay,
type TweakValues,
type ObsidianLiveSyncSettings,
type RemoteDBSettings,
@@ -15,11 +16,21 @@ import {
} from "@vrtmrz/livesync-commonlib/compat/common/types";
import { escapeMarkdownValue } from "@vrtmrz/livesync-commonlib/compat/common/utils";
import { AbstractModule } from "@/modules/AbstractModule.ts";
import { $msg } from "@/common/translation";
import { $msg, translateIfAvailable } from "@/common/translation";
import type { InjectableServiceHub } from "@vrtmrz/livesync-commonlib/compat/services/implements/injectable/InjectableServiceHub";
import type { LiveSyncCore } from "@/main.ts";
import { REMOTE_P2P } from "@vrtmrz/livesync-commonlib/compat/common/models/setting.const";
/**
* Localised counterpart of Commonlib's `confName()`, which takes no translator.
* Same shape: label plus status suffix, and an empty string for an unknown key.
*/
function localisedConfName(key: keyof ObsidianLiveSyncSettings): string {
const info = configurationNames[key];
if (!info) return "";
return `${translateIfAvailable(info.name)}${statusDisplay(info.status)}`;
}
function valueToString(value: string | number | boolean | object | undefined): string {
if (typeof value === "boolean") {
return value ? "true" : "false";
@@ -158,7 +169,7 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule {
// table += `| ${confName(key)} | ${valueMine} | ${valuePreferred} | \n`;
tableRows.push(
$msg("TweakMismatchResolve.Table.Row", {
name: confName(key),
name: localisedConfName(key),
self: valueToString(valueMine),
remote: valueToString(valuePreferred),
})
@@ -342,7 +353,7 @@ export class ModuleResolvingMismatchedTweaks extends AbstractModule {
}
tableRows.push(
$msg("TweakMismatchResolve.Table.Row", {
name: confName(key),
name: localisedConfName(key),
self: currentValueForDisplay,
remote: remoteValueForDisplay,
})
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from "vitest";
import { afterEach, describe, expect, it, vi } from "vitest";
import {
DEFAULT_SETTINGS,
REMOTE_COUCHDB,
@@ -6,6 +6,7 @@ import {
type TweakValues,
} from "@vrtmrz/livesync-commonlib/compat/common/types";
import { ModuleResolvingMismatchedTweaks } from "./ModuleResolveMismatchedTweaks";
import { setLang } from "@/common/translation";
function createModule(settingsOverride: Partial<typeof DEFAULT_SETTINGS> = {}) {
const askSelectStringDialogue = vi.fn(async (..._args: unknown[]): Promise<string | undefined> => undefined);
@@ -255,3 +256,43 @@ describe("ModuleResolvingMismatchedTweaks", () => {
expect(calls).toEqual(["save", "reinitialise", "set-preferred"]);
});
});
describe("ModuleResolvingMismatchedTweaks setting labels", () => {
afterEach(() => setLang("def"));
async function renderMismatchTable() {
const { module, askSelectStringDialogue } = createModule({
autoAcceptCompatibleTweak: true,
hashAlg: "xxhash64",
encrypt: false,
tweakModified: 100,
});
const preferred = {
...(DEFAULT_SETTINGS as unknown as TweakValues),
hashAlg: "xxhash32",
encrypt: true,
tweakModified: 200,
} as Partial<TweakValues>;
await module._checkAndAskResolvingMismatchedTweaks(preferred);
return String(askSelectStringDialogue.mock.calls[0]?.[0] ?? "");
}
it("localises the setting names and keeps the status suffix", async () => {
setLang("zh-tw");
const message = await renderMismatchTable();
expect(message).toContain("chunk ID 的雜湊演算法 (Experimental)");
expect(message).toContain("端對端加密");
expect(message).not.toContain("The Hash algorithm for chunk IDs");
});
it("leaves English unchanged", async () => {
const message = await renderMismatchTable();
expect(message).toContain("The Hash algorithm for chunk IDs (Experimental)");
expect(message).toContain("End-to-End Encryption");
});
});
@@ -1 +1,37 @@
export * from "@vrtmrz/livesync-commonlib/compat/common/settingConstants";
export {
AllSettingDefault,
OnDialogSettingsDefault,
SettingInformation,
} from "@vrtmrz/livesync-commonlib/compat/common/settingConstants";
export type {
AllSettings,
AllSettingItemKey,
AllStringItemKey,
AllNumericItemKey,
AllBooleanItemKey,
OnDialogSettings,
ValueOf,
} from "@vrtmrz/livesync-commonlib/compat/common/settingConstants";
import {
getConfig as getCommonlibConfig,
getConfName as getCommonlibConfName,
type AllSettingItemKey,
} from "@vrtmrz/livesync-commonlib/compat/common/settingConstants";
import type { MessageTranslator } from "@vrtmrz/livesync-commonlib/context";
import { translateLiveSyncMessage } from "@/common/translation";
// Commonlib defaults `translate` to its English-only translator, so every caller which omits
// it silently renders English regardless of `displayLanguage`. Default it to the LiveSync
// catalogue instead, and re-export these wrappers under the original names so that no call
// site has to remember the second argument.
/** `getConfig` with the LiveSync catalogue applied by default. */
export function getConfig(key: AllSettingItemKey, translate: MessageTranslator = translateLiveSyncMessage) {
return getCommonlibConfig(key, translate);
}
/** `getConfName` with the LiveSync catalogue applied by default. See `getConfig`. */
export function getConfName(key: AllSettingItemKey, translate: MessageTranslator = translateLiveSyncMessage) {
return getCommonlibConfName(key, translate);
}
@@ -0,0 +1,33 @@
import { afterEach, describe, expect, it } from "vitest";
import { setLang } from "@/common/translation";
import { getConfig, getConfName } from "./settingConstants";
describe("setting manifest labels", () => {
afterEach(() => setLang("def"));
it("renders names and descriptions in the selected display language", () => {
setLang("zh-tw");
expect(getConfName("liveSync")).toBe("同步模式");
expect(getConfig("couchDB_URI")).toMatchObject({ name: "伺服器 URI" });
expect(getConfig("encrypt")).toMatchObject({
name: "端對端加密",
desc: "加密遠端資料庫中的內容。如果你使用外掛的同步功能,建議啟用此選項。",
});
});
it("leaves English untouched, so that the catalogue key and its English value stay interchangeable", () => {
expect(getConfName("liveSync")).toBe("Sync Mode");
expect(getConfig("encrypt")).toMatchObject({
name: "End-to-End Encryption",
desc: "Encrypt contents on the remote database. If you use the plugin's synchronization feature, enabling this is recommended.",
});
});
it("passes through labels which Commonlib owns but the catalogue does not carry", () => {
setLang("zh-tw");
expect(getConfName("chunkSplitterVersion")).toBe("Chunk Splitter");
});
});