Available Translation Node Styles#
Note on Package Structure (v1.17.0 and later)#
As of version 1.17.0, the backend part of the package is private and only the browser extension is distributed publicly. The extension and backend are now maintained as separate components. This documentation covers the extension's translation node styling features.
Available Translation Node Styles#
Translation node styles are now configurable as either a preset or a custom CSS style. The available preset styles are defined as an enum and include:
default(normal): No special styling is applied to the translated text node.blur: Applies a blur effect to the translated text, which is removed on hover.blockquote: Renders the translation with a blockquote-style left border and padding.weakened: Displays the translation in a muted color to visually de-emphasize it.dashedLine: Underlines the translated text with a dashed line in the primary color.border: Highlights the translated text with a 1px solid border in the primary color, 2px vertical and 4px horizontal padding, 4px border-radius.textColor: Colors the translated text with the primary color.background: Highlights the translated text with a subtle background using the primary color, 2px vertical and 4px horizontal padding, 4px border-radius.
These preset styles are centrally enumerated and validated in the configuration schema. In addition, users can enable a custom CSS mode, allowing them to define their own CSS rules for translation nodes. When custom CSS is enabled, the preset is ignored and the user's CSS is injected for translation results.
Custom CSS is entered in the options page via a code editor, with syntax validation and a live preview. The custom CSS is injected using modern browser APIs for performance and safety, with a fallback to a
Style Loading and Injection#
The extension uses an ensurePresetStyles() function to guarantee that preset CSS styles from translation-node-preset.css are loaded before any UI elements render. This mechanism prevents FOUC (Flash of Unstyled Content) by ensuring styles are available when needed.
The ensurePresetStyles() function is called in two key locations:
-
Host content script initialization (
src/entrypoints/host.content/index.tsx): The function is called with thedocumentroot when the content script starts, ensuring styles are available for all translation UI elements on the page. -
Spinner creation (
src/utils/host/translate/ui/spinner.ts): Before creating spinner elements increateSpinnerInside(), the function is called with the appropriate root context—either the containing shadow root or the document—to ensure styles are loaded in the correct DOM scope.
The function works with both regular documents and shadow roots, accepting the appropriate root context as a parameter. This ensures that preset styles are available regardless of whether translation UI elements are rendered in the main document or within shadow DOM trees.
Visual Effects and CSS#
Translation nodes now preserve line breaks and whitespace in translated content. The extension applies white-space: pre-wrap to translation nodes, ensuring that newlines in the translated text are displayed as line breaks. Additionally, when rendering translated content, newline characters (\n) are converted to <br> elements for accurate display. This behavior applies to both preset and custom styles.
When writing custom CSS, be aware that the default style includes white-space: pre-wrap to maintain the original formatting of the translated text, including line breaks from the source content. If you override this property in your custom CSS, line breaks may not display as intended.
For example, if your translated text contains multiple lines, each line will appear as a separate line in the rendered output, matching the original structure (such as tweets or posts with line breaks). This ensures that translations of social media posts and similar content retain their intended formatting.
Float Layout Preservation#
The .read-frog-translated-block-content class has a conditional variant for preserving layout flow around floated elements:
.read-frog-translated-block-content[data-read-frog-float-wrap="true"] {
display: block !important;
}
This rule is automatically applied to block translations when they need to preserve layout flow around floated elements:
- The
data-read-frog-float-wrap="true"attribute is automatically added by the translation insertion logic when it detects that a paragraph has an active floated sibling element (such as a floated image or info box). - The
display: block !important;override prevents the translated content from dropping below floated elements and instead keeps it flowing beside them, matching the original content's behavior. - This is particularly important for sites like Wikipedia that heavily use floated layout elements for images, info boxes, and navigation elements.
- The float-wrap behavior preserves the original page's layout and maintains readability in bilingual mode by ensuring translated paragraphs stay in their intended position relative to floated content.
Options Page: Selection and Preview#
Users can select their preferred translation node style in the options page. The UI now provides:
- A switch to enable or disable custom CSS mode (
Use Custom Style). - When custom CSS is disabled, a dropdown selector lists all available preset styles, with localized names.
- When custom CSS is enabled, a CSS code editor appears, allowing users to enter any valid CSS rules. You must include the selector
[data-read-frog-custom-translation-style='custom']in your CSS. The editor provides syntax highlighting, live linting, a color picker for color values, and enforces an 8KB limit. A link to a tutorial is available for guidance and examples. - A live preview displays both the original and translated text, applying the chosen style (preset or custom) dynamically. The preview updates in real time as the user edits their CSS.
- When custom CSS is enabled, the preview now includes additional controls:
- A language selector, allowing users to preview how their custom style appears for different target languages (affecting font and direction).
- A text direction selector (LTR/RTL), to test right-to-left languages and direction-sensitive styles.
- An editable translated text field, so users can test their styles with different content.
- The preview's DOM structure now matches the actual translation node structure used on web pages, ensuring that the preview accurately reflects real translation rendering and style application (including font-family overrides).
Validation messages and save status are shown below the editor. The UI is fully localized and matches the main application's rendering logic.
Configuration Schema#
The translation node style is now stored in the configuration under translate.translationNodeStyle as an object:
export const translationNodeStyleConfigSchema = z.object({
preset: translationNodeStylePresetSchema, // enum of preset styles
isCustom: z.boolean(), // true if custom CSS is enabled
customCSS: z.string().max(8192).nullable(), // user CSS, up to 8KB
})
preset: The selected preset style (ignored ifisCustomis true).isCustom: If true, custom CSS mode is enabled andcustomCSSis used.customCSS: The user's custom CSS rules (nullable, validated for length).
The default value for new installs is { preset: 'textColor', isCustom: false, customCSS: null }. For users upgrading from previous versions, their existing preset selection is preserved. The configuration is validated and merged using standard project mechanisms.
Migration Steps#
When upgrading from versions prior to v30, the migration script automatically restructures the translationNodeStyle property from a simple string to an object with preset, isCustom, and customCSS fields. Existing preset selections are preserved, and custom CSS is initialized as null. No manual intervention is required for existing users; their configuration will be seamlessly upgraded.
Note: For new installs, the default preset style is now textColor. Existing users retain their previous style selection after migration.
Important: If you previously saved only CSS declarations (e.g., color: blue;), you must now wrap your rules with the selector before saving:
[data-read-frog-custom-translation-style='custom'] {
/* your styles */
}
Example migration:
- Before (v29):
"translationNodeStyle": "blur" - After (v30):
"translationNodeStyle": { "preset": "blur", "isCustom": false, "customCSS": null }
If you use custom CSS, update your saved styles to include the selector as shown above.
Localization Support#
All translation node style names, as well as the title and description for the style selector, are localized. Localization files now also provide translations for:
- The custom style switch (
useCustomStyle,useCustomStyleDescription) - The preset selector (
presetStyle) - The CSS editor (
cssEditor,customCSS.editor.placeholder,customCSS.editor.saveButton,customCSS.editor.savedButton) - Validation messages (
customCSS.editor.validation.*) - The preview section (
preview) - Preview controls for custom style:
- Language selector (
stylePreviewLanguage) - Direction selector (
stylePreviewDirection) - Editable translated text label (
stylePreviewTranslatedText)
- Language selector (
These keys are used throughout the options page UI to provide a localized experience for English, Japanese, Korean, Simplified Chinese, and Traditional Chinese.
Extensibility#
To add a new preset translation node style, update the TRANSLATION_NODE_STYLE constant, extend the CSS in the preset stylesheet (translation-node-preset.css), add localization entries, and update the configuration schema. The system is designed for straightforward extension and robust validation.
With custom CSS support, users can now define arbitrary styles without needing to extend the preset list. The custom CSS editor and validation logic ensure safe and performant application of user-defined styles.
Note: As of recent refactoring, translation node preset styles are organized in src/assets/styles/translation-node-preset.css, extracted from the main host content stylesheet for better maintainability and organization.