autumnnote 1.0.8 → 1.0.9

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.
@@ -76,16 +76,17 @@ export class CodeTooltip {
76
76
  // ---------------------------------------------------------------------------
77
77
 
78
78
  _buildTooltip() {
79
+ const L = this.context.locale.tooltips.code;
79
80
  const el = createElement('div', {
80
81
  class: 'an-link-tooltip an-code-tooltip',
81
82
  role: 'toolbar',
82
- 'aria-label': 'Code block actions',
83
+ 'aria-label': L.ariaLabel,
83
84
  });
84
85
  el.style.display = 'none';
85
86
 
86
87
  // Label
87
88
  this._label = createElement('span', { class: 'an-link-tooltip-url' });
88
- this._label.textContent = 'Code';
89
+ this._label.textContent = L.label;
89
90
  el.appendChild(this._label);
90
91
 
91
92
  el.appendChild(this._sep());
@@ -93,8 +94,8 @@ export class CodeTooltip {
93
94
  // Language selector
94
95
  this._langSelect = createElement('select', {
95
96
  class: 'an-code-lang-select',
96
- title: 'Syntax Language',
97
- 'aria-label': 'Syntax language',
97
+ title: L.syntaxLanguage,
98
+ 'aria-label': L.syntaxAriaLabel,
98
99
  });
99
100
  const LANGUAGES = [
100
101
  ['', 'Plain text'], ['javascript', 'JavaScript'], ['typescript', 'TypeScript'],
@@ -115,25 +116,25 @@ export class CodeTooltip {
115
116
  el.appendChild(this._sep());
116
117
 
117
118
  // Copy code
118
- this._copyBtn = this._makeBtn(ICONS.copy, 'Copy Code', () => this._copyCode());
119
+ this._copyBtn = this._makeBtn(ICONS.copy, L.copyCode, () => this._copyCode());
119
120
 
120
121
  el.appendChild(this._copyBtn);
121
122
 
122
123
  el.appendChild(this._sep());
123
124
 
124
125
  // Toggle word-wrap
125
- this._wrapBtn = this._makeBtn(ICONS.wrapOn, 'Toggle Word Wrap', () => this._toggleWrap());
126
+ this._wrapBtn = this._makeBtn(ICONS.wrapOn, L.toggleWordWrap, () => this._toggleWrap());
126
127
  el.appendChild(this._wrapBtn);
127
128
 
128
129
  el.appendChild(this._sep());
129
130
 
130
131
  // Convert to normal paragraph
131
- el.appendChild(this._makeBtn(ICONS.toParagraph, 'Convert to Paragraph', () => this._toParagraph()));
132
+ el.appendChild(this._makeBtn(ICONS.toParagraph, L.convertToParagraph, () => this._toParagraph()));
132
133
 
133
134
  el.appendChild(this._sep());
134
135
 
135
136
  // Delete block
136
- el.appendChild(this._makeBtn(ICONS.deleteCode, 'Delete Code Block', () => this._delete(), true));
137
+ el.appendChild(this._makeBtn(ICONS.deleteCode, L.deleteCodeBlock, () => this._delete(), true));
137
138
 
138
139
  // Keep tooltip alive while hovering it
139
140
  this._disposers.push(
@@ -241,7 +242,9 @@ export class CodeTooltip {
241
242
  const wrapped = (this._activePre.style.whiteSpace || '').includes('pre-wrap')
242
243
  || window.getComputedStyle(this._activePre).whiteSpace === 'pre-wrap';
243
244
  this._wrapBtn.classList.toggle('active', wrapped);
244
- this._wrapBtn.title = wrapped ? 'Disable Word Wrap' : 'Enable Word Wrap';
245
+ this._wrapBtn.title = wrapped
246
+ ? this.context.locale.tooltips.code.disableWordWrap
247
+ : this.context.locale.tooltips.code.enableWordWrap;
245
248
  }
246
249
 
247
250
  _syncLangSelect() {
@@ -48,8 +48,9 @@ const COLOR_PRESETS = [
48
48
 
49
49
  function makeColorSubItems(colorType) {
50
50
  const label = colorType === 'foreColor' ? 'Text Color' : 'Highlight Color';
51
+ const localeKey = colorType === 'foreColor' ? 'textColor' : 'highlightColor';
51
52
  return () => [
52
- { back: true, label, navigate: () => defaultItems },
53
+ { back: true, label, localeKey, navigate: () => defaultItems },
53
54
  { colorPalette: true, colorType },
54
55
  ];
55
56
  }
@@ -171,7 +172,8 @@ export class ContextMenu {
171
172
  const iconSpan = createElement('span', { class: 'an-context-icon', 'aria-hidden': 'true' });
172
173
  iconSpan.innerHTML = ICONS.back;
173
174
  backBtn.appendChild(iconSpan);
174
- backBtn.appendChild(createElement('span', { class: 'an-context-label' }, [it.label || 'Back']));
175
+ const backLabel = (it.localeKey && this.context.locale.contextMenu[it.localeKey]) || it.label || this.context.locale.contextMenu.back || 'Back';
176
+ backBtn.appendChild(createElement('span', { class: 'an-context-label' }, [backLabel]));
175
177
  const off = on(backBtn, 'click', (e) => {
176
178
  e.stopPropagation();
177
179
  const curLeft = parseFloat(this.el.style.left);
@@ -204,7 +206,7 @@ export class ContextMenu {
204
206
  btn.appendChild(iconSpan);
205
207
  }
206
208
  }
207
- btn.appendChild(createElement('span', { class: 'an-context-label' }, [it.label || it.name]));
209
+ btn.appendChild(createElement('span', { class: 'an-context-label' }, [(this.context.locale.contextMenu[it.name] || it.label || it.name)]));
208
210
  const chevron = createElement('span', { class: 'an-context-chevron', 'aria-hidden': 'true' });
209
211
  chevron.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>`;
210
212
  btn.appendChild(chevron);
@@ -238,9 +240,9 @@ export class ContextMenu {
238
240
  if (it.colorType === 'hiliteColor') {
239
241
  const noColor = createElement('div', {
240
242
  class: 'an-context-color-swatch an-context-color-none',
241
- title: 'No highlight',
243
+ title: this.context.locale.contextMenu.noHighlight || 'No highlight',
242
244
  role: 'button',
243
- 'aria-label': 'No highlight',
245
+ 'aria-label': this.context.locale.contextMenu.noHighlight || 'No highlight',
244
246
  });
245
247
  noColor.innerHTML = ICONS.noColor;
246
248
  const offNo = on(noColor, 'click', (e) => { e.stopPropagation(); this._applyColor('hiliteColor', 'transparent'); });
@@ -254,10 +256,10 @@ export class ContextMenu {
254
256
  const colorInput = createElement('input', {
255
257
  type: 'color',
256
258
  value: it.colorType === 'foreColor' ? '#000000' : '#ffff00',
257
- title: 'Custom color',
258
- 'aria-label': 'Custom color',
259
+ title: this.context.locale.contextMenu.customColor || 'Custom color',
260
+ 'aria-label': this.context.locale.contextMenu.customColor || 'Custom color',
259
261
  });
260
- const customLabel = createElement('span', {}, ['Custom…']);
262
+ const customLabel = createElement('span', {}, [this.context.locale.contextMenu.customColorLabel || 'Custom…']);
261
263
  const offCustom = on(colorInput, 'change', () => this._applyColor(it.colorType, colorInput.value));
262
264
  this._menuDisposers.push(offCustom);
263
265
  customRow.appendChild(colorInput);
@@ -277,7 +279,7 @@ export class ContextMenu {
277
279
  iconSpan.innerHTML = it.icon;
278
280
  headerBtn.appendChild(iconSpan);
279
281
  }
280
- headerBtn.appendChild(createElement('span', { class: 'an-context-label' }, [it.label || 'Insert Table']));
282
+ headerBtn.appendChild(createElement('span', { class: 'an-context-label' }, [this.context.locale.contextMenu.table || it.label || 'Insert Table']));
281
283
  const chevron = createElement('span', { class: 'an-context-chevron', 'aria-hidden': 'true' });
282
284
  chevron.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"/></svg>`;
283
285
  headerBtn.appendChild(chevron);
@@ -305,7 +307,7 @@ export class ContextMenu {
305
307
  cells.forEach((cell) => {
306
308
  cell.classList.toggle('active', +cell.dataset.row <= rows && +cell.dataset.col <= cols);
307
309
  });
308
- labelEl.textContent = (rows && cols) ? `${cols} × ${rows}` : 'Insert Table';
310
+ labelEl.textContent = (rows && cols) ? `${cols} × ${rows}` : (this.context.locale.contextMenu.table || 'Insert Table');
309
311
  };
310
312
 
311
313
  panel.appendChild(gridEl);
@@ -358,7 +360,7 @@ export class ContextMenu {
358
360
  iconSpan.innerHTML = it.icon;
359
361
  btn.appendChild(iconSpan);
360
362
  }
361
- btn.appendChild(createElement('span', { class: 'an-context-label' }, [it.label || it.name]));
363
+ btn.appendChild(createElement('span', { class: 'an-context-label' }, [(this.context.locale.contextMenu[it.name] || it.label || it.name)]));
362
364
  const off = on(btn, 'click', (e) => {
363
365
  e.stopPropagation();
364
366
  this.hide();
@@ -555,19 +555,20 @@ export class EmojiDialog {
555
555
  // ---------------------------------------------------------------------------
556
556
 
557
557
  _buildDialog() {
558
+ const L = this.context.locale.emojiDialog;
558
559
  const overlay = createElement('div', {
559
560
  class: 'an-dialog-overlay',
560
561
  role: 'dialog',
561
562
  'aria-modal': 'true',
562
- 'aria-label': 'Insert emoji',
563
+ 'aria-label': L.ariaLabel,
563
564
  });
564
565
  const box = createElement('div', { class: 'an-dialog-box an-emoji-box' });
565
566
 
566
567
  // Title row
567
568
  const titleRow = createElement('div', { class: 'an-icon-title-row' });
568
569
  const title = createElement('h3', { class: 'an-dialog-title' });
569
- title.textContent = 'Insert Emoji';
570
- const closeBtn = createElement('button', { type: 'button', class: 'an-icon-close', 'aria-label': 'Close' });
570
+ title.textContent = L.title;
571
+ const closeBtn = createElement('button', { type: 'button', class: 'an-icon-close', 'aria-label': L.close });
571
572
  closeBtn.innerHTML = '&times;';
572
573
  titleRow.append(title, closeBtn);
573
574
 
@@ -575,7 +576,7 @@ export class EmojiDialog {
575
576
  const searchInput = createElement('input', {
576
577
  type: 'search',
577
578
  class: 'an-input an-icon-search',
578
- placeholder: 'Search emojis…',
579
+ placeholder: L.searchPlaceholder,
579
580
  autocomplete: 'off',
580
581
  });
581
582
  this._searchInput = searchInput;
@@ -583,11 +584,11 @@ export class EmojiDialog {
583
584
  // Category tabs
584
585
  const catBar = createElement('div', { class: 'an-icon-cats' });
585
586
  const allTab = createElement('button', { type: 'button', class: 'an-icon-cat active', 'data-cat': 'all' });
586
- allTab.textContent = 'All';
587
+ allTab.textContent = L.all;
587
588
  catBar.appendChild(allTab);
588
589
  EMOJI_CATS.forEach(({ id, label }) => {
589
590
  const tab = createElement('button', { type: 'button', class: 'an-icon-cat', 'data-cat': id });
590
- tab.textContent = label;
591
+ tab.textContent = (L.categories && L.categories[id]) || label;
591
592
  catBar.appendChild(tab);
592
593
  });
593
594
  this._catBar = catBar;
@@ -611,7 +612,7 @@ export class EmojiDialog {
611
612
  // Cancel only — clicking an emoji inserts immediately
612
613
  const btnRow = createElement('div', { class: 'an-dialog-actions' });
613
614
  const cancelBtn = createElement('button', { type: 'button', class: 'an-btn' });
614
- cancelBtn.textContent = 'Cancel';
615
+ cancelBtn.textContent = L.cancelBtn;
615
616
  btnRow.appendChild(cancelBtn);
616
617
 
617
618
  box.append(titleRow, searchInput, catBar, grid, btnRow);
@@ -122,7 +122,7 @@ export class FindReplace {
122
122
  const isReplace = this._mode === 'replace';
123
123
  if (replaceRow) replaceRow.style.display = isReplace ? '' : 'none';
124
124
  if (replaceActions) replaceActions.style.display = isReplace ? '' : 'none';
125
- if (title) title.textContent = isReplace ? 'Find & Replace' : 'Find';
125
+ if (title) title.textContent = isReplace ? this.context.locale.findReplace.findReplaceTitle : this.context.locale.findReplace.findTitle;
126
126
  }
127
127
 
128
128
  // ---------------------------------------------------------------------------
@@ -130,24 +130,25 @@ export class FindReplace {
130
130
  // ---------------------------------------------------------------------------
131
131
 
132
132
  _buildDialog() {
133
+ const L = this.context.locale.findReplace;
133
134
  const overlay = createElement('div', {
134
135
  class: 'an-dialog-overlay an-fr-dialog',
135
136
  role: 'dialog',
136
137
  'aria-modal': 'true',
137
- 'aria-label': 'Find and Replace',
138
+ 'aria-label': L.findReplaceTitle,
138
139
  });
139
140
  const box = createElement('div', { class: 'an-dialog-box' });
140
141
 
141
142
  // ---- Title row ----
142
143
  const titleRow = createElement('div', { class: 'an-icon-title-row' });
143
144
  const title = createElement('h3', { class: 'an-dialog-title' });
144
- title.textContent = 'Find';
145
+ title.textContent = L.findTitle;
145
146
  const closeBtn = createElement('button', {
146
147
  type: 'button',
147
148
  class: 'an-icon-close',
148
149
  'aria-label': 'Close',
149
150
  });
150
- closeBtn.textContent = '×';
151
+ closeBtn.textContent = L.close;
151
152
  this._closeBtn = closeBtn;
152
153
  titleRow.append(title, closeBtn);
153
154
  box.appendChild(titleRow);
@@ -157,8 +158,8 @@ export class FindReplace {
157
158
  const findInput = createElement('input', {
158
159
  type: 'text',
159
160
  class: 'an-input',
160
- placeholder: 'Find…',
161
- 'aria-label': 'Search text',
161
+ placeholder: L.findPlaceholder,
162
+ 'aria-label': L.searchAriaLabel,
162
163
  });
163
164
  this._findInput = findInput;
164
165
  findRow.appendChild(findInput);
@@ -172,7 +173,7 @@ export class FindReplace {
172
173
  'aria-label': 'Case sensitive',
173
174
  });
174
175
  this._caseCheckbox = caseCheckbox;
175
- caseLabel.append(caseCheckbox, document.createTextNode('\u00a0Case sensitive'));
176
+ caseLabel.append(caseCheckbox, document.createTextNode(L.caseSensitive));
176
177
  const counter = createElement('span', { class: 'an-fr-counter' });
177
178
  this._counterEl = counter;
178
179
  optRow.append(caseLabel, counter);
@@ -181,9 +182,9 @@ export class FindReplace {
181
182
  // ---- Find actions ----
182
183
  const findActions = createElement('div', { class: 'an-dialog-actions an-fr-find-actions' });
183
184
  const prevBtn = createElement('button', { type: 'button', class: 'an-btn' });
184
- prevBtn.textContent = '\u2190 Prev';
185
+ prevBtn.textContent = L.prevBtn;
185
186
  const nextBtn = createElement('button', { type: 'button', class: 'an-btn an-btn-primary' });
186
- nextBtn.textContent = 'Next \u2192';
187
+ nextBtn.textContent = L.nextBtn;
187
188
  findActions.append(prevBtn, nextBtn);
188
189
  box.appendChild(findActions);
189
190
 
@@ -193,8 +194,8 @@ export class FindReplace {
193
194
  const replaceInput = createElement('input', {
194
195
  type: 'text',
195
196
  class: 'an-input',
196
- placeholder: 'Replace with\u2026',
197
- 'aria-label': 'Replace with',
197
+ placeholder: L.replacePlaceholder,
198
+ 'aria-label': L.replaceAriaLabel,
198
199
  });
199
200
  this._replaceInput = replaceInput;
200
201
  replaceRow.appendChild(replaceInput);
@@ -204,9 +205,9 @@ export class FindReplace {
204
205
  const replaceActions = createElement('div', { class: 'an-dialog-actions an-fr-replace-actions' });
205
206
  replaceActions.style.display = 'none';
206
207
  const replaceBtn = createElement('button', { type: 'button', class: 'an-btn' });
207
- replaceBtn.textContent = 'Replace';
208
+ replaceBtn.textContent = L.replaceBtn;
208
209
  const replaceAllBtn = createElement('button', { type: 'button', class: 'an-btn an-btn-primary' });
209
- replaceAllBtn.textContent = 'Replace All';
210
+ replaceAllBtn.textContent = L.replaceAllBtn;
210
211
  replaceActions.append(replaceBtn, replaceAllBtn);
211
212
  box.appendChild(replaceActions);
212
213
 
@@ -332,11 +332,12 @@ export class IconDialog {
332
332
  // ---------------------------------------------------------------------------
333
333
 
334
334
  _buildDialog() {
335
+ const L = this.context.locale.iconDialog;
335
336
  const overlay = createElement('div', {
336
337
  class: 'an-dialog-overlay',
337
338
  role: 'dialog',
338
339
  'aria-modal': 'true',
339
- 'aria-label': 'Insert FA icon',
340
+ 'aria-label': L.ariaLabel,
340
341
  });
341
342
 
342
343
  const box = createElement('div', { class: 'an-dialog-box an-icon-box' });
@@ -344,8 +345,8 @@ export class IconDialog {
344
345
  // Title row
345
346
  const titleRow = createElement('div', { class: 'an-icon-title-row' });
346
347
  const title = createElement('h3', { class: 'an-dialog-title' });
347
- title.textContent = 'Insert FA Icon';
348
- const closeBtn = createElement('button', { type: 'button', class: 'an-icon-close', 'aria-label': 'Close' });
348
+ title.textContent = L.title;
349
+ const closeBtn = createElement('button', { type: 'button', class: 'an-icon-close', 'aria-label': L.close });
349
350
  closeBtn.innerHTML = '&times;';
350
351
  titleRow.append(title, closeBtn);
351
352
 
@@ -353,7 +354,7 @@ export class IconDialog {
353
354
  const searchInput = createElement('input', {
354
355
  type: 'search',
355
356
  class: 'an-input an-icon-search',
356
- placeholder: 'Search icons…',
357
+ placeholder: L.searchPlaceholder,
357
358
  autocomplete: 'off',
358
359
  });
359
360
  this._searchInput = searchInput;
@@ -361,11 +362,11 @@ export class IconDialog {
361
362
  // Category tabs
362
363
  const catBar = createElement('div', { class: 'an-icon-cats' });
363
364
  const allTab = createElement('button', { type: 'button', class: 'an-icon-cat active', 'data-cat': 'all' });
364
- allTab.textContent = 'All';
365
+ allTab.textContent = L.all;
365
366
  catBar.appendChild(allTab);
366
367
  ICON_CATEGORIES.forEach(({ id, label }) => {
367
368
  const tab = createElement('button', { type: 'button', class: 'an-icon-cat', 'data-cat': id });
368
- tab.textContent = label;
369
+ tab.textContent = (L.categories && L.categories[id]) || label;
369
370
  catBar.appendChild(tab);
370
371
  });
371
372
  this._catBar = catBar;
@@ -386,7 +387,7 @@ export class IconDialog {
386
387
  const optRow = createElement('div', { class: 'an-icon-options' });
387
388
 
388
389
  const styleLabel = createElement('label', { class: 'an-label' });
389
- styleLabel.textContent = 'Style';
390
+ styleLabel.textContent = L.style;
390
391
  const styleSelect = createElement('select', { class: 'an-input an-icon-option-select' });
391
392
  [['fa-solid', 'Solid'], ['fa-regular', 'Regular'], ['fa-light', 'Light (Pro)']].forEach(([v, t]) => {
392
393
  const opt = createElement('option', { value: v });
@@ -397,7 +398,7 @@ export class IconDialog {
397
398
  this._styleSelect = styleSelect;
398
399
 
399
400
  const sizeLabel = createElement('label', { class: 'an-label' });
400
- sizeLabel.textContent = 'Size';
401
+ sizeLabel.textContent = L.size;
401
402
  const sizeSelect = createElement('select', { class: 'an-input an-icon-option-select' });
402
403
  [['', 'Inherit'], ['0.75em', '0.75em'], ['1em', '1em'], ['1.25em', '1.25em'], ['1.5em', '1.5em'], ['2em', '2em'], ['3em', '3em']].forEach(([v, t]) => {
403
404
  const opt = createElement('option', { value: v });
@@ -408,30 +409,30 @@ export class IconDialog {
408
409
  this._sizeSelect = sizeSelect;
409
410
 
410
411
  const colorLabel = createElement('label', { class: 'an-label' });
411
- colorLabel.textContent = 'Color';
412
+ colorLabel.textContent = L.color;
412
413
  const colorInput = createElement('input', { type: 'color', class: 'an-icon-color', value: '#000000' });
413
414
  this._colorInput = colorInput;
414
415
 
415
416
  const useColorLabel = createElement('label', { class: 'an-label an-label-inline an-icon-use-color' });
416
417
  const useColorCb = createElement('input', { type: 'checkbox', checked: '' });
417
418
  this._useColorCb = useColorCb;
418
- useColorLabel.append(useColorCb, document.createTextNode(' Use color'));
419
+ useColorLabel.append(useColorCb, document.createTextNode(L.useColor));
419
420
 
420
421
  optRow.append(styleLabel, styleSelect, sizeLabel, sizeSelect, colorLabel, colorInput, useColorLabel);
421
422
 
422
423
  // Preview
423
424
  const preview = createElement('div', { class: 'an-icon-preview' });
424
425
  const previewHint = createElement('span', { class: 'an-icon-preview-hint' });
425
- previewHint.textContent = 'Select an icon';
426
+ previewHint.textContent = L.selectHint;
426
427
  preview.appendChild(previewHint);
427
428
  this._preview = preview;
428
429
 
429
430
  // Actions
430
431
  const btnRow = createElement('div', { class: 'an-dialog-actions' });
431
432
  const insertBtn = createElement('button', { type: 'button', class: 'an-btn an-btn-primary', disabled: '' });
432
- insertBtn.textContent = 'Insert FA Icon';
433
+ insertBtn.textContent = L.insertBtn;
433
434
  const cancelBtn = createElement('button', { type: 'button', class: 'an-btn' });
434
- cancelBtn.textContent = 'Cancel';
435
+ cancelBtn.textContent = L.cancelBtn;
435
436
  btnRow.append(insertBtn, cancelBtn);
436
437
  this._insertBtn = insertBtn;
437
438
 
@@ -57,35 +57,36 @@ export class ImageDialog {
57
57
  // ---------------------------------------------------------------------------
58
58
 
59
59
  _buildDialog() {
60
+ const L = this.context.locale.imageDialog;
60
61
  const overlay = createElement('div', {
61
62
  class: 'an-dialog-overlay',
62
63
  role: 'dialog',
63
64
  'aria-modal': 'true',
64
- 'aria-label': 'Insert image',
65
+ 'aria-label': L.ariaLabel,
65
66
  });
66
67
  const box = createElement('div', { class: 'an-dialog-box' });
67
68
 
68
69
  const title = createElement('h3', { class: 'an-dialog-title' });
69
- title.textContent = 'Insert Image';
70
+ title.textContent = L.title;
70
71
 
71
72
  // URL tab
72
73
  const urlLabel = createElement('label', { class: 'an-label' });
73
- urlLabel.textContent = 'Image URL';
74
+ urlLabel.textContent = L.imageUrl;
74
75
  const urlInput = createElement('input', {
75
76
  type: 'url',
76
77
  class: 'an-input',
77
- placeholder: 'https://example.com/image.png',
78
+ placeholder: L.urlPlaceholder,
78
79
  autocomplete: 'off',
79
80
  });
80
81
  this._urlInput = urlInput;
81
82
 
82
83
  // Alt text
83
84
  const altLabel = createElement('label', { class: 'an-label' });
84
- altLabel.textContent = 'Alt Text';
85
+ altLabel.textContent = L.altText;
85
86
  const altInput = createElement('input', {
86
87
  type: 'text',
87
88
  class: 'an-input',
88
- placeholder: 'Describe the image',
89
+ placeholder: L.altPlaceholder,
89
90
  autocomplete: 'off',
90
91
  });
91
92
  this._altInput = altInput;
@@ -94,13 +95,13 @@ export class ImageDialog {
94
95
 
95
96
  // Alignment
96
97
  const alignLabel = createElement('label', { class: 'an-label' });
97
- alignLabel.textContent = 'Alignment';
98
+ alignLabel.textContent = L.alignment;
98
99
  const alignRow = createElement('div', { class: 'an-align-row' });
99
100
  const alignOptions = [
100
- { value: '', label: 'None' },
101
- { value: 'left', label: 'Left' },
102
- { value: 'center', label: 'Center' },
103
- { value: 'right', label: 'Right' },
101
+ { value: '', label: L.alignNone },
102
+ { value: 'left', label: L.alignLeft },
103
+ { value: 'center', label: L.alignCenter },
104
+ { value: 'right', label: L.alignRight },
104
105
  ];
105
106
  alignOptions.forEach(({ value, label }) => {
106
107
  const radioId = `an-align-${value || 'none'}`;
@@ -114,7 +115,7 @@ export class ImageDialog {
114
115
  box.append(alignLabel, alignRow);
115
116
  if (this.options.allowImageUpload !== false) {
116
117
  const fileLabel = createElement('label', { class: 'an-label' });
117
- fileLabel.textContent = 'Or upload a file';
118
+ fileLabel.textContent = L.uploadLabel;
118
119
  const fileInput = createElement('input', {
119
120
  type: 'file',
120
121
  class: 'an-input',
@@ -132,9 +133,9 @@ export class ImageDialog {
132
133
  // Buttons
133
134
  const btnRow = createElement('div', { class: 'an-dialog-actions' });
134
135
  const insertBtn = createElement('button', { type: 'button', class: 'an-btn an-btn-primary' });
135
- insertBtn.textContent = 'Insert';
136
+ insertBtn.textContent = L.insertBtn;
136
137
  const cancelBtn = createElement('button', { type: 'button', class: 'an-btn' });
137
- cancelBtn.textContent = 'Cancel';
138
+ cancelBtn.textContent = L.cancelBtn;
138
139
  btnRow.appendChild(insertBtn);
139
140
  btnRow.appendChild(cancelBtn);
140
141
 
@@ -166,7 +167,7 @@ export class ImageDialog {
166
167
  'image/webp', 'image/svg+xml', 'image/avif',
167
168
  ]);
168
169
  if (!SUPPORTED.has(file.type)) {
169
- const message = `Format "${file.type}" is not supported for display in web browsers. Please convert to JPEG, PNG, or WebP first.`;
170
+ const message = this.context.locale.errors.imageFormat(file.type);
170
171
  if (this._fileHint) this._fileHint.textContent = message;
171
172
  this.context.triggerEvent('imageError', { file, message });
172
173
  this._fileInput.value = '';
@@ -177,7 +178,7 @@ export class ImageDialog {
177
178
  // Validate file size (max 5 MB by default)
178
179
  const maxSize = (this.options.maxImageSize || 5) * 1024 * 1024;
179
180
  if (file.size > maxSize) {
180
- const message = `Image file is too large. Maximum allowed size is ${this.options.maxImageSize || 5} MB.`;
181
+ const message = this.context.locale.errors.imageSize(this.options.maxImageSize || 5);
181
182
  if (this._fileHint) this._fileHint.textContent = message;
182
183
  console.warn('[AutumnNote] ImageDialog:', message);
183
184
  this.context.triggerEvent('imageError', { file, message });
@@ -75,24 +75,25 @@ export class ImageTooltip {
75
75
  // ---------------------------------------------------------------------------
76
76
 
77
77
  _buildTooltip() {
78
+ const L = this.context.locale.tooltips.image;
78
79
  const el = createElement('div', {
79
80
  class: 'an-link-tooltip an-image-tooltip',
80
81
  role: 'toolbar',
81
- 'aria-label': 'Image actions',
82
+ 'aria-label': L.ariaLabel,
82
83
  });
83
84
  el.style.display = 'none';
84
85
 
85
86
  // Label showing "Image"
86
87
  this._label = createElement('span', { class: 'an-link-tooltip-url' });
87
- this._label.textContent = 'Image';
88
+ this._label.textContent = L.label;
88
89
  el.appendChild(this._label);
89
90
 
90
91
  el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
91
92
 
92
- this._floatLeftBtn = this._makeBtn(ICONS.floatLeft, 'Float Left', () => this._setFloat('left'));
93
- this._floatNoneBtn = this._makeBtn(ICONS.floatNone, 'No Float', () => this._setFloat(''));
94
- this._alignCenterBtn = this._makeBtn(ICONS.alignCenter, 'Align Center', () => this._setCenter());
95
- this._floatRightBtn = this._makeBtn(ICONS.floatRight, 'Float Right', () => this._setFloat('right'));
93
+ this._floatLeftBtn = this._makeBtn(ICONS.floatLeft, L.floatLeft, () => this._setFloat('left'));
94
+ this._floatNoneBtn = this._makeBtn(ICONS.floatNone, L.noFloat, () => this._setFloat(''));
95
+ this._alignCenterBtn = this._makeBtn(ICONS.alignCenter, L.alignCenter, () => this._setCenter());
96
+ this._floatRightBtn = this._makeBtn(ICONS.floatRight, L.floatRight, () => this._setFloat('right'));
96
97
 
97
98
  el.appendChild(this._floatLeftBtn);
98
99
  el.appendChild(this._floatNoneBtn);
@@ -101,28 +102,28 @@ export class ImageTooltip {
101
102
 
102
103
  el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
103
104
 
104
- this._originalBtn = this._makeBtn(ICONS.originalSize, 'Original Size', () => this._resetSize());
105
+ this._originalBtn = this._makeBtn(ICONS.originalSize, L.originalSize, () => this._resetSize());
105
106
 
106
107
  el.appendChild(this._originalBtn);
107
108
 
108
109
  el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
109
110
 
110
- el.appendChild(this._makeBtn(ICONS.rotateLeft, 'Rotate Left', () => this._rotate(-90)));
111
- el.appendChild(this._makeBtn(ICONS.rotateRight, 'Rotate Right', () => this._rotate(90)));
111
+ el.appendChild(this._makeBtn(ICONS.rotateLeft, L.rotateLeft, () => this._rotate(-90)));
112
+ el.appendChild(this._makeBtn(ICONS.rotateRight, L.rotateRight, () => this._rotate(90)));
112
113
 
113
114
  el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
114
115
 
115
- this._cropBtn = this._makeBtn(ICONS.crop, 'Crop Image', () => this._crop());
116
+ this._cropBtn = this._makeBtn(ICONS.crop, L.cropImage, () => this._crop());
116
117
  el.appendChild(this._cropBtn);
117
118
 
118
119
  el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
119
120
 
120
- this._captionBtn = this._makeBtn(ICONS.caption, 'Add / Edit Caption', () => this._toggleCaption());
121
+ this._captionBtn = this._makeBtn(ICONS.caption, L.addCaption, () => this._toggleCaption());
121
122
  el.appendChild(this._captionBtn);
122
123
 
123
124
  el.appendChild(createElement('div', { class: 'an-link-tooltip-sep' }));
124
125
 
125
- this._deleteBtn = this._makeBtn(ICONS.deleteImg, 'Delete Image', () => this._delete(), true);
126
+ this._deleteBtn = this._makeBtn(ICONS.deleteImg, L.deleteImage, () => this._delete(), true);
126
127
 
127
128
  el.appendChild(this._deleteBtn);
128
129
 
@@ -59,19 +59,20 @@ export class LinkDialog {
59
59
  // ---------------------------------------------------------------------------
60
60
 
61
61
  _buildDialog() {
62
- const overlay = createElement('div', { class: 'an-dialog-overlay', role: 'dialog', 'aria-modal': 'true', 'aria-label': 'Insert link' });
62
+ const L = this.context.locale.linkDialog;
63
+ const overlay = createElement('div', { class: 'an-dialog-overlay', role: 'dialog', 'aria-modal': 'true', 'aria-label': L.ariaLabel });
63
64
  const box = createElement('div', { class: 'an-dialog-box' });
64
65
 
65
66
  const title = createElement('h3', { class: 'an-dialog-title' });
66
- title.textContent = 'Insert Link';
67
+ title.textContent = L.title;
67
68
 
68
69
  // URL field
69
70
  const urlLabel = createElement('label', { class: 'an-label' });
70
- urlLabel.textContent = 'URL';
71
+ urlLabel.textContent = L.url;
71
72
  const urlInput = createElement('input', {
72
73
  type: 'url',
73
74
  class: 'an-input',
74
- placeholder: 'https://',
75
+ placeholder: L.urlPlaceholder,
75
76
  id: 'an-link-url',
76
77
  name: 'url',
77
78
  autocomplete: 'off',
@@ -80,11 +81,11 @@ export class LinkDialog {
80
81
 
81
82
  // Text field
82
83
  const textLabel = createElement('label', { class: 'an-label' });
83
- textLabel.textContent = 'Display Text';
84
+ textLabel.textContent = L.displayText;
84
85
  const textInput = createElement('input', {
85
86
  type: 'text',
86
87
  class: 'an-input',
87
- placeholder: 'Link text',
88
+ placeholder: L.textPlaceholder,
88
89
  id: 'an-link-text',
89
90
  name: 'linkText',
90
91
  autocomplete: 'off',
@@ -100,14 +101,14 @@ export class LinkDialog {
100
101
  });
101
102
  this._tabCheckbox = tabCheckbox;
102
103
  tabLabel.appendChild(tabCheckbox);
103
- tabLabel.appendChild(document.createTextNode(' Open in new tab'));
104
+ tabLabel.appendChild(document.createTextNode(' ' + L.openInNewTab));
104
105
 
105
106
  // Buttons
106
107
  const btnRow = createElement('div', { class: 'an-dialog-actions' });
107
108
  const insertBtn = createElement('button', { type: 'button', class: 'an-btn an-btn-primary' });
108
- insertBtn.textContent = 'Insert';
109
+ insertBtn.textContent = L.insertBtn;
109
110
  const cancelBtn = createElement('button', { type: 'button', class: 'an-btn' });
110
- cancelBtn.textContent = 'Cancel';
111
+ cancelBtn.textContent = L.cancelBtn;
111
112
  btnRow.appendChild(insertBtn);
112
113
  btnRow.appendChild(cancelBtn);
113
114