locales: the panel's words (wb.*), 51 languages

- 668 wb.* messages for the panel (navigation, settings search, accounts, updates, Appearance, the
  Theme Builder, fonts, plugins, custom CSS, Make, Power User, settings, backup and sync, developer
  mode, the controls), moved with every translation from wayBetter for X's catalogs; `{site}`
  stands where the English said "X" (49 keys; the app passes "X", so X reads the same). Keys that
  named X got site-neutral names (settings.links.site*, settings.language.followSite*,
  builder.leadingSite, builder.liveOnSite, fonts.asSite, make.siteDefaultLeading, features.default).
  English source: shell/src/panel/panelMessages.ts.
- One translation could not take `{site}` (hu wb.settings.alerts.hint never named the site) and
  falls back to English.
- locales/en.meta.json: the translator notes of the moved keys (40), among them the one fragment a
  language may leave empty (wb.make.step2Before); the catalog test reads it.
- runtime/tests/i18n.test.ts: en.json is the kit, shell-model, store, shell-frame and panel source.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
CRTkafa 2026-09-30 14:03:09 +07:00
parent 479d3d0019
commit 7a3f23aa82
53 changed files with 33525 additions and 54 deletions

View file

@ -0,0 +1,677 @@
// The panel's words in English (`wb.*`), the source of the framework catalogs
// (`waybetter/locales/<bcp47>.json`). Placeholders: `{site}` is the site's name ("X"); the rest
// are counts, names and paths. The panel reads the translations through the app's i18n instance
// (setShellI18n); tests/panel.test.ts checks that every key the panel uses is here.
export const PANEL_MESSAGES = {
'wb.appearance.accent': 'Accent',
'wb.appearance.accentColor': 'Accent color',
'wb.appearance.accentHint': 'Links, the active tab, focus rings and filled buttons.',
'wb.appearance.accountTheme': 'Account theme · {name}',
'wb.appearance.accountsHint': 'Every pane of an account shows its theme unless the pane has its own.',
'wb.appearance.appTheme': 'App theme · {name}',
'wb.appearance.askFonts': 'Download fonts for this theme',
'wb.appearance.askFontsText': 'Download {count, plural, one {it} other {them}} now? wayBetter fetches the font files once from fonts.googleapis.com and fonts.gstatic.com into its app data (open-source licenses). Until then the theme falls back to its other fonts.',
'wb.appearance.askFontsTitle': '“{name}” uses {fonts} from Google Fonts',
'wb.appearance.avatars': 'Avatars',
'wb.appearance.avatars.circle': 'Circle',
'wb.appearance.avatars.rounded': 'Rounded',
'wb.appearance.background': 'Background',
'wb.appearance.backgroundHint': 'The canvas around {site}\'s columns. Text on it stays readable.',
'wb.appearance.basedOn': 'Based on {name}.',
'wb.appearance.bg.clouds': 'Clouds',
'wb.appearance.bg.diagonal': 'Diagonal lines',
'wb.appearance.bg.dots': 'Dots',
'wb.appearance.bg.glow': 'Glow',
'wb.appearance.bg.grid': 'Grid',
'wb.appearance.bg.image': 'Photo…',
'wb.appearance.bg.imageHint': 'PNG, JPEG, WebP, GIF or AVIF up to 800 KB',
'wb.appearance.bg.none': 'Plain',
'wb.appearance.bg.paper': 'Paper grain',
'wb.appearance.bg.scanlines': 'Scanlines',
'wb.appearance.bold': 'Bold weight',
'wb.appearance.bold.bold': 'Bold',
'wb.appearance.bold.heavy': 'Heavy',
'wb.appearance.bold.medium': 'Medium',
'wb.appearance.boldHint': 'Names, headings and buttons.',
'wb.appearance.chrome': 'Theme wayBetter’s window',
'wb.appearance.chromeHint': 'Tabs, address bar, titlebar and this panel take the theme’s colors and its window font. Off keeps wayBetter’s own Night Ink look.',
'wb.appearance.corners': 'Corners',
'wb.appearance.corners.crisp': 'Crisp',
'wb.appearance.corners.round': 'Round',
'wb.appearance.corners.soft': 'Soft',
'wb.appearance.corners.square': 'Square',
'wb.appearance.cornersHint': 'Cards, media, menus and buttons.',
'wb.appearance.crt': 'CRT overlay',
'wb.appearance.crtHint': 'Scanlines and a vignette over the whole page.',
'wb.appearance.cssApplied': 'CSS applied to {name}.',
'wb.appearance.cssLines': '{count, plural, one {# line} other {# lines}} · Ctrl+S applies',
'wb.appearance.customName': '{name} (custom)',
'wb.appearance.customize': 'Customize {name}',
'wb.appearance.customizeHint': 'Changes apply to {site} immediately and stay on top of this theme until you reset or switch themes.',
'wb.appearance.density': 'Density',
'wb.appearance.density.compact': 'Compact',
'wb.appearance.density.default': 'Default',
'wb.appearance.density.roomy': 'Roomy',
'wb.appearance.densityHint': 'Space around each post.',
'wb.appearance.dim': 'Photo dimming',
'wb.appearance.dimHint': 'A layer of the page color over the photo keeps the navigation legible.',
'wb.appearance.downloaded': 'Downloaded fonts',
'wb.appearance.downloadedEmpty': 'Google Fonts you pick in a font role are downloaded once and listed here.',
'wb.appearance.downloadedFont': 'Downloaded {family}.',
'wb.appearance.downloadedHint': '{count, plural, one {# Google Fonts family} other {# Google Fonts families}} · {size} in wayBetter’s app data. They work offline.',
'wb.appearance.families': 'Families',
'wb.appearance.familiesHint': 'Google Fonts are open source (SIL Open Font License 1.1 or Apache License 2.0). Removing one makes themes that use it fall back to their other fonts.',
'wb.appearance.followAccount': 'Follow account / app',
'wb.appearance.followApp': 'Follow the app theme',
'wb.appearance.followsApp': 'Follows the app theme · {name}',
'wb.appearance.fonts': 'Fonts',
'wb.appearance.fontsHint': 'Which font goes where. Every role inherits the interface font until you give it one: Google Fonts (downloaded once), Geist, or any installed font.',
'wb.appearance.hover': 'Hover',
'wb.appearance.hover.lift': 'Lift',
'wb.appearance.hover.none': 'None',
'wb.appearance.hover.tint': 'Tint',
'wb.appearance.hoverEffect': 'Hover effect',
'wb.appearance.hoverHint': 'What a post does under the pointer.',
'wb.appearance.imageTooLarge': 'That image is too large. Keep it under about 800 KB (a 1920px JPEG usually is).',
'wb.appearance.imageType': 'Use a PNG, JPEG, WebP, GIF or AVIF image.',
'wb.appearance.importJson': 'Import JSON',
'wb.appearance.importSafe': 'Unknown fields are ignored; unsafe values are dropped.',
'wb.appearance.importText': 'A .json theme document with colors, fonts, shape, layout, background and effects. Drop it here, or export any theme to see the format. Google fonts it names are downloaded only if you say so.',
'wb.appearance.importTitle': 'Import a theme file',
'wb.appearance.imported': 'Imported “{name}”.',
'wb.appearance.mode.auto': 'Follows {site}',
'wb.appearance.mode.dark': 'Dark',
'wb.appearance.mode.light': 'Light',
'wb.appearance.motion': 'Motion',
'wb.appearance.motion.lively': 'Lively',
'wb.appearance.motion.subtle': 'Subtle',
'wb.appearance.motionHint': 'Hover and state transitions. Reduced-motion settings are respected.',
'wb.appearance.noneYet': 'None yet',
'wb.appearance.ownTheme': 'Own theme',
'wb.appearance.pane': 'pane',
'wb.appearance.panes': 'Panes',
'wb.appearance.panesEmpty': 'Open {site} panes appear here.',
'wb.appearance.panesHint': 'A pane’s own theme wins over its account’s. Closed panes forget theirs.',
'wb.appearance.pasteJson': '…or paste theme JSON here',
'wb.appearance.percent': '{value, number, percent}',
'wb.appearance.px': '{value} px',
'wb.appearance.removeNamed': 'Remove {name}',
'wb.appearance.removeTheme': 'Remove theme',
'wb.appearance.removedFont': 'Removed {family}.',
'wb.appearance.removedTheme': 'Removed “{name}”.',
'wb.appearance.saveAsTheme': 'Save as theme',
'wb.appearance.saved': 'Saved “{name}”. You can export or rename it by editing the JSON.',
'wb.appearance.savedName': '{name} custom',
'wb.appearance.scopes': 'Where themes apply',
'wb.appearance.scopesHint': 'Give an account or a single pane its own theme. A pane’s ⋯ menu (next to Split) does the same.',
'wb.appearance.sidebarWidth': 'Sidebar width',
'wb.appearance.textSize': 'Text size',
'wb.appearance.textSizeHint': 'Scales {site}\'s own text sizes.',
'wb.appearance.theme': 'Theme',
'wb.appearance.themeCss': 'Theme CSS',
'wb.appearance.themeCssHint': 'CSS that belongs to this theme: it is exported and saved with it. For CSS that applies to every theme, use Custom CSS below.',
'wb.appearance.themeCssLabel': 'CSS for this theme',
'wb.appearance.themeFor': 'Theme for {name}',
'wb.appearance.themeHint': 'A theme restyles {site} itself and this window: type, corners, density, layout, canvas and motion, with readable contrast guaranteed.',
'wb.appearance.themeJson': 'Theme JSON',
'wb.appearance.timeline': 'Timeline',
'wb.appearance.timeline.cards': 'Cards',
'wb.appearance.timeline.flat': 'Flat',
'wb.appearance.timeline.framed': 'Framed',
'wb.appearance.timelineHint': 'Flat rows, a framed column, or posts as separate cards.',
'wb.appearance.timelineStyle': 'Timeline style',
'wb.appearance.timelineWidth': 'Timeline width',
'wb.appearance.you': 'You',
'wb.appearance.yours': 'Yours',
'wb.backup.anotherComputer': 'another computer',
'wb.backup.applied': 'Applied {count, plural, one {# section} other {# sections}}.',
'wb.backup.applySection': 'Apply {section}',
'wb.backup.applySelected': 'Apply selected',
'wb.backup.applying': 'Applying…',
'wb.backup.chosen': '{count} of {total} sections · the rest stays as it is',
'wb.backup.comparing': 'Comparing with this computer…',
'wb.backup.encryptedSnapshot': 'Encrypted snapshot',
'wb.backup.export': 'Export settings',
'wb.backup.exportButton': 'Export settings…',
'wb.backup.exportHint': 'Themes (incl. account and pane themes), plugins you enabled and your own plugin files, custom CSS, {site} tweaks, links, keyword alerts, decks, workspaces and your account list. Never cookies, {site} sessions, tokens or keys.',
'wb.backup.exportedAt': 'Exported {when}',
'wb.backup.exporting': 'Exporting…',
'wb.backup.hint': 'Everything you set up, in one .waybetter file: move it to another computer or keep it safe.',
'wb.backup.import': 'Import settings',
'wb.backup.importButton': 'Import…',
'wb.backup.importFile': 'Import {file}',
'wb.backup.importHint': 'Opens a .waybetter file and shows what would change. Pick the sections to apply; nothing changes before you confirm.',
'wb.backup.includeDrafts': 'Include drafts',
'wb.backup.noKnown': 'This file has no settings wayBetter knows.',
'wb.backup.saved': 'Saved {file}.',
'wb.backup.status.changes': 'Changes',
'wb.backup.status.new': 'New',
'wb.backup.status.same': 'Same',
'wb.backup.syncedAgo': 'Synced {when} · encrypted snapshot',
'wb.backup.title': 'Backup',
'wb.backup.unknownDate': 'unknown date',
'wb.builder.adjusted': 'Adjusted {count, plural, one {# color pair} other {# color pairs}} to pass.',
'wb.builder.allPass': 'All pass',
'wb.builder.angle': 'Angle',
'wb.builder.author': 'Author',
'wb.builder.auto': 'Auto',
'wb.builder.autoFix': 'Auto-fix {count}',
'wb.builder.backgroundColor': 'Background color',
'wb.builder.backgroundEffects': 'Background and effects',
'wb.builder.buttonShape': 'Button shape',
'wb.builder.buttons': 'Buttons',
'wb.builder.cardCorners': 'Card corners',
'wb.builder.colors': 'Colors',
'wb.builder.colorsHint': 'Pick three; every other role is derived from them with the same proportions as the built-in themes. Click a role to set it by hand.',
'wb.builder.contrast': 'Contrast',
'wb.builder.contrast.accent-bg': 'Links and accent',
'wb.builder.contrast.accent-elevated': 'Links on hover',
'wb.builder.contrast.button-label': 'Post button label',
'wb.builder.contrast.button-page': 'Post button on the page',
'wb.builder.contrast.muted-bg': 'Secondary text',
'wb.builder.contrast.muted-surface': 'Secondary text on cards',
'wb.builder.contrast.text-bg': 'Text on background',
'wb.builder.contrast.text-page': 'Text on the page canvas',
'wb.builder.contrast.text-surface': 'Text on cards and menus',
'wb.builder.contrastHint': 'What {site} draws with this palette. wayBetter enforces these levels on {site} either way; Auto-fix makes the draft itself pass.',
'wb.builder.copyFailed': 'Could not copy to the clipboard.',
'wb.builder.cover': 'Cover',
'wb.builder.cssHint': 'Free-form CSS that travels with this theme (same trust as your own Custom CSS).',
'wb.builder.cssLines': '{count, plural, one {# line} other {# lines}} · applied live',
'wb.builder.deep': 'Deep',
'wb.builder.derived': 'Derived',
'wb.builder.description': 'Description',
'wb.builder.dimming': 'Dimming',
'wb.builder.fit': 'Fit',
'wb.builder.from': 'From',
'wb.builder.gradient': 'Gradient',
'wb.builder.gradientAngle': 'Gradient angle',
'wb.builder.gradientEnd': 'Gradient end',
'wb.builder.gradientStart': 'Gradient start',
'wb.builder.ink': 'Ink',
'wb.builder.leading': 'Post line height',
'wb.builder.leadingSite': '{site}\'s',
'wb.builder.liveNote': 'Live on your {site} panes and this window. Nothing is saved until you save.',
'wb.builder.liveOff': 'Live preview on {site} is off; this miniature still follows every change.',
'wb.builder.liveOnSite': 'Live on {site}',
'wb.builder.ms': '{value} ms',
'wb.builder.name': 'Theme name',
'wb.builder.needs': 'needs {ratio}:1',
'wb.builder.paletteRoles': 'Palette roles',
'wb.builder.pattern': 'Pattern',
'wb.builder.patternInk': 'Pattern ink',
'wb.builder.patternScale': 'Pattern scale',
'wb.builder.patternStrength': 'Pattern strength',
'wb.builder.photo': 'Photo',
'wb.builder.photoFit': 'Photo fit',
'wb.builder.pill': 'Pill',
'wb.builder.preview': 'Preview',
'wb.builder.previewLive': 'Preview live on {site}',
'wb.builder.redo': 'Redo (Ctrl+Shift+Z)',
'wb.builder.regularWeight': 'Regular weight',
'wb.builder.replace': 'Replace…',
'wb.builder.role.border': 'Border',
'wb.builder.role.elevated': 'Elevated',
'wb.builder.role.inverse': 'Button',
'wb.builder.role.muted': 'Secondary text',
'wb.builder.role.onInverse': 'Button label',
'wb.builder.role.page': 'Page canvas',
'wb.builder.role.surface': 'Surface',
'wb.builder.saved': 'Saved “{name}” and switched to it.',
'wb.builder.savedMissing': 'Download {fonts} in its font roles to see {count, plural, one {it} other {them}} on {site}.',
'wb.builder.scale': 'Scale',
'wb.builder.setByHand': 'Set by hand',
'wb.builder.shadow': 'Shadow',
'wb.builder.shape': 'Shape and layout',
'wb.builder.share': 'Share',
'wb.builder.shared': 'Theme JSON copied. Anyone can paste it into Appearance → Import.',
'wb.builder.startFrom': 'Start from',
'wb.builder.startFromPlaceholder': 'Start from…',
'wb.builder.startedFrom': 'Started from {name}. Undo brings your draft back.',
'wb.builder.strength': 'Strength',
'wb.builder.text': 'Text',
'wb.builder.textColor': 'Text color',
'wb.builder.tile': 'Tile',
'wb.builder.to': 'To',
'wb.builder.tooLow': 'Too low',
'wb.builder.tracking': 'Letter spacing',
'wb.builder.type': 'Type',
'wb.builder.typeHint': 'Which font goes where. Every role inherits the interface font until you give it one.',
'wb.builder.undo': 'Undo (Ctrl+Z)',
'wb.builder.untitled': 'Untitled theme',
'wb.common.add': 'Add',
'wb.common.apply': 'Apply',
'wb.common.chooseFile': 'Choose file…',
'wb.common.clear': 'Clear',
'wb.common.clipboardUnavailable': 'Clipboard unavailable.',
'wb.common.copied': 'Copied.',
'wb.common.copy': 'Copy',
'wb.common.create': 'Create',
'wb.common.discard': 'Discard',
'wb.common.export': 'Export',
'wb.common.import': 'Import',
'wb.common.notNow': 'Not now',
'wb.common.removedNamed': '{name} removed.',
'wb.common.reset': 'Reset',
'wb.css.applied': 'Custom CSS applied to {site}.',
'wb.css.applied.short': 'Applied',
'wb.css.empty': 'Empty',
'wb.css.hint': 'Applied to every {site} tab on top of whichever theme is selected, like BetterDiscord\'s Custom CSS. CSS for one theme goes in Theme CSS above.',
'wb.css.label': 'Custom CSS for {site}',
'wb.css.title': 'Custom CSS',
'wb.css.unsaved': 'Unsaved changes',
'wb.dev.chooseTheme': 'Choose theme file…',
'wb.dev.desktopOnly': 'Developer mode is available in the desktop app.',
'wb.dev.errors': 'Load errors',
'wb.dev.errorsHint': 'Syntax errors are caught before a plugin reloads (the running version stays). Errors thrown while a plugin starts show here and as a toast in the {site} tab, with file and line.',
'wb.dev.hint': 'For writing plugins and themes: save a file and every {site} tab updates at once. Off by default; nothing is watched while it is off.',
'wb.dev.mode': 'Developer mode',
'wb.dev.modeHint': 'Watches the plugins folder, custom.css and the theme file below. Enabled plugins reload on save (stop, then start the new version); themes and CSS apply instantly.',
'wb.dev.noErrors': 'No errors',
'wb.dev.notAvailable': 'Not available here.',
'wb.dev.off': 'Developer mode off.',
'wb.dev.on': 'Developer mode on: saved files reload in every {site} tab.',
'wb.dev.pluginsFolder': 'Plugins folder',
'wb.dev.saveToReload': 'Save a plugin, custom.css or the theme file to reload it.',
'wb.dev.stopWatching': 'Stop watching',
'wb.dev.stoppedTheme': 'Stopped watching the theme file; {site} tabs show your theme again.',
'wb.dev.themeFile': 'Theme file',
'wb.dev.themeFileHint': 'A theme .json you are editing (Appearance → Export, or npm create waybetter theme). While developer mode is on it is shown in every {site} tab as a preview; nothing is saved until you import it.',
'wb.dev.title': 'Live reload',
'wb.dev.turnOn': 'Turn developer mode on to watch your files.',
'wb.dev.watching': 'Watching',
'wb.features.default': 'default',
'wb.fonts.asSite': 'As {site} draws it',
'wb.fonts.builtIn': 'Built-in & system',
'wb.fonts.category': 'Category',
'wb.fonts.category.all': 'All',
'wb.fonts.category.display': 'Display',
'wb.fonts.category.handwriting': 'Handwriting',
'wb.fonts.category.mono': 'Mono',
'wb.fonts.category.sans': 'Sans',
'wb.fonts.category.serif': 'Serif',
'wb.fonts.categoryName.display': 'Display',
'wb.fonts.categoryName.handwriting': 'Handwriting',
'wb.fonts.categoryName.mono': 'Monospace',
'wb.fonts.categoryName.sans': 'Sans serif',
'wb.fonts.categoryName.serif': 'Serif',
'wb.fonts.choice.humanist': 'Humanist (Segoe, Avenir)',
'wb.fonts.choice.mono': 'System mono',
'wb.fonts.choice.rounded': 'Rounded',
'wb.fonts.choice.serif': 'Serif (Charter, Georgia)',
'wb.fonts.choice.system': 'System UI',
'wb.fonts.choose': 'Choose a font',
'wb.fonts.chooseFor': 'Choose the font for: {role}',
'wb.fonts.detailEmpty': 'Pick a family to preview it with your own text, choose weights and use it for: {role}.',
'wb.fonts.downloadUseFor': 'Download and use for: {role}',
'wb.fonts.downloaded': 'Downloaded',
'wb.fonts.downloadedSize': 'Downloaded ({size})',
'wb.fonts.downloading': 'Downloading…',
'wb.fonts.families': 'Google Fonts families',
'wb.fonts.fineTune': 'Fine-tune {role}',
'wb.fonts.fineTuneTitle': 'Weight, size, spacing',
'wb.fonts.footer': 'Google Fonts are open source (SIL Open Font License 1.1 or Apache License 2.0; see each family’s page). wayBetter downloads the files you pick once, from fonts.googleapis.com and fonts.gstatic.com, into its app data; {site} never loads fonts from the web. Previews fetch only the letters shown.',
'wb.fonts.forRole': 'for: {role}',
'wb.fonts.fromWeight': 'from {weight}',
'wb.fonts.googleCount': '{count, plural, one {# open-source family} other {# open-source families}} from Google Fonts, previewed live.',
'wb.fonts.heaviest': 'Heaviest weight',
'wb.fonts.inUse': 'In use',
'wb.fonts.inheritAgain': 'Inherit again',
'wb.fonts.inherits': 'Inherits · {font}',
'wb.fonts.installedFont': 'A font installed on this computer',
'wb.fonts.installedPlaceholder': 'e.g. Iosevka, Avenir Next, SF Pro',
'wb.fonts.license': 'License and designers ↗',
'wb.fonts.lightest': 'Lightest weight',
'wb.fonts.loadingCatalog': 'Loading the catalog…',
'wb.fonts.monospace': 'Monospace',
'wb.fonts.noMatch': 'No family matches “{query}”.',
'wb.fonts.previewWeight': 'Preview weight',
'wb.fonts.role.chrome.hint': 'Tabs, address bar, titlebar and this panel.',
'wb.fonts.role.chrome.label': 'wayBetter window',
'wb.fonts.role.dialog.hint': 'Dialogs and toasts from plugins (the UI kit).',
'wb.fonts.role.dialog.label': 'Plugin dialogs',
'wb.fonts.role.heading.hint': 'Display names, profile names and page headings.',
'wb.fonts.role.heading.label': 'Names and headings',
'wb.fonts.role.interface.hint': 'All of {site}: navigation, buttons, menus. Every other role inherits it.',
'wb.fonts.role.interface.label': 'Interface',
'wb.fonts.role.mono.hint': 'Code blocks. Inherits a monospaced face.',
'wb.fonts.role.mono.label': 'Code',
'wb.fonts.role.numbers.hint': 'Like, repost and follower counts.',
'wb.fonts.role.numbers.label': 'Numbers',
'wb.fonts.role.post.hint': 'The text of posts and replies.',
'wb.fonts.role.post.label': 'Post text',
'wb.fonts.roleInherited': '{role} font: {font} (inherited). Change',
'wb.fonts.roleOwn': '{role} font: {font}. Change',
'wb.fonts.roleSize': '{role} size',
'wb.fonts.roleSpacing': '{role} letter spacing',
'wb.fonts.roleTabular': '{role} tabular figures',
'wb.fonts.roleWeight': '{role} weight',
'wb.fonts.sample': 'Sample text',
'wb.fonts.search': 'Search Google Fonts',
'wb.fonts.searchPlaceholder': 'Search Inter, Fraunces, Space Mono…',
'wb.fonts.showMore': 'Show {count} more of {total}',
'wb.fonts.size': 'Size',
'wb.fonts.source': 'Font source',
'wb.fonts.spacing': 'Spacing',
'wb.fonts.staticFiles': 'Each weight is a separate file (Latin and Latin Extended).',
'wb.fonts.systemHint': 'Fonts that ship with wayBetter, or any font installed on this computer.',
'wb.fonts.tabular': 'Tabular figures',
'wb.fonts.toWeight': 'to {weight}',
'wb.fonts.useFor': 'Use for: {role}',
'wb.fonts.useIt': 'Use it',
'wb.fonts.variable': 'Variable',
'wb.fonts.variableFile': 'One variable file covers every weight in the range (Latin and Latin Extended).',
'wb.fonts.variableRange': 'Variable {min}–{max}',
'wb.fonts.weight': 'Weight',
'wb.fonts.weightCount': '{count, plural, one {# weight} other {# weights}}',
'wb.fonts.weightsList': 'Weights {weights}',
'wb.fonts.weightsToDownload': 'Weights to download',
'wb.make.copiedDoc': '{doc} copied.',
'wb.make.copiedVar': '{name} copied.',
'wb.make.copyCommand': 'Copy: {command}',
'wb.make.copyMarkdown': 'Copy Markdown',
'wb.make.copyVar': 'Copy {name}',
'wb.make.create.app': 'A wayBetter app for another site',
'wb.make.create.plugin': 'A plugin',
'wb.make.create.pluginTs': 'A plugin in TypeScript',
'wb.make.create.theme': 'A theme',
'wb.make.demo.cannotUndo': 'This cannot be undone.',
'wb.make.demo.couldNotSave': 'Could not save',
'wb.make.demo.deleteNote': 'Delete this note?',
'wb.make.demo.exported': 'Exported',
'wb.make.demo.exportedText': 'Your list was saved to Downloads.',
'wb.make.demo.hideTrends': 'Hide trends',
'wb.make.demo.linkCopied': 'Link copied',
'wb.make.demo.min3': 'Use at least 3 characters.',
'wb.make.demo.myPlugin': 'My plugin',
'wb.make.demo.name': 'Name',
'wb.make.demo.postHidden': 'Post hidden',
'wb.make.demo.reading': 'Reading',
'wb.make.demo.renameList': 'Rename list',
'wb.make.demo.saved': 'Saved',
'wb.make.demo.undo': 'Undo',
'wb.make.demo.undoClicked': 'Undo clicked',
'wb.make.demo.whatHidden': 'What should be hidden?',
'wb.make.document': 'Document',
'wb.make.examples': 'Example plugins',
'wb.make.examplesHint': 'Pick one, change it, then copy or download the file.',
'wb.make.file': 'File',
'wb.make.fileName': 'File name',
'wb.make.fileRule': 'File names are letters, digits, spaces, -, _ or . and end in .plugin.js.',
'wb.make.fontsHint': 'The theme\'s font roles as --wb-font and the resolved stacks. Theme files set them with font.family and font.tweet.',
'wb.make.inCode': 'In code',
'wb.make.inCodeHint': 'Plugins read the same values; plugin CSS uses the variables.',
'wb.make.intro': 'Plugins are one *.plugin.js file with a class that has start() and stop(); themes are one JSON file. Both use the same wayBetter API every wayBetter app has. Start from an example here, or scaffold a project:',
'wb.make.kit.alert': 'Alert',
'wb.make.kit.confirm': 'Confirm',
'wb.make.kit.dialog': 'Dialog',
'wb.make.kit.prompt': 'Prompt',
'wb.make.kit.toast': 'Toast',
'wb.make.kit.toastAction': 'Toast with Undo',
'wb.make.kit.toastDanger': 'Danger toast',
'wb.make.kit.toastSuccess': 'Success toast',
'wb.make.kitHint': 'What this.scope.ui opens in {site}: the same kit, in the current theme. Dialogs draw above the panes; toasts stay inside this panel.',
'wb.make.kitTitle': 'Plugin UI kit',
'wb.make.liveAfter': 'show up here.',
'wb.make.liveBefore': 'Live:',
'wb.make.liveMiddle': 'as plugins in {site} see it now. Changes in',
'wb.make.loadingTheme': 'Loading the theme…',
'wb.make.openPluginsFolder': 'Open plugins folder',
'wb.make.pluginCopied': 'Plugin copied.',
'wb.make.pluginsList': 'Plugins list:',
'wb.make.reference': 'Reference:',
'wb.make.referenceBundled': '(bundled with the app, in English).',
'wb.make.role.accent': 'Links, focus',
'wb.make.role.bg': 'Main surface',
'wb.make.role.border': 'Lines',
'wb.make.role.elevated': 'Hover, selected',
'wb.make.role.inverse': 'Filled button',
'wb.make.role.muted': 'Secondary text',
'wb.make.role.onAccent': 'Text on accent',
'wb.make.role.onInverse': 'Its label',
'wb.make.role.page': 'Behind the columns',
'wb.make.role.surface': 'Cards, inputs',
'wb.make.role.text': 'Text',
'wb.make.savedDownloads': '{file} saved to Downloads.',
'wb.make.siteDefaultLeading': '{site} default',
'wb.make.source': 'Source of {file}',
'wb.make.step1': 'Copy or download the file and put it in the plugins folder as {file}.',
'wb.make.step2After': ', press Rescan and turn it on. It starts live in every {site} tab; turning it off calls stop().',
'wb.make.step2Before': 'In',
'wb.make.step3': 'Errors show in the {site} tab\'s console and in wayBetter.errors. wayBetter never installs plugin code by itself: only files you put in the folder run.',
'wb.make.tab.docs': 'Docs',
'wb.make.tab.kit': 'UI kit',
'wb.make.tab.theme': 'Theme API',
'wb.make.themeCopied': 'Theme copied.',
'wb.make.themeFile': 'A theme file',
'wb.make.themeFileHint': 'Three colors are enough; everything else is derived. Import it in Appearance → Import.',
'wb.make.warn.export': 'Export the plugin: module.exports = class \'{ start() {} stop() {} }\';',
'wb.make.warn.header': 'Start the file with a /** … */ header; without it the Plugins list shows only the file name.',
'wb.make.warn.permissions': 'No @permissions line: the plugin is listed as “legacy, full page access” and gets the whole API. Declare what it uses, e.g. @permissions storage, ui, network:none.',
'wb.make.warn.stop': 'Add stop() that undoes everything start() did (scope.dispose() does it for a scope).',
'wb.make.warn.tag': 'The header has no {tag}.',
'wb.panel.accounts.add': '+ Add account',
'wb.panel.accounts.hint': 'Each account is its own {site} sign-in on this computer and stays signed in across restarts. Click one to open its feed beside this pane.',
'wb.panel.accounts.newTabsBadge': 'new tabs',
'wb.panel.accounts.newTabsHere': 'New tabs here',
'wb.panel.accounts.newTabsTitle': 'New tabs (Ctrl+T) open in this account',
'wb.panel.accounts.openCount': '{count} open',
'wb.panel.accounts.openFeed': 'Open its feed beside this pane',
'wb.panel.accounts.removeConfirm': 'Remove “{name}” from this computer? {tabs, plural, =0 {} one {Its open tab closes, } other {Its # open tabs close, }}its sign-in and site data here are deleted. The {site} account itself is not touched.',
'wb.panel.accounts.signIn': 'Sign in',
'wb.panel.accounts.signInBeside': 'Sign in on {site} beside this pane',
'wb.panel.accounts.useForNewTabs': 'Use for new tabs',
'wb.panel.nav.label': 'wayBetter sections',
'wb.panel.search.for': 'for “{query}”',
'wb.panel.search.label': 'Search settings',
'wb.panel.search.none': 'No settings match',
'wb.panel.search.noneHint': 'Try a shorter word, like “font”, “logo” or “links”. Drafts have their own search in Drafts.',
'wb.panel.search.results': 'Results',
'wb.panel.section.accounts': 'Accounts',
'wb.panel.section.backup': 'Backup & sync',
'wb.panel.section.builder': 'Theme Builder',
'wb.panel.section.developer': 'Developer',
'wb.panel.section.home': 'wayBetter',
'wb.panel.section.make': 'Make',
'wb.panel.section.plugins': 'Plugins',
'wb.panel.section.power': 'Power User',
'wb.panel.section.settings': 'Settings',
'wb.panel.section.store': 'Store',
'wb.panel.section.themes': 'Appearance',
'wb.panel.section.updates': 'Updates',
'wb.panel.updates.checking': 'Checking for updates…',
'wb.panel.updates.download': 'Download',
'wb.panel.updates.downloading': 'Downloading an update…',
'wb.panel.updates.error': 'The last update check failed.',
'wb.panel.updates.hint': 'Signed updates are downloaded and verified natively. Tabs come back after the restart.',
'wb.panel.updates.idle': 'Updates are checked automatically in the background.',
'wb.panel.updates.installing': 'Installing the update…',
'wb.panel.updates.problem': 'The last update did not start correctly.',
'wb.panel.updates.ready': 'An update is downloaded and verified.',
'wb.panel.updates.restart': 'Restart & update',
'wb.panel.updates.upToDate': 'wayBetter for {site} is up to date.',
'wb.panel.updates.version': 'Version {version}',
'wb.plugins.deleteFile': 'Delete file',
'wb.plugins.enabled': '{name} enabled',
'wb.plugins.headerProblem': 'header problem',
'wb.plugins.hint': 'Install from the Store, drop a *.plugin.js file on the window (you see its code, hash and permissions first), or copy it into the plugins folder. Plugins run inside {site} with the page\'s access; permissions limit the wayBetter API, not the page. Only install code you trust.',
'wb.plugins.keep': 'Keep',
'wb.plugins.noVersion': 'no version',
'wb.plugins.none': 'No plugins yet',
'wb.plugins.noneHint': 'Add a file like this to the plugins folder, then Rescan.',
'wb.plugins.openFolder': 'Open folder',
'wb.plugins.rescan': 'Rescan',
'wb.plugins.source.file': 'Dropped file',
'wb.plugins.source.fileTitle': 'Installed from a file you dropped',
'wb.plugins.source.link': 'Link',
'wb.plugins.started': '{name} started.',
'wb.plugins.stopped': '{name} stopped.',
'wb.plugins.title': 'JavaScript plugins',
'wb.power.addAccountFirst': 'Add an account first',
'wb.power.columnCount': '{count, plural, one {# column} other {# columns}}',
'wb.power.columnsFlag': 'Columns: {flag}',
'wb.power.comfortable': 'Comfortable',
'wb.power.deckCreated': '{name} deck created.',
'wb.power.decks': 'Decks',
'wb.power.decksHint': 'Presets add a ready deck; you can change every column afterwards.',
'wb.power.densityComfortable': 'Columns are comfortable.',
'wb.power.densityCompact': 'Columns are compact.',
'wb.power.densityHint': 'Compact trims post padding and text size inside columns.',
'wb.power.flagOff': '{flag}: off in columns.',
'wb.power.flagOn': '{flag}: on in columns.',
'wb.power.guard': 'Memory guard',
'wb.power.hint': 'A TweetDeck-style deck: {site} columns side by side, each in the account you pick. Every column is a real {site} page; posts, likes and replies are {site}’s own.',
'wb.power.key.column': 'Previous / next column',
'wb.power.key.columnHint': '[ and ] (not while typing)',
'wb.power.key.jump': 'Jump to column 1–9',
'wb.power.key.page': 'Previous / next page',
'wb.power.key.post': 'Post from the deck',
'wb.power.key.postHint': 'Ctrl+Alt+N opens {site}’s composer in the dock; you press {site}’s Post',
'wb.power.key.read': 'Mark column read / jump to unread',
'wb.power.key.toggle': 'Deck and back',
'wb.power.keys': 'Keys',
'wb.power.memory': 'Memory',
'wb.power.memoryHint': 'Each column is a full {site} page. Measured on the developer\'s Windows machine: about {range} MB per column (whole app, 60 s idle).',
'wb.power.openDeck': 'Open deck',
'wb.power.park': 'Park off-page columns',
'wb.power.parkHint': 'Columns on another page drop caches and decoded images (WebView2’s low memory target). They keep running.',
'wb.power.parkOff': 'Off-page columns stay at normal memory.',
'wb.power.parkOn': 'Off-page columns are parked.',
'wb.power.perPage': 'Columns per page',
'wb.power.perPageGuard': 'More than {max} visible columns: about {mb} MB for the columns alone.',
'wb.power.perPageHint': 'Up to {count} columns on screen, about {mb} MB. The rest wait on the next page.',
'wb.power.perPageSaved': '{count, plural, one {# column} other {# columns}} per page.',
'wb.power.title': 'Power User Mode',
'wb.power.width': 'Column width',
'wb.power.widthHint': 'New columns start at this width; a page stretches its columns to fill the window.',
'wb.power.widthSaved': 'New columns are {width} px wide.',
'wb.settings.alerts.add': 'Add keyword',
'wb.settings.alerts.hint': 'A desktop notification when a post {site} already showed you mentions one of your words. Matching stays on this device; at most one alert per keyword a minute.',
'wb.settings.alerts.keywords': 'Keywords',
'wb.settings.alerts.keywordsHint': 'Up to {max}. Case does not matter. Separate several with commas.',
'wb.settings.alerts.label': 'Alerts',
'wb.settings.alerts.none': 'No keywords yet.',
'wb.settings.alerts.onCount': 'On · {count, plural, one {# keyword} other {# keywords}}',
'wb.settings.alerts.stopped': 'Stopped watching “{word}”.',
'wb.settings.alerts.title': 'Keyword alerts',
'wb.settings.alerts.turnedOff': 'Keyword alerts off.',
'wb.settings.alerts.turnedOn': 'Keyword alerts on.',
'wb.settings.alerts.watching': 'Watching “{word}”.',
'wb.settings.alerts.watchingMore': 'Watching {count, plural, one {# more keyword} other {# more keywords}}.',
'wb.settings.home.hint': 'Opens on first launch and in every new tab (Ctrl+T).',
'wb.settings.home.label': 'Home page',
'wb.settings.home.reset': 'Reset to {site}',
'wb.settings.home.resetDone': 'Home page reset to {site}.',
'wb.settings.home.saved': 'Home page saved.',
'wb.settings.home.url': 'Home page URL',
'wb.settings.language.active': 'Showing {language}',
'wb.settings.language.followSite': 'Follow {site}',
'wb.settings.language.followSiteHint': 'The language your {site} account is set to',
'wb.settings.language.followSiteNow': 'Now: {language}',
'wb.settings.language.followSystem': 'Follow system',
'wb.settings.language.followSystemHint': 'Your computer\'s language',
'wb.settings.language.help': 'Help translate',
'wb.settings.language.helpMachine': 'This {language} translation was drafted by a machine and has not been checked by people yet. Fixes are welcome.',
'wb.settings.language.helpReviewed': '{language}: {percent} translated and reviewed by volunteers.',
'wb.settings.language.helpTitle': 'Translation',
'wb.settings.language.hint': 'wayBetter speaks the languages {site}\'s own website offers. Changes apply at once to every window, {site} tab and plugin.',
'wb.settings.language.keywords': 'language locale translation dil sprache idioma langue',
'wb.settings.language.label': 'App language',
'wb.settings.language.machine': 'Machine-drafted',
'wb.settings.language.reviewed': 'Reviewed',
'wb.settings.language.title': 'Language',
'wb.settings.links.beside': 'Beside',
'wb.settings.links.browser': 'System browser',
'wb.settings.links.external': 'Links to other sites',
'wb.settings.links.externalHint': 'Beside opens a split next to the tab you clicked in and reuses it for the next link.',
'wb.settings.links.externalSaved': 'Links to other sites {how}.',
'wb.settings.links.hint': 'How tabs and links behave in the app.',
'wb.settings.links.newTab': 'New tab',
'wb.settings.links.opens.browser': 'open in your browser',
'wb.settings.links.opens.pane': 'open beside the tab',
'wb.settings.links.opens.same': 'open in place, as on {site}',
'wb.settings.links.opens.tab': 'open in a new tab',
'wb.settings.links.sameTab': 'Same tab',
'wb.settings.links.site': 'Links to {site} pages',
'wb.settings.links.siteHint': 'Posts, profiles, hashtags and lists you click in a timeline or hover card. Photos, videos, menus and {site}\'s navigation always stay in place.',
'wb.settings.links.siteSaved': '{site} pages {how}.',
'wb.settings.links.title': 'Tabs and links',
'wb.settings.media.addFolder': 'Add folder…',
'wb.settings.media.cleared': 'Clipboard history cleared.',
'wb.settings.media.clipboard': 'Clipboard history',
'wb.settings.media.clipboardHint': 'Keeps your recent copied images and texts on this device, from the next copy on. Off by default.',
'wb.settings.media.clipboardOff': 'Clipboard history off.',
'wb.settings.media.clipboardOn': 'Clipboard history on.',
'wb.settings.media.folderRemoved': 'Folder removed.',
'wb.settings.media.folders': 'Gallery folders',
'wb.settings.media.foldersHint': 'The newest images from these folders. Only files directly inside them are read.',
'wb.settings.media.hint': 'The Media panel (Ctrl+Shift+G) beside {site}.',
'wb.settings.media.keep': 'Items to keep',
'wb.settings.media.keepHint': 'Older items drop off the end.',
'wb.settings.media.noFolders': 'No folders yet. Add one to see its images in the Media panel.',
'wb.settings.media.title': 'Media',
'wb.settings.restore.hint': 'Reopen your tabs and split layout from last time. Pinned tabs always come back.',
'wb.settings.restore.label': 'Restore tabs on launch',
'wb.settings.restore.off': 'Tabs will not be restored.',
'wb.settings.restore.on': 'Tabs will be restored.',
'wb.sync.auto': 'Sync changes automatically',
'wb.sync.autoHint': 'Writes a new snapshot shortly after your settings change (the last 10 of this computer are kept).',
'wb.sync.change': 'Change…',
'wb.sync.check': 'Check for newer',
'wb.sync.chooseFolder': 'Choose folder…',
'wb.sync.choosePass': 'Choose a passphrase',
'wb.sync.choosePassHint': 'At least 8 characters. Use the same one on your other computers. It cannot be recovered: without it the snapshots cannot be read.',
'wb.sync.computerName': 'This computer\'s name',
'wb.sync.deriving': 'Deriving key…',
'wb.sync.differ': 'The passphrases differ.',
'wb.sync.folder': 'Sync folder',
'wb.sync.folderHint': 'Encrypted with a passphrase only you know (Argon2id + XChaCha20-Poly1305).',
'wb.sync.hint': 'Pick a folder you already sync (OneDrive, iCloud Drive, Dropbox, a network share). wayBetter writes encrypted snapshots of your settings there and offers newer ones on your other computers. No wayBetter server or account; drafts are never synced.',
'wb.sync.last': 'Last synced from here',
'wb.sync.lastHint': '{when} · {count, plural, one {# snapshot} other {# snapshots}} of this computer in the folder',
'wb.sync.lock': 'Lock',
'wb.sync.lockRemembered': 'The key is remembered on this computer (never in a backup or snapshot). Lock forgets it; you then enter the passphrase again.',
'wb.sync.lockSession': 'The key is kept only until wayBetter closes.',
'wb.sync.locked': 'Locked. Automatic sync pauses until you unlock.',
'wb.sync.new': 'new',
'wb.sync.newerFrom': 'Newer settings from {device}.',
'wb.sync.notYet': 'Not yet',
'wb.sync.nothingNewer': 'Nothing newer from your other computers.',
'wb.sync.now': 'Sync now',
'wb.sync.on': 'Encrypted · on',
'wb.sync.others': 'From your other computers',
'wb.sync.othersEmpty': 'Nothing yet. Set up sync with the same folder and passphrase on another computer.',
'wb.sync.othersHint': 'Review shows what would change; you pick the sections.',
'wb.sync.passphrase': 'Passphrase',
'wb.sync.passphraseLabel': 'Sync passphrase',
'wb.sync.problem': 'Problem',
'wb.sync.remember': 'Remember on this computer',
'wb.sync.rename': 'Rename',
'wb.sync.repeat': 'Repeat passphrase',
'wb.sync.repeatLabel': 'Repeat sync passphrase',
'wb.sync.review': 'Review…',
'wb.sync.setUp': 'Set up sync',
'wb.sync.setUpDone': 'Sync is set up. Your settings sync from now on.',
'wb.sync.stop': 'Stop syncing',
'wb.sync.stopped': 'Sync stopped on this computer. The folder and its snapshots stay.',
'wb.sync.syncing': 'Syncing…',
'wb.sync.thisComputer': 'This computer',
'wb.sync.thisComputerHint': 'How your other computers see this one.',
'wb.sync.title': 'Sync through a folder',
'wb.sync.unlock': 'Unlock',
'wb.sync.unlockPass': 'Unlock with your passphrase',
'wb.sync.unlockPassHint': 'The passphrase you chose on the computer that set up this folder.',
'wb.sync.unlocked': 'Unlocked.',
'wb.sync.written': 'Snapshot written.',
'wb.ui.chip.remove': 'Remove {item}',
'wb.ui.color.custom': '{label}: custom color',
'wb.ui.color.hex': '{label}: hex code',
'wb.ui.color.pick': 'Pick any color',
'wb.ui.search.clear': 'Clear search',
'wb.ui.select.placeholder': 'Choose…',
'wb.ui.stepper.decrease': 'Decrease {label}',
'wb.ui.stepper.increase': 'Increase {label}',
} as const;
export type PanelKey = keyof typeof PANEL_MESSAGES;