-
Notifications
You must be signed in to change notification settings - Fork 49
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fixes #60
- Loading branch information
Showing
10 changed files
with
156 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import type { PartialDeep } from "./utils"; | ||
|
||
type Strings = { | ||
[key: string]: | ||
| string | ||
| ((params: Record<string, unknown>) => string) | ||
| Strings; | ||
}; | ||
|
||
/** The default set of localizable strings */ | ||
export const defaultStrings = { | ||
link_tooltip: { | ||
apply_button_text: "Apply" as string, | ||
apply_button_title: "Apply new link" as string, | ||
edit_button_title: "Edit link" as string, | ||
remove_button_title: "Remove link" as string, | ||
}, | ||
menubar: { | ||
mode_toggle_label: "Markdown" as string, | ||
mode_toggle_title: "Toggle Markdown mode" as string, | ||
}, | ||
nodes: { | ||
codeblock_lang_auto: ({ lang }: { lang: string }) => `${lang} (auto)`, | ||
spoiler_reveal_text: "Reveal spoiler" as string, | ||
}, | ||
image_upload: { | ||
upload_error_file_too_big: | ||
"Your image is too large to upload (over 2 MiB)" as string, | ||
upload_error_generic: | ||
"Image upload failed. Please try again." as string, | ||
upload_error_unsupported_format: | ||
"Please select an image (jpeg, png, gif) to upload" as string, | ||
uploaded_image_preview_alt: "uploaded image preview" as string, | ||
}, | ||
} as const; | ||
|
||
/** The set of strings that were overridden by registerLocalizationStrings */ | ||
let strings: PartialDeep<typeof defaultStrings> = defaultStrings; | ||
|
||
/** Registers new localization strings; any strings that are left unregistered will fall back to the default value */ | ||
export function registerLocalizationStrings( | ||
newStrings: PartialDeep<typeof defaultStrings> | ||
) { | ||
strings = newStrings; | ||
} | ||
|
||
/** Resolves a dot-separeated key against an object */ | ||
function resolve(obj: Strings, key: string) { | ||
return key.split(".").reduce((p, n) => p?.[n], obj); | ||
} | ||
|
||
/** Caches key lookups to their values so we're not continuously splitting */ | ||
const cache: Strings = {}; | ||
|
||
/** | ||
* Checks the localized strings for a given key and returns the value | ||
* @param key A dot-separated key to the localized string e.g. "menubar.mode_toggle_label" | ||
* @param params An object of parameters to pass to the localization function if it exists | ||
*/ | ||
export function _t(key: string, params: Record<string, unknown> = {}): string { | ||
if (!(key in cache)) { | ||
cache[key] = resolve(strings, key) || resolve(defaultStrings, key); | ||
} | ||
|
||
const string = cache[key]; | ||
|
||
if (!string) { | ||
throw `Missing translation for key: ${key}`; | ||
} | ||
|
||
if (typeof string === "string") { | ||
return string; | ||
} else if (typeof string === "function") { | ||
return string(params); | ||
} | ||
|
||
throw `Missing translation for key: ${key}`; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { registerLocalizationStrings, _t } from "../../src/shared/localization"; | ||
|
||
describe("localization", () => { | ||
it("should find nested entries", () => { | ||
expect(_t("link_tooltip.apply_button_text")).toBe("Apply"); | ||
}); | ||
|
||
it("should execute function values with params passed", () => { | ||
expect(_t("nodes.codeblock_lang_auto", { lang: "test" })).toBe( | ||
"test (auto)" | ||
); | ||
}); | ||
|
||
it("should throw when an entry is not found", () => { | ||
expect(() => _t("fake.faker.fakest")).toThrow( | ||
/^Missing translation for key:/ | ||
); | ||
}); | ||
|
||
it("should allow overriding a partial set of strings", () => { | ||
registerLocalizationStrings({ | ||
nodes: { | ||
spoiler_reveal_text: "Раскрыть спойлер", | ||
}, | ||
}); | ||
|
||
// overridden | ||
expect(_t("nodes.spoiler_reveal_text")).toBe("Раскрыть спойлер"); | ||
// not overridden - falls back to default | ||
expect(_t("link_tooltip.apply_button_text")).toBe("Apply"); | ||
}); | ||
}); |