- A per-element Preview toggle (aria-pressed, off by default) splits the editor 50/50 with an auto-fit grid that wraps the pane below on narrow widths. - The pane is an iframe with an empty sandbox, content set only through srcdoc, created on first use; it reads only the value getter, so previewing never edits or emits summer-change.
161 lines
4.3 KiB
TypeScript
161 lines
4.3 KiB
TypeScript
/** Every label, prompt and error the Blog Editor shows. */
|
|
export interface Labels {
|
|
tabWysiwyg: string
|
|
tabSource: string
|
|
toolbar: string
|
|
paragraph: string
|
|
heading2: string
|
|
heading3: string
|
|
heading4: string
|
|
bold: string
|
|
italic: string
|
|
bulletList: string
|
|
orderedList: string
|
|
link: string
|
|
blockquote: string
|
|
insertTable: string
|
|
addRow: string
|
|
deleteRow: string
|
|
addColumn: string
|
|
deleteColumn: string
|
|
deleteTable: string
|
|
image: string
|
|
embed: string
|
|
rawHtml: string
|
|
undo: string
|
|
redo: string
|
|
linkUrl: string
|
|
linkApply: string
|
|
linkRemove: string
|
|
linkInvalid: string
|
|
embedUrl: string
|
|
embedInsert: string
|
|
embedInvalid: string
|
|
cancel: string
|
|
uploading: string
|
|
uploadFailed: string
|
|
uploadTimeout: string
|
|
notAnImage: string
|
|
altText: string
|
|
caption: string
|
|
altRequired: string
|
|
insertImage: string
|
|
rawHtmlCard: string
|
|
editAsHtml: string
|
|
embedCard: string
|
|
preview: string
|
|
previewFrame: string
|
|
}
|
|
|
|
const en: Labels = {
|
|
tabWysiwyg: 'WYSIWYG',
|
|
tabSource: 'Source',
|
|
toolbar: 'Formatting',
|
|
paragraph: 'Paragraph',
|
|
heading2: 'Heading 2',
|
|
heading3: 'Heading 3',
|
|
heading4: 'Heading 4',
|
|
bold: 'Bold',
|
|
italic: 'Italic',
|
|
bulletList: 'Bullet list',
|
|
orderedList: 'Numbered list',
|
|
link: 'Link',
|
|
blockquote: 'Quote',
|
|
insertTable: 'Insert table',
|
|
addRow: 'Add row',
|
|
deleteRow: 'Delete row',
|
|
addColumn: 'Add column',
|
|
deleteColumn: 'Delete column',
|
|
deleteTable: 'Delete table',
|
|
image: 'Image',
|
|
embed: 'Embed video',
|
|
rawHtml: 'HTML block',
|
|
undo: 'Undo',
|
|
redo: 'Redo',
|
|
linkUrl: 'Link URL',
|
|
linkApply: 'Apply',
|
|
linkRemove: 'Remove link',
|
|
linkInvalid: 'Links must use http, https, mailto or a relative URL.',
|
|
embedUrl: 'YouTube URL',
|
|
embedInsert: 'Insert',
|
|
embedInvalid: 'This video URL is not supported. Paste a YouTube link.',
|
|
cancel: 'Cancel',
|
|
uploading: 'Uploading {name}…',
|
|
uploadFailed: 'Upload failed: {error}',
|
|
uploadTimeout: 'The upload of {name} took too long.',
|
|
notAnImage: 'Only JPEG, PNG, GIF and WebP images can be uploaded.',
|
|
altText: 'Alt text (required)',
|
|
caption: 'Caption (optional)',
|
|
altRequired: 'Enter the alt text.',
|
|
insertImage: 'Insert image',
|
|
rawHtmlCard: 'HTML block',
|
|
editAsHtml: 'Edit as HTML',
|
|
embedCard: 'Embedded video',
|
|
preview: 'Preview',
|
|
previewFrame: 'Post preview',
|
|
}
|
|
|
|
const pl: Labels = {
|
|
tabWysiwyg: 'WYSIWYG',
|
|
tabSource: 'Źródło',
|
|
toolbar: 'Formatowanie',
|
|
paragraph: 'Akapit',
|
|
heading2: 'Nagłówek 2',
|
|
heading3: 'Nagłówek 3',
|
|
heading4: 'Nagłówek 4',
|
|
bold: 'Pogrubienie',
|
|
italic: 'Kursywa',
|
|
bulletList: 'Lista punktowana',
|
|
orderedList: 'Lista numerowana',
|
|
link: 'Link',
|
|
blockquote: 'Cytat',
|
|
insertTable: 'Wstaw tabelę',
|
|
addRow: 'Dodaj wiersz',
|
|
deleteRow: 'Usuń wiersz',
|
|
addColumn: 'Dodaj kolumnę',
|
|
deleteColumn: 'Usuń kolumnę',
|
|
deleteTable: 'Usuń tabelę',
|
|
image: 'Obraz',
|
|
embed: 'Osadź wideo',
|
|
rawHtml: 'Blok HTML',
|
|
undo: 'Cofnij',
|
|
redo: 'Ponów',
|
|
linkUrl: 'Adres linku',
|
|
linkApply: 'Zastosuj',
|
|
linkRemove: 'Usuń link',
|
|
linkInvalid: 'Link musi używać http, https, mailto albo adresu względnego.',
|
|
embedUrl: 'Adres filmu YouTube',
|
|
embedInsert: 'Wstaw',
|
|
embedInvalid: 'Ten adres filmu nie jest obsługiwany. Wklej link do YouTube.',
|
|
cancel: 'Anuluj',
|
|
uploading: 'Wysyłanie {name}…',
|
|
uploadFailed: 'Wysyłanie nie powiodło się: {error}',
|
|
uploadTimeout: 'Wysyłanie {name} trwało zbyt długo.',
|
|
notAnImage: 'Można wysłać tylko obrazy JPEG, PNG, GIF i WebP.',
|
|
altText: 'Tekst alternatywny (wymagany)',
|
|
caption: 'Podpis (opcjonalny)',
|
|
altRequired: 'Wpisz tekst alternatywny.',
|
|
insertImage: 'Wstaw obraz',
|
|
rawHtmlCard: 'Blok HTML',
|
|
editAsHtml: 'Edytuj jako HTML',
|
|
embedCard: 'Osadzone wideo',
|
|
preview: 'Podgląd',
|
|
previewFrame: 'Podgląd wpisu',
|
|
}
|
|
|
|
const TABLES: Record<string, Labels> = { en, pl }
|
|
|
|
/**
|
|
* labelsFor returns the labels for the admin UI locale (the element's
|
|
* ui-locale attribute): the table for its language subtag, else English.
|
|
*/
|
|
export function labelsFor(uiLocale: string | null | undefined): Labels {
|
|
const language = (uiLocale ?? '').toLowerCase().split(/[-_]/)[0] ?? ''
|
|
return TABLES[language] ?? en
|
|
}
|
|
|
|
/** format replaces {name} placeholders in a label. */
|
|
export function format(label: string, values: Record<string, string>): string {
|
|
return label.replace(/\{(\w+)\}/g, (match, key: string) => values[key] ?? match)
|
|
}
|