Skip to content

fix: float translation layout#1188

Merged
mengxi-ream merged 2 commits intomainfrom
fix/1155-float-translation-layout
Mar 21, 2026
Merged

fix: float translation layout#1188
mengxi-ream merged 2 commits intomainfrom
fix/1155-float-translation-layout

Conversation

@ananaBMaster
Copy link
Copy Markdown
Collaborator

@ananaBMaster ananaBMaster commented Mar 21, 2026

Type of Changes

  • 🐛 Bug fix (fix)
  • ✨ New feature (feat)
  • 📝 Documentation change (docs)
  • 💄 UI/style change (style)
  • ♻️ Code refactoring (refactor)
  • ⚡ Performance improvement (perf)
  • ✅ Test related (test)
  • 🔧 Build or dependencies update (build)
  • 🔄 CI/CD related (ci)
  • 🌐 Internationalization (i18n)
  • 🧠 AI model related (ai)
  • 🔄 Revert a previous commit (revert)
  • 📦 Other changes that do not modify src or test files (chore)

Description

Preserves float-based article layouts during bilingual page translation by marking block translations that appear beside active floated siblings and rendering those translations as block content instead of inline-block boxes.

This keeps translated paragraphs in the same readable flow on pages like Wikipedia while preserving existing block translation insertion behavior and adding regression coverage for float-adjacent content.

Related Issue

Closes #1155

Related:

How Has This Been Tested?

  • Added unit tests
  • Verified through manual testing

Commands run:

  • SKIP_FREE_API=true pnpm vitest run src/utils/host/__tests__/node-translate.test.tsx src/utils/host/__tests__/translate.integration.test.tsx src/assets/styles/__tests__/translation-node-preset.test.ts
  • pnpm tsc --noEmit
  • pnpm build

Screenshots

N/A

Checklist

  • I have tested these changes locally
  • I have updated the documentation accordingly if necessary
  • My code follows the code style of this project
  • My changes do not break existing functionality
  • If my code was generated by AI, I have proofread and improved it as necessary.

Additional Information

  • This PR contains two commits:
    • fix: keep bilingual block translations inside float flow
    • fix: render float-wrapped translations as block content
  • The float-wrap override intentionally stays scoped to data-read-frog-float-wrap="true" instead of changing every block translation globally.

Summary by cubic

Fixes bilingual translation layout around floated elements so translated blocks stay beside floats instead of dropping below. This keeps article flow readable on sites like Wikipedia.

  • Bug Fixes
    • Detects active floated siblings and marks adjacent block translations with data-read-frog-float-wrap="true".
    • Renders marked translations as block in translation-node-preset.css, scoped only to the attribute.
    • Adds integration and CSS tests to cover float-adjacent behavior.

Written for commit ef8e28c. Summary will update on new commits.

@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Mar 21, 2026

🦋 Changeset detected

Latest commit: ef8e28c

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@read-frog/extension Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dosubot dosubot bot added the size:L This PR changes 100-499 lines, ignoring generated files. label Mar 21, 2026
@github-actions github-actions bot added the fix label Mar 21, 2026
Copy link
Copy Markdown
Contributor

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 6 files

@dosubot
Copy link
Copy Markdown

dosubot bot commented Mar 21, 2026

Documentation Updates

2 document(s) were updated by changes in this PR:

Translation Node Styling
View Changes
@@ -36,6 +36,23 @@
 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:
+
+```css
+.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:
Translation Toggle Logic and Content Detection
View Changes
@@ -11,7 +11,7 @@
 
 To find the wrapper for a translated node, `findPreviousTranslatedWrapper(node: Element | Text, walkId: string)` checks if the node itself is a wrapper (with a different walkId) or looks for a wrapper as a child that doesn't match the current walkId. The wrapper element always includes a `data-read-frog-translation-mode` attribute indicating the mode (`bilingual` or `translationOnly`) and a `data-read-frog-walked` attribute for walk tracking.
 
-The system uses additional DOM attributes and classes to label nodes during traversal, such as `WALKED_ATTRIBUTE`, `BLOCK_ATTRIBUTE`, `INLINE_ATTRIBUTE`, and `PARAGRAPH_ATTRIBUTE`, which help distinguish between block and inline nodes and manage translation state.
+The system uses additional DOM attributes and classes to label nodes during traversal, such as `WALKED_ATTRIBUTE`, `BLOCK_ATTRIBUTE`, `INLINE_ATTRIBUTE`, and `PARAGRAPH_ATTRIBUTE`, which help distinguish between block and inline nodes and manage translation state. The `FLOAT_WRAP_ATTRIBUTE` (`data-read-frog-float-wrap`) is applied to block translations when they should maintain layout flow around floated sibling elements.
 
 **Exclusion of Hidden Elements:**
 Elements that are visually hidden or marked as not intended for user visibility are explicitly excluded from translation and text extraction. This includes:
@@ -71,6 +71,15 @@
 
 **Empty Block Element Handling:**
 During traversal, empty block elements (elements where `textContent?.trim() === ""` and not forced as block) are ignored to simplify the translation logic. This prevents unnecessary processing of decorative or structural elements without text content and avoids splitting paragraphs at empty block descendants.
+
+**Float Layout Detection:**
+When rendering block translations, the system detects if there are floated elements (CSS `float: left` or `float: right`) that would cause the translation to drop below them. The detection logic includes:
+- `isFloatedElement()`: Checks if an element has CSS float left or right
+- `hasVisibleLayoutBox()`: Verifies the element has non-zero width and height
+- `findActiveFloatSibling()`: Searches for floated elements in sibling nodes that vertically overlap with the paragraph being translated
+- `shouldWrapInsideFloatFlow()`: Determines if a translation needs the float-wrap attribute
+
+When an active floated sibling is detected, the `data-read-frog-float-wrap="true"` attribute is added to the block translation element. This triggers the CSS rule `.read-frog-translated-block-content[data-read-frog-float-wrap="true"]` which applies `display: block !important;` to preserve layout flow. This prevents translations from dropping below floated images, info boxes, or other floated content on sites like Wikipedia. The detection runs during translation insertion for any element marked with the paragraph attribute.
 
 For example, a translated block in bilingual mode:
 
@@ -172,6 +181,12 @@
 - The alert component uses the `role="alert"` attribute for accessibility and proper testing
 - Custom action errors follow the same inline alert pattern for consistency across all selection toolbar features
 
+**Float Layout Tests:**
+Integration tests verify the float layout detection and handling:
+- In bilingual mode, block translations are marked with `data-read-frog-float-wrap="true"` when the translated content would drop below an active floated sibling
+- Block translations that stay beside floated siblings do not receive the float-wrap attribute
+- The CSS test suite confirms that `.read-frog-translated-block-content[data-read-frog-float-wrap="true"]` applies `display: block !important;` to maintain layout flow around floated elements
+
 ### User Experience Improvements
 A translation mode selector is now available in the popup UI, allowing users to easily switch between bilingual and translation-only modes. The selector uses localized labels and provides tooltips for additional guidance. If a user selects a mode that is not supported by the current provider, the system automatically switches to a compatible provider, ensuring seamless operation and reducing the likelihood of errors. This smart fallback mechanism improves reliability and user confidence in the translation feature.
 

How did I do? Any feedback?  Join Discord

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: ef8e28ca25

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

Comment on lines +38 to +40
const floatCandidates = [sibling, ...sibling.querySelectorAll<HTMLElement>("*")]
for (const candidate of floatCandidates) {
if (!isFloatedElement(candidate) || !hasVisibleLayoutBox(candidate))
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Cache float candidates per container to avoid quadratic scans

findActiveFloatSibling rebuilds floatCandidates from every sibling subtree for each translated paragraph, then immediately runs style/layout reads (getComputedStyle/getBoundingClientRect) on those nodes. On long article containers this turns bilingual translation into repeated full-DOM scans with forced reflow, so translation latency grows roughly with page size and can cause visible jank/freezes in production pages with many paragraphs. Consider collecting active float nodes once per flow container (or limiting to nearby siblings) and reusing that result across insertions.

Useful? React with 👍 / 👎.

@mengxi-ream mengxi-ream merged commit 234998a into main Mar 21, 2026
9 checks passed
@mengxi-ream mengxi-ream deleted the fix/1155-float-translation-layout branch March 21, 2026 18:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] 翻译文本导致网页原有的浮动环绕排版(Float)被破坏

2 participants