@scm-js/plugin-api 1.19.0 → 1.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/index.d.ts +68 -2
  2. package/package.json +1 -1
package/index.d.ts CHANGED
@@ -42,6 +42,25 @@ export type CombineMode =
42
42
  | "last"
43
43
  /** Only the first occurrence is used. */
44
44
  | "first";
45
+ /**
46
+ * The byte encodings a map's text can be in, and how to tell which one a file used.
47
+ *
48
+ * StarEdit wrote the string table in whatever code page Windows was running — EUC-KR
49
+ * (CP949) on a Korean machine, Shift_JIS on a Japanese one, Windows-1252 nearly everywhere
50
+ * else — and 1.16.1 still reads it that way. Remastered writes UTF-8 and, reading, tries
51
+ * UTF-8 first and falls back to the client's legacy code page when the bytes are not
52
+ * valid UTF-8. The file itself carries no note of which was used, so a table is *guessed*
53
+ * on open (`detectTextEncoding`) and the guess is a setting the user can correct
54
+ * (Scenario ▸ Map Revision).
55
+ *
56
+ * Decoding is the platform's (`TextDecoder` knows every label here). Encoding is not —
57
+ * `TextEncoder` is UTF-8 only — so each legacy encoding's table is built once, lazily,
58
+ * by decoding every byte and every lead/trail byte pair it has and remembering what came
59
+ * back (`reverseTable`). A character the encoding cannot hold is written as `?`, the
60
+ * way StarEdit's own dialogs did, and `unencodable` lists them so Check Map and the
61
+ * dialog can say so before the file is written.
62
+ */
63
+ export type TextEncoding = "utf-8" | "euc-kr" | "shift_jis" | "gbk" | "big5" | "windows-1251" | "windows-1252";
45
64
  /**
46
65
  * STR/STRx string table.
47
66
  *
@@ -49,12 +68,19 @@ export type CombineMode =
49
68
  * MRGN, SPRP and friends — several of which we round-trip as raw bytes — so the table
50
69
  * must keep its index space stable across a save. Entries are therefore addressed by
51
70
  * position, never renumbered.
71
+ *
72
+ * The bytes carry no note of their encoding (see `text/encoding.ts`): `decodeStrings`
73
+ * guesses one from the whole table's bytes unless told, and `encodeStrings` writes the
74
+ * table's, so a file opened and saved keeps its bytes and a Korean file edited on a
75
+ * Korean game stays readable there.
52
76
  */
53
77
  export interface StringTable {
54
78
  /** `strings[i]` is string index `i`; slot 0 is always null. */
55
79
  strings: (string | null)[];
56
80
  /** True when the source section was STRx (Remastered, 32-bit count and offsets). */
57
81
  extended: boolean;
82
+ /** How the text is written to bytes; guessed on open, a setting afterwards. */
83
+ encoding: TextEncoding;
58
84
  }
59
85
  export interface UnitRecord {
60
86
  serial: number;
@@ -1538,6 +1564,8 @@ export interface MapVersionView {
1538
1564
  type: string;
1539
1565
  /** Whether the string table is STRx. */
1540
1566
  extendedStrings: boolean;
1567
+ /** How the string table's text is written to bytes. */
1568
+ textEncoding: TextEncoding;
1541
1569
  /** The file extension StarEdit would give it. */
1542
1570
  extension: string;
1543
1571
  }
@@ -1771,7 +1799,12 @@ export interface StringImport {
1771
1799
  message: string;
1772
1800
  }[];
1773
1801
  }
1802
+ export type Locale = "en" | "ko";
1803
+ /** `"auto"` follows the browser (or the desktop app's system language). */
1804
+ export type LanguagePreference = "auto" | Locale;
1774
1805
  export interface Preferences {
1806
+ /** The editor's own language: `"auto"` follows the browser's (the system's, in the desktop app), else one of `LOCALES`. Applied live. */
1807
+ language: LanguagePreference;
1775
1808
  /** Show the splash while the game data loads; off starts straight on the editor. */
1776
1809
  splash: boolean;
1777
1810
  /** Ask before closing or replacing a map with unsaved changes. */
@@ -1986,6 +2019,8 @@ export interface PluginApi {
1986
2019
  readonly commands: CommandsApi;
1987
2020
  /** Live objects one plugin holds out for others to use, found by name and watched for arriving. */
1988
2021
  readonly services: ServicesApi;
2022
+ /** The plugin's words in the editor's language: its own catalogues, and a `t` over them. */
2023
+ readonly i18n: I18nApi;
1989
2024
  readonly events: EventsApi;
1990
2025
  /**
1991
2026
  * A small key-value store of the plugin's own, kept in the browser's local storage under
@@ -2588,6 +2623,12 @@ export interface UpdateTransaction {
2588
2623
  readonly cuwp: CuwpUpdate;
2589
2624
  /** Scenario ▸ Map Revision: VER / TYPE and, moving to or from Remastered, the string table's width. */
2590
2625
  setVersion(version: MapVersion, extendedStrings?: boolean): void;
2626
+ /**
2627
+ * Scenario ▸ Map Revision: how the string table's text is written to bytes. A map's
2628
+ * file carries no note of it; the editor guesses on open (`document.version().textEncoding`)
2629
+ * and this is the correction. The strings are unchanged; the table is re-encoded on save.
2630
+ */
2631
+ setTextEncoding(encoding: TextEncoding): void;
2591
2632
  /** A line for the status bar, appended to the label. */
2592
2633
  note(text: string): void;
2593
2634
  }
@@ -4434,8 +4475,9 @@ export interface MenuItemSpec {
4434
4475
  */
4435
4476
  icon?: "plugin" | PluginIcon;
4436
4477
  /**
4437
- * Where in the menu: the label of the built-in item or submenu to sit directly under
4438
- * (`"Open Recent"`). Without it, or when nothing has that label, the item goes to the
4478
+ * Where in the menu: the English label of the built-in item or submenu to sit directly
4479
+ * under (`"Open Recent"`) — labels are identities, and the same whatever language the
4480
+ * menu is showing. Without it, or when nothing has that label, the item goes to the
4439
4481
  * end of the menu after a separator.
4440
4482
  */
4441
4483
  after?: string;
@@ -4506,6 +4548,8 @@ export interface HotkeyApi {
4506
4548
  export type PluginEvent =
4507
4549
  /** A map was opened, closed or replaced. */
4508
4550
  "document"
4551
+ /** The editor's language changed (Preferences ▸ Display): re-label what is showing through `api.i18n.t`. */
4552
+ | "language"
4509
4553
  /** Any committed edit (every `document.edit`, stroke, undo and redo bumps it, terrain or not), and a fog edit. */
4510
4554
  | "terrain" | "units" | "doodads" | "locations" | "settings" | "triggers" | "layer"
4511
4555
  /** THG2 sprites — the same bump doodad edits make. */
@@ -4552,6 +4596,28 @@ export interface DocumentEvent {
4552
4596
  /** `document.id()` after the change: the map now in front, or null after a close. */
4553
4597
  id: number | null;
4554
4598
  }
4599
+ /**
4600
+ * The plugin's words in the editor's language. The editor's own chrome is translated
4601
+ * the same way — English text as the key, a flat catalogue per language — and a plugin
4602
+ * brings its catalogues and gets a `t` over them: an untranslated string is its own
4603
+ * English. Placeholders are `{name}`, `{n, plural, one {…} other {…}}`,
4604
+ * `{x, select, …}` and, for Korean, `{name|을}` (the particle agrees with the value).
4605
+ *
4606
+ * @example
4607
+ * api.i18n.register({ ko: { "Count units\u2026": "유닛 세기…", "{n} units": "유닛 {n}개" } });
4608
+ * api.menu.add("Tools", { label: api.i18n.t("Count units\u2026"), run: () => api.ui.alert(api.i18n.t("{n} units", { n: 3 })) });
4609
+ * api.events.on("language", () => relabel());
4610
+ */
4611
+ export interface I18nApi {
4612
+ /** The editor's language, a BCP 47 primary tag: `"en"`, `"ko"`. */
4613
+ readonly language: string;
4614
+ /** Add catalogues, keyed by language; a later one overrides earlier entries. */
4615
+ register(catalogues: Record<string, Record<string, string>>): Disposable;
4616
+ /** The text in the current language, placeholders filled; the text itself when there is no translation. */
4617
+ t(text: string, params?: Record<string, string | number>): string;
4618
+ /** `t` with a context, for the same English words meant differently in two places. */
4619
+ tc(context: string, text: string, params?: Record<string, string | number>): string;
4620
+ }
4555
4621
  /**
4556
4622
  * Listeners are notifications: they run after the change, in the order the plugins were
4557
4623
  * activated, and cannot veto or reorder one another. A listener that rewrites the map in
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scm-js/plugin-api",
3
- "version": "1.19.0",
3
+ "version": "1.21.0",
4
4
  "description": "Type declarations for the scmJS plugin API",
5
5
  "license": "MIT",
6
6
  "types": "index.d.ts",