feat 阅读Markdown的翻译功能#130
Conversation
refactor(RepositoryCard): 增强工具提示在浅色模式下的可读性 feat(ReadmeModal): 添加字体大小类型支持 style(index.css): 改进文本区域和输入框的浅色模式样式 refactor(MarkdownRenderer): 移除行号显示并支持字体大小调整 refactor(RepositoryEditModal): 优化浅色模式下的表单样式和交互
Adjust Tailwind typography classes in MarkdownRenderer: use 'prose prose-sm' for the 'small' fontSize instead of 'prose-xs', and remove the explicit 'prose-sm' for the medium/default case to fall back to the base 'prose' class. This normalizes sizing across fontSize options.
Fix stacking and improve the AI search tooltip UI and copy. Lowered SortByDropdown menu z-index to z-40 and added explicit z-indexes for the search input (z-40) and sort controls (z-30) to resolve overlay issues. Reworked the info tooltip: wider, responsive sizing, unified light/dark backgrounds and borders, improved text color/spacing, enabled word-wrapping, and adjusted the tooltip arrow styling/position. Also replaced the previous conditional AI copy with a single bilingual description explaining the multi-dimensional weighted search/ranking algorithm.
添加 hasHydrated 状态用于检测 store 是否完成水合 在 App 组件中添加加载状态以确保主题正确应用 更新搜索算法权重描述文案
根据activeAIConfig状态动态显示不同的搜索模式说明,当启用AI配置时显示语义搜索模式说明,否则显示本地智能排序说明
将加载状态的渲染逻辑移动到useEffect之后,使组件初始化逻辑更清晰
将加载状态的渲染逻辑移到认证检查之前,确保主题正确应用后再进行认证检查
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
实现文档翻译核心功能,包括: 1. 添加query-string依赖处理URL参数 2. 创建翻译服务模块调用微软翻译API 3. 实现Markdown分割与重组工具 4. 在ReadmeModal中添加翻译UI控件 5. 创建useMarkdownTranslation自定义hook管理翻译状态
|
目前测试还有很多问题,个人能力有限。可以的话帮忙改下 |
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
✅ Files skipped from review due to trivial changes (1)
📝 WalkthroughWalkthroughAdds bilingual README translation: a translation service, DOM text scanner, and a BilingualMarkdownRenderer with translate/revert handles; ReadmeModal is wired for translation UI, TOC bilingual labels, and resizable TOC. Also adds language helpers, normalizes heading text in MarkdownRenderer, updates Tailwind colors, and adds a query-string dependency. ChangesBilingual README translation feature
Sequence Diagram(s)sequenceDiagram
participant User as User
participant Readme as ReadmeModal
participant Renderer as BilingualMarkdownRenderer
participant Scanner as domTextScanner
participant Service as translateService
participant API as TranslatorAPI
User->>Readme: Click "Translate"
Readme->>Renderer: translate()
Renderer->>Scanner: scanDomForTranslation(container)
Scanner-->>Renderer: segments[]
Renderer->>Service: translateBatch(segments)
Service->>API: apiMsAuth, POST translate requests
API-->>Service: translations
Service-->>Renderer: translated segments
Renderer->>Renderer: insert ATTR_TRANSLATION nodes / update progress
Renderer-->>Readme: onHeadingsTranslated / status updates
Readme-->>User: update UI (progress, mode, TOC labels)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Tip 💬 Introducing Slack Agent: The best way for teams to turn conversations into code.Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.
Built for teams:
One agent for your entire SDLC. Right inside Slack. Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Review rate limit: 7/8 reviews remaining, refill in 7 minutes and 30 seconds.Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/ReadmeModal.tsx (1)
158-206:⚠️ Potential issue | 🟠 Major | ⚡ Quick winRecompute TOC and heading IDs from the rendered content.
After translation,
MarkdownRenderergetsdisplayContent, buttocItems,headingIdMap, and the observer lifecycle are still derived fromreadmeContent. That means TOC clicks and active-section highlighting stop matching as soon as the heading text changes in the translated README.Also applies to: 235-235, 266-270, 557-563
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/ReadmeModal.tsx` around lines 158 - 206, The TOC, headingIdMap, and intersection observer are still based on readmeContent so translations break TOC/active-section syncing; update the useEffect and any logic that currently reads tocItems/headingIdMap from readmeContent to derive them from the rendered DOM/displayContent instead: in the useEffect that references contentRef, tocItems, readmeContent and the IntersectionObserver (the effect using setActiveHeadingId), recompute tocItems/headingIdMap by querying contentRef.current (e.g., headings and their ids/text) or use the MarkdownRenderer's displayContent output as the dependency, then observe those computed elements and update the effect dependency array to include displayContent (or the derived TOC) so observer lifecycle and TOC clicks reflect translated headings (apply same change for the other similar blocks mentioned).
🧹 Nitpick comments (1)
package.json (1)
25-29: ⚡ Quick winRemove
@types/query-stringfrom runtime deps.
query-stringalready ships its own TypeScript declarations, and@types/query-stringis a deprecated stub that explicitly says you do not need it installed. Keeping both here can pin stale v6 typings against the v9 runtime package. (npmjs.com)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@package.json` around lines 25 - 29, The package.json currently includes the deprecated runtime dependency "@types/query-string" alongside "query-string"; remove the "@types/query-string" entry from package.json (the dependency named "@types/query-string") so the project relies on the built-in TypeScript declarations shipped with "query-string", and then run your install (or update lockfile) to ensure the lockfile no longer pins the obsolete v6 typings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/services/translateService.ts`:
- Around line 122-126: The current parameter building in translateText and
translateBatchInternal always includes from via from || '', which prevents the
Microsoft Translator API from auto-detecting the source language; change both
functions (translateText and translateBatchInternal) to only include the from
key when a source language is explicitly provided (i.e., conditionally add from
to the params object or remove it when falsy) before calling
queryString.stringify so the from parameter is omitted entirely for
auto-detection.
- Around line 69-89: apiMsAuth currently ignores an AbortSignal and callers pass
signals expecting cancellation behavior; update apiMsAuth to accept an optional
signal parameter and pass that signal into the fetch call and any internal async
flows (including the shared tokenPromise) so token requests can be aborted, and
ensure tokenPromise is cleared on abort/failure; update the three callers
(translateText, translateBatch, translateBatchInternal) to forward their signal
into apiMsAuth; finally, change translateBatch to throw an actual AbortError
(e.g., new DOMException('Aborted', 'AbortError') or other AbortError class used
in the codebase) instead of Error('Aborted') so useMarkdownTranslation's
AbortError handling will work.
In `@src/utils/markdownSplitter.ts`:
- Line 17: The splitter's combinedRegex currently only protects triple-backtick
fences so fenced blocks using tilde fences (~~~) get passed through translation;
update the combinedRegex in markdownSplitter.ts (the variable combinedRegex) to
also match tilde-fenced blocks (e.g., include a branch like
(```[\s\S]*?```|~~~[\s\S]*?~~~)) so both fenced code blocks are treated as
non-translatable, keeping inline code (`...`), images/links patterns unchanged;
this mirrors extractToc()'s handling of both fence styles.
- Line 17: The combinedRegex currently treats entire markdown links/images as
non-translatable; update the regex (combinedRegex) to capture link label/alt
text and URL/src separately (e.g. use patterns like \!\[([^\]]*)\]\(([^)]+)\)
and \[([^\]]*)\]\(([^)]+)\)) so the label/alt text is a distinct capture group
from the URL, then change the tokenization logic that uses combinedRegex (and
the related handling in the block around lines 53-64) so it only freezes the
URL/src group while allowing the label/alt text group to be emitted as
translatable text. Ensure downstream code that maps capture groups to token
types is updated to treat group 1 as translatable and group 2 as a preserved
non-translatable token.
---
Outside diff comments:
In `@src/components/ReadmeModal.tsx`:
- Around line 158-206: The TOC, headingIdMap, and intersection observer are
still based on readmeContent so translations break TOC/active-section syncing;
update the useEffect and any logic that currently reads tocItems/headingIdMap
from readmeContent to derive them from the rendered DOM/displayContent instead:
in the useEffect that references contentRef, tocItems, readmeContent and the
IntersectionObserver (the effect using setActiveHeadingId), recompute
tocItems/headingIdMap by querying contentRef.current (e.g., headings and their
ids/text) or use the MarkdownRenderer's displayContent output as the dependency,
then observe those computed elements and update the effect dependency array to
include displayContent (or the derived TOC) so observer lifecycle and TOC clicks
reflect translated headings (apply same change for the other similar blocks
mentioned).
---
Nitpick comments:
In `@package.json`:
- Around line 25-29: The package.json currently includes the deprecated runtime
dependency "@types/query-string" alongside "query-string"; remove the
"@types/query-string" entry from package.json (the dependency named
"@types/query-string") so the project relies on the built-in TypeScript
declarations shipped with "query-string", and then run your install (or update
lockfile) to ensure the lockfile no longer pins the obsolete v6 typings.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e3ef5d00-d630-4171-94e9-3f7980d1fc2f
⛔ Files ignored due to path filters (1)
package-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (5)
package.jsonsrc/components/ReadmeModal.tsxsrc/hooks/useMarkdownTranslation.tssrc/services/translateService.tssrc/utils/markdownSplitter.ts
将TOC提取逻辑从README内容加载中分离,改为在翻译内容或原始内容更新时触发 优化翻译服务,支持请求中止并改进参数处理 增强markdown分割器,支持更多代码块格式并改进链接和图片处理
|
我也是纯 ai 改,最近被弱智模型坑的不行。我找找公益站先,之前手头的公益站都死的差不多了。 |
|
现在主要是翻译后的MD排版总是在某些情况出问题,AI检查了很多问题自己也改了一些 |
那个 trae 么,还有个 trae solo。之前刚出的时候用过一阵,后来就是排队不用了,亚马逊那个 kiro 也用过一段。现在主要就是 Claude code 和 opencode,不在电脑前就用🦞。 那个翻译是全文翻还是弄成沉浸式翻译那种? |
|
看了一下,主要是翻译以后有一些markdown语法不渲染,还有一些html标签 |
重构 markdown 解析器,新增对 HTML 标签和带链接图片的支持 优化语言检测和翻译方向判断逻辑 调整 tailwind 配置中的颜色结构
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/utils/markdownSplitter.ts`:
- Line 22: The current combinedRegex in markdownSplitter.ts only matches a
narrow set of opening/self-closing HTML tags and misses paired tags and explicit
closing tags, so update the regex (used as combinedRegex in this file) to also
match full paired tag blocks and their closing tags for the supported set
(video, audio, iframe, object, embed, svg, canvas, picture) by using patterns
like <tag\b[^>]*>[\s\S]*?<\/tag> and explicit <\/tag> alternatives, and ensure
source/img remain matched as self-closing; apply the same updated pattern where
combinedRegex is redefined (also around lines 65-82) so paired tags and closing
tags are shielded from translation.
- Around line 248-291: extractTranslatableChunks currently concatenates multiple
translatable segments into larger chunks which loses original boundaries and
makes mergeTranslatedChunks/splitTranslationToParts unrecoverable; change
extractTranslatableChunks to preserve 1:1 segment boundaries by emitting a chunk
per translatable MarkdownSegment (or include an unambiguous boundary token and
original segment index/length metadata on each chunk) so reconstructed text can
be mapped exactly back to segmentIds, and then update mergeTranslatedChunks and
splitTranslationToParts to rely on the preserved per-segment mapping (segmentIds
or explicit boundary metadata) instead of guessing paragraph counts.
- Around line 143-153: The current code pushes the markdown delimiters into
segments marked 'translatable' (see segments.push calls that add content '!['
and `${altText}]` using segmentIdCounter), which lets MT change syntax; instead
split these into separate segments so only the label text is translatable: push
a non-translatable/delimiter segment for '![' (type e.g. 'delimiter' or
'token'), then push a translatable segment containing only altText (no
surrounding brackets), then push another non-translatable segment for ']' —
apply the same change to the other occurrence noted (lines ~189-193) so all
bracket/marker content is excluded from translatable segments.
- Around line 343-345: The loop in markdownSplitter.ts currently uses "const
translation = translations[translationIndex] ?? ''", which silently replaces
missing translations and can erase the original chunk; replace this with an
explicit undefined check on translations[translationIndex] and either (a) throw
a descriptive Error (including translationIndex and chunk metadata) to fail
fast, or (b) fall back to the original chunk content by setting translation =
chunk.text (or chunk.content) when undefined; update the code paths around
translationIndex, chunks, and translations to use this check so missing items
are handled explicitly and add/update any tests that expect the new behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 32dc5a39-076c-44c4-b436-c9858ac21445
📒 Files selected for processing (2)
src/utils/markdownSplitter.tstailwind.config.js
| const segments: MarkdownSegment[] = []; | ||
|
|
||
| // 组合正则表达式:匹配各类 Markdown 元素 | ||
| const combinedRegex = /(<picture[\s\S]*?<\/picture>)|(<(?:source|img|video|audio|iframe|object|embed|svg|canvas)[^>]*\/?>)|(```[\s\S]*?```)|(~~~[\s\S]*?~~~)|(`[^`\n]+`)|(\[!\[[^\]]*\]\([^)]*\)\]\([^)]+\))|(!\[([^\]]*)\]\([^)]+\))|(\[([^\]]*)\]\([^)]+\))/g; |
There was a problem hiding this comment.
HTML tag shielding is incomplete for paired tags and closing tags.
At Line 22, the regex mainly captures opening/self-closing tags from a narrow whitelist. Closing tags and many paired HTML blocks can still flow into translatable text and get corrupted.
Suggested fix (at least preserve paired + closing tags for supported set)
- const combinedRegex = /(<picture[\s\S]*?<\/picture>)|(<(?:source|img|video|audio|iframe|object|embed|svg|canvas)[^>]*\/?>)|(```[\s\S]*?```)|(~~~[\s\S]*?~~~)|(`[^`\n]+`)|(\[!\[[^\]]*\]\([^)]*\)\]\([^)]+\))|(!\[([^\]]*)\]\([^)]+\))|(\[([^\]]*)\]\([^)]+\))/g;
+ const combinedRegex =
+ /(<picture[\s\S]*?<\/picture>)|(<(?:video|audio|iframe|object|embed|svg|canvas)\b[^>]*>[\s\S]*?<\/(?:video|audio|iframe|object|embed|svg|canvas)>|<(?:source|img)\b[^>]*\/?>|<\/(?:video|audio|iframe|object|embed|svg|canvas)>)|(```[\s\S]*?```)|(~~~[\s\S]*?~~~)|(`[^`\n]+`)|(\[!\[[^\]]*\]\([^)]*\)\]\([^)]+\))|(!\[([^\]]*)\]\([^)]+\))|(\[([^\]]*)\]\([^)]+\))/g;Also applies to: 65-82
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@src/utils/markdownSplitter.ts` at line 22, The current combinedRegex in
markdownSplitter.ts only matches a narrow set of opening/self-closing HTML tags
and misses paired tags and explicit closing tags, so update the regex (used as
combinedRegex in this file) to also match full paired tag blocks and their
closing tags for the supported set (video, audio, iframe, object, embed, svg,
canvas, picture) by using patterns like <tag\b[^>]*>[\s\S]*?<\/tag> and explicit
<\/tag> alternatives, and ensure source/img remain matched as self-closing;
apply the same updated pattern where combinedRegex is redefined (also around
lines 65-82) so paired tags and closing tags are shielded from translation.
|
劳动节好好休息放松放松啊,别太卷了 |
重构翻译服务,添加FALLBACK_TOKEN_TTL_MS常量用于令牌过期处理 新增BilingualMarkdownRenderer组件实现双语对照显示 重构useMarkdownTranslation钩子和markdownSplitter工具函数 优化翻译分段处理逻辑和占位符替换机制
There was a problem hiding this comment.
Actionable comments posted: 3
♻️ Duplicate comments (1)
src/utils/markdownSplitter.ts (1)
30-32:⚠️ Potential issue | 🟠 Major | ⚡ Quick win
~~~fenced code blocks are not extracted — their content is sent to the translator.Only triple-backtick fences are replaced with placeholders. Any README using
~~~fencing (which GitHub Markdown fully supports) will have the raw code content forwarded to the translation API and potentially corrupted.🐛 Proposed fix
- processed = processed.replace(/```[\s\S]*?```/g, (match) => { + processed = processed.replace(/(```[\s\S]*?```|~~~[\s\S]*?~~~)/g, (match) => { return createPlaceholder('CODE', match); });🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/utils/markdownSplitter.ts` around lines 30 - 32, The regex that replaces fenced code blocks only matches triple backticks so tilde fences (~~~...~~~) are left intact; update the replacement in the processed.replace call that invokes createPlaceholder('CODE', match) to also match tilde-fenced blocks (e.g., adjust the pattern used by processed.replace to include both /```[\s\S]*?```/ and /~~~[\s\S]*?~~~/ or a single alternation like /(```[\s\S]*?```|~~~[\s\S]*?~~~)/g) so all fenced code blocks are extracted before translation.
🧹 Nitpick comments (2)
src/services/translateService.ts (1)
101-105: 💤 Low valueRedundant conditional in
tokenPromisecatch block.Both branches of the
ifare identical — they both unconditionallythrow err. The check adds no value.🛠️ Proposed cleanup
- } catch (err) { - if (err instanceof Error && err.name === 'AbortError') { - throw err; - } - throw err; + } catch (err) { + throw err; } finally {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/services/translateService.ts` around lines 101 - 105, The catch block inside the tokenPromise logic in translateService.ts redundantly checks for AbortError but both branches just rethrow err; simplify by removing the if and directly rethrow the caught error (i.e., replace the conditional in the tokenPromise catch with a single "throw err;") so the behavior remains unchanged and the code is cleaner.src/hooks/useMarkdownTranslation.ts (1)
93-102: 💤 Low value
hasCodeBlockbranch is redundant — both branches push the same values.The
if (segment.hasCodeBlock)andelse if (segment.originalContent.trim())branches are identical. A segment withhasCodeBlock = truealways has non-emptyoriginalContent(it contains a placeholder like__CODE_0__), so theelse ifalready covers it.♻️ Proposed simplification
- if (segment.hasCodeBlock) { - batchTexts.push(segment.originalContent); - batchIndices.push(j); - } else if (segment.originalContent.trim()) { + if (segment.originalContent.trim()) { batchTexts.push(segment.originalContent); batchIndices.push(j); }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/hooks/useMarkdownTranslation.ts` around lines 93 - 102, The two branches inside the batching loop are redundant because segment.hasCodeBlock segments also have non-empty originalContent; update the loop in useMarkdownTranslation (the for-loop that builds batchTexts and batchIndices over newSegments) to remove the hasCodeBlock branch and simply check segment.originalContent.trim() (or truthiness) before pushing to batchTexts and batchIndices, preserving the same push behavior for applicable segments.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/BilingualMarkdownRenderer.tsx`:
- Around line 23-47: The per-segment "translating" spinner is unreachable
because segments never get status 'translating' and BilingualMarkdownRenderer is
only mounted once translateStatus === 'translated'; remove the dead UI by
deleting the isTranslating const and the entire spinner JSX block (the
conditional that renders Loader2 and the "Translating..." text) from
BilingualMarkdownRenderer, and also remove any references to 'translating' in
that component; if you instead want live per-segment progress, update
useMarkdownTranslation to set segment.status = 'translating' before dispatching
each batch and change ReadmeModal to mount BilingualMarkdownRenderer when
translateStatus === 'translating' so the spinner can appear.
In `@src/hooks/useMarkdownTranslation.ts`:
- Around line 140-144: The catch in useMarkdownTranslation.ts currently checks
"err instanceof Error && err.name === 'AbortError'", which misses browser
DOMException aborts; change the abort handling in the catch inside the
useMarkdownTranslation hook to check err?.name === 'AbortError' (or typeof (err
as any)?.name === 'string' && err.name === 'AbortError') instead of instanceof
Error so aborted fetches hit the abort branch, call setStatus('idle') and return
false; update any references to the catch block around the
translateService/translate call so aborts are treated silently rather than
setting setError('Translation failed') and setStatus('error').
In `@src/utils/markdownSplitter.ts`:
- Around line 117-126: getTranslateDirection currently returns from: 'auto' when
detected is 'unknown', which then causes translateBatchInternal to send an
invalid from='auto' to Azure; change getTranslateDirection (and its return type)
so that when detected === 'unknown' it returns from as undefined (i.e., omit the
from property) instead of the string 'auto', and ensure translateBatchInternal's
spread still only adds from when it's defined (e.g., ...(from != null && { from
})), so the Azure Translator auto-detection is triggered by omitting the from
parameter.
---
Duplicate comments:
In `@src/utils/markdownSplitter.ts`:
- Around line 30-32: The regex that replaces fenced code blocks only matches
triple backticks so tilde fences (~~~...~~~) are left intact; update the
replacement in the processed.replace call that invokes createPlaceholder('CODE',
match) to also match tilde-fenced blocks (e.g., adjust the pattern used by
processed.replace to include both /```[\s\S]*?```/ and /~~~[\s\S]*?~~~/ or a
single alternation like /(```[\s\S]*?```|~~~[\s\S]*?~~~)/g) so all fenced code
blocks are extracted before translation.
---
Nitpick comments:
In `@src/hooks/useMarkdownTranslation.ts`:
- Around line 93-102: The two branches inside the batching loop are redundant
because segment.hasCodeBlock segments also have non-empty originalContent;
update the loop in useMarkdownTranslation (the for-loop that builds batchTexts
and batchIndices over newSegments) to remove the hasCodeBlock branch and simply
check segment.originalContent.trim() (or truthiness) before pushing to
batchTexts and batchIndices, preserving the same push behavior for applicable
segments.
In `@src/services/translateService.ts`:
- Around line 101-105: The catch block inside the tokenPromise logic in
translateService.ts redundantly checks for AbortError but both branches just
rethrow err; simplify by removing the if and directly rethrow the caught error
(i.e., replace the conditional in the tokenPromise catch with a single "throw
err;") so the behavior remains unchanged and the code is cleaner.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 2dfe893c-dff0-4916-baa3-0b51fac617bf
📒 Files selected for processing (5)
src/components/BilingualMarkdownRenderer.tsxsrc/components/ReadmeModal.tsxsrc/hooks/useMarkdownTranslation.tssrc/services/translateService.tssrc/utils/markdownSplitter.ts
修复令牌验证时未检查缓存令牌是否存在的问题 优化markdown分割器中的代码块正则匹配,支持~~~语法 移除不必要的AbortError类型检查 简化双语渲染组件中的翻译状态显示逻辑
优化 translateService 中的 isTokenValid 类型守卫,使其更准确地判断 token 有效性 移除 BilingualMarkdownRenderer 中未使用的 language 属性及相关依赖
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/utils/markdownSplitter.ts`:
- Around line 46-49: The current markdown splitting flow is lossy: using
processed.split(/\n\n+/), filter(p => p.trim()), .trim() and join('\n\n') in
markdownSplitter.ts destroys intentional blank-line layout. Update the logic in
the functions handling "processed", "paragraphs" and the TranslationSegment
creation to preserve original inter-paragraph whitespace: avoid collapsing
multiple newlines with /\n\n+/, do not filter out empty-but-meaningful
paragraphs via filter(p => p.trim()), and stop trimming content before
rejoining; instead, record and carry the exact separator between paragraphs
(e.g., capture the matched separator when splitting) and use that original
separator when restoring segments so join uses the preserved separators rather
than a fixed '\n\n'. Ensure functions/methods that reference processed,
paragraphs, TranslationSegment construction, the trim() usage at the earlier
mentioned call site, and the final join call are updated to pass through or
store exact whitespace separators.
- Around line 30-44: Add protection for single-backtick inline code spans by
adding a replacement on the processed string that uses
createPlaceholder('INLINE_CODE', match) for matches of inline code (e.g.,
/`[^`\n]+`/g); place this replacement in markdownSplitter.ts near the other
processed.replace calls (after shielding fenced blocks with CODE and before
other content transformations) so inline code is replaced before sending text to
MT and won't be translated or altered.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: fe50c926-6735-41e6-9026-8cf1272919e5
📒 Files selected for processing (4)
src/components/BilingualMarkdownRenderer.tsxsrc/hooks/useMarkdownTranslation.tssrc/services/translateService.tssrc/utils/markdownSplitter.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/hooks/useMarkdownTranslation.ts
- src/services/translateService.ts
支持内联代码和details标签的占位处理,保留原始分隔符 添加原文/译文/双语三种显示模式切换功能 优化翻译按钮样式和占位符恢复逻辑
|
@coderabbitai resume |
✅ Actions performedReviews resumed. |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
src/components/BilingualMarkdownRenderer.tsx (2)
4-4: 💤 Low valueRemove unused
EyeOffimport.
EyeOffis imported but never used in the component.Proposed fix
-import { FileText, Languages, Eye, EyeOff } from 'lucide-react'; +import { FileText, Languages, Eye } from 'lucide-react';🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/BilingualMarkdownRenderer.tsx` at line 4, The import list in BilingualMarkdownRenderer.tsx includes an unused symbol EyeOff which should be removed; update the import statement that currently imports { FileText, Languages, Eye, EyeOff } from 'lucide-react' to drop EyeOff so only used icons (FileText, Languages, Eye) are imported, and run a quick lint/type check to ensure no other references to EyeOff remain.
29-61: ⚡ Quick win
getDisplayContentduplicatesrestorePlaceholdersfrom markdownSplitter.ts.This function is nearly identical to
restorePlaceholdersexported from../utils/markdownSplitter. Consider importing and reusing that function, then adding the extra leftover-placeholder pass if needed.Proposed refactor
+import { restorePlaceholders } from '../utils/markdownSplitter'; const SegmentBlock: React.FC<{...}> = memo(({ segment, placeholderMap, ... }) => { const hasTranslation = segment.translatedContent !== null && segment.status === 'done'; const getDisplayContent = (content: string): string => { if (!content || !placeholderMap.size) return content; - let result = content; - - const entries = Array.from(placeholderMap.entries()); - - for (const [key, value] of entries) { - if (result.includes(key)) { - result = result.split(key).join(value); - continue; - } - - const coreId = key.replace(/^_+|_+$/g, ''); - const pattern = new RegExp(`_+${coreId.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}_+`, 'gi'); - - if (pattern.test(result)) { - result = result.replace(pattern, value); - } - } + let result = restorePlaceholders(content, placeholderMap); + // Extra pass for any remaining placeholders with modified format const placeholderPattern = /__[A-Z]+_\d+__/g; result = result.replace(placeholderPattern, (match) => { const coreId = match.replace(/^_+|_+$/g, ''); const found = Array.from(placeholderMap.entries()).find(([k]) => k.replace(/^_+|_+$/g, '') === coreId); if (found) { return found[1]; } return match; }); return result; };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/BilingualMarkdownRenderer.tsx` around lines 29 - 61, getDisplayContent duplicates restorePlaceholders from ../utils/markdownSplitter; replace the local implementation by importing restorePlaceholders and calling it (passing the same placeholderMap and content) inside BilingualMarkdownRenderer, and then perform only the additional leftover-placeholder pass (the /__[A-Z]+_\d+__/ replacement) if restorePlaceholders doesn’t already handle it. Update references to placeholderMap and ensure getDisplayContent delegates to restorePlaceholders (keeping the extra regex fallback) to avoid duplicated logic.src/components/ReadmeModal.tsx (1)
67-78: ⚡ Quick win
getDisplayContentduplicatessegmentsToMarkdownlogic.This function replicates the segment reconstruction logic from
segmentsToMarkdowninmarkdownSplitter.ts. Consider importing and reusing that utility.Proposed refactor
+import { segmentsToMarkdown } from '../utils/markdownSplitter'; const getDisplayContent = useCallback((): string => { if (translateStatus === 'translated' && segments.length > 0) { - return segments.reduce((acc, segment, index) => { - const content = segment.translatedContent || segment.originalContent; - if (index === 0) { - return content; - } - return acc + segment.separator + content; - }, ''); + return segmentsToMarkdown(segments); } return readmeContent; }, [translateStatus, segments, readmeContent]);🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/ReadmeModal.tsx` around lines 67 - 78, getDisplayContent currently duplicates the segment-joining logic; replace the manual reduce with a call to the existing utility segmentsToMarkdown from markdownSplitter.ts: import segmentsToMarkdown and, when translateStatus === 'translated' and segments.length > 0, return segmentsToMarkdown(segments) (or segmentsToMarkdown(segments, useTranslated=true) if the utility accepts a flag) instead of reconstructing content manually, otherwise return readmeContent; update the dependency array to still include translateStatus, segments, and readmeContent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/utils/markdownSplitter.ts`:
- Around line 55-81: The separator is being recorded off-by-one: the loop in
markdownSplitter (using separatorPattern, parts, segments, currentSeparator)
assigns currentSeparator to the segment but then updates currentSeparator =
separator, so segment.separator actually represents the separator after the
segment; fix by storing the separator that actually follows the content (i.e.,
set segment.separator = separator || '\n\n' instead of currentSeparator) or
alternatively change segmentsToMarkdown to concatenate content +
segment.separator (instead of segment.separator + content); update either the
loop (assign separator to the created TranslationSegment) or the
segmentsToMarkdown logic so the stored separator and reconstruction order match.
---
Nitpick comments:
In `@src/components/BilingualMarkdownRenderer.tsx`:
- Line 4: The import list in BilingualMarkdownRenderer.tsx includes an unused
symbol EyeOff which should be removed; update the import statement that
currently imports { FileText, Languages, Eye, EyeOff } from 'lucide-react' to
drop EyeOff so only used icons (FileText, Languages, Eye) are imported, and run
a quick lint/type check to ensure no other references to EyeOff remain.
- Around line 29-61: getDisplayContent duplicates restorePlaceholders from
../utils/markdownSplitter; replace the local implementation by importing
restorePlaceholders and calling it (passing the same placeholderMap and content)
inside BilingualMarkdownRenderer, and then perform only the additional
leftover-placeholder pass (the /__[A-Z]+_\d+__/ replacement) if
restorePlaceholders doesn’t already handle it. Update references to
placeholderMap and ensure getDisplayContent delegates to restorePlaceholders
(keeping the extra regex fallback) to avoid duplicated logic.
In `@src/components/ReadmeModal.tsx`:
- Around line 67-78: getDisplayContent currently duplicates the segment-joining
logic; replace the manual reduce with a call to the existing utility
segmentsToMarkdown from markdownSplitter.ts: import segmentsToMarkdown and, when
translateStatus === 'translated' and segments.length > 0, return
segmentsToMarkdown(segments) (or segmentsToMarkdown(segments,
useTranslated=true) if the utility accepts a flag) instead of reconstructing
content manually, otherwise return readmeContent; update the dependency array to
still include translateStatus, segments, and readmeContent.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: df7ca08c-e117-4107-930b-4811c38306b9
📒 Files selected for processing (5)
src/components/BilingualMarkdownRenderer.tsxsrc/components/ReadmeModal.tsxsrc/hooks/useMarkdownTranslation.tssrc/services/translateService.tssrc/utils/markdownSplitter.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/services/translateService.ts
- src/hooks/useMarkdownTranslation.ts
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
|
@coderabbitai Complete Review PR |
|
Tip For best results, initiate chat on the files or code changes.
[full_review] |
重构翻译功能,使用DOM文本扫描器替代Markdown分割器,实现更精准的文本块识别和翻译 新增BilingualMarkdownRenderer组件,支持原文、译文和双语三种显示模式 优化翻译服务,添加重试机制和HTML内容类型支持 改进目录功能,支持翻译后的标题同步显示
添加appendSafeHTMLNodes函数来安全处理翻译文本中的内联代码节点,防止潜在的HTML注入风险。当文本包含内联代码时,不再直接设置innerHTML,而是递归复制安全节点。
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/BilingualMarkdownRenderer.tsx`:
- Around line 131-140: The language detection is being run on the raw Markdown
variable `markdown`, which biases results from code/URLs; update the flow to run
`detectLanguage` on the extracted human-readable text segment instead (the text
produced earlier when rendering/extracting the prose) rather than `markdown`,
then use that detected value for `getTranslateDirection(detected, targetLang)`
and the existing `setError`/`updateStatus` logic; locate the call site where
`detectLanguage(markdown)` is invoked and replace the argument with the
extracted segment text variable (e.g., `extractedText`/`segmentText`) so
detection reflects readable prose not code fences.
- Around line 196-212: The code currently uses
segments[i].element.after(wrapper) which creates invalid DOM when the source
element is a list item or table cell; change the logic in
BilingualMarkdownRenderer so that before calling element.after you check the tag
of segments[i].element (e.g., element.tagName or a helper isInlineContainer) and
if it is one of LI, TD, TH, DT, or DD you should append the translation wrapper
into the element (element.appendChild or element.append) instead of inserting it
as a sibling; keep the existing setting of ATTR_TRANSLATION, className,
textContent/innerHTML handling and still call
translationElementsRef.current.set(segments[i].id, wrapper) after inserting the
wrapper.
- Around line 201-203: The code assigns translator output to wrapper.innerHTML
when segments[i].hasInlineCode (see BilingualMarkdownRenderer.tsx,
wrapper.innerHTML = translatedTexts[i]), which risks XSS because
cleanTranslatedText() doesn't escape HTML; change this to set
wrapper.textContent = translatedTexts[i] to treat translatedTexts[i] as plain
text, or if you must preserve inline-code formatting, escape HTML before
assigning or construct DOM nodes (create text nodes and code elements) from the
escaped text instead of using innerHTML; update the logic around
segments[i].hasInlineCode and any callers that expect HTML accordingly.
In `@src/components/ReadmeModal.tsx`:
- Around line 334-340: The translatedHeadingMap is not cleared when
displayContent changes, causing stale translated labels to persist across
documents; inside the useEffect that runs on displayContent (the one that calls
extractToc and calls setTocItems/setHeadingIdMap), reset the
translatedHeadingMap to an empty map (or call the state setter that owns it)
before or immediately after calling extractToc so IDs like "heading-0" don't
reuse previous translations; locate the translatedHeadingMap state/variable (and
its setter) in this component and clear it in that effect (alternatively clear
it before fetchReadme() if that better fits the flow).
In `@src/services/translateService.ts`:
- Around line 74-100: withTranslateRetry currently retries every non-abort
error; change it to only retry transient failures by inspecting the thrown error
before backing off: preserve AbortError/CanceledError behavior, and for other
errors check if the error has an HTTP status (e.g., (err as
any).response?.status or (err as any).status) — if there is no status
(network/timeout) OR status === 429 OR status is 5xx then perform the
exponential backoff retry logic (sleep and continue), otherwise immediately
rethrow the error so deterministic 4xx client errors are not retried; keep the
existing apiMsAuth/token acquisition, maxRetries and backoff behavior and still
surface lastError after exhausting retries.
In `@src/utils/domTextScanner.ts`:
- Line 11: scanDomForTranslation is skipping <summary> elements because
BLOCK_SELECTOR (const BLOCK_SELECTOR) doesn't include 'summary'; update the
selector string inside src/utils/domTextScanner.ts to add "summary" (e.g.,
include ', summary' in the comma-separated list) so summary elements are treated
as block nodes and will be turned into translation segments by
scanDomForTranslation.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: c56d1ca3-6d1e-4233-bd97-5c62172bcd6b
📒 Files selected for processing (5)
src/components/BilingualMarkdownRenderer.tsxsrc/components/ReadmeModal.tsxsrc/services/translateService.tssrc/utils/domTextScanner.tssrc/utils/markdownSplitter.ts
修复翻译服务中的重试逻辑,仅对瞬态错误进行重试 优化双语渲染器中的代码块处理逻辑 更新DOM文本扫描器以包含summary标签 在ReadmeModal中重置翻译标题映射
There was a problem hiding this comment.
Actionable comments posted: 5
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
src/components/ReadmeModal.tsx (1)
348-369:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winReset resize side effects when the modal closes.
If the modal is closed while the TOC splitter is being dragged, the
mouseuphandler never runs anddocument.body.style.cursor/userSelectstay overridden. ClearisResizingRef.currentand restore both body styles in this!isOpenbranch too.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/ReadmeModal.tsx` around lines 348 - 369, When closing the modal in the useEffect !isOpen branch, clear any ongoing resize state and restore global body styles: set isResizingRef.current = false and reset document.body.style.cursor and document.body.style.userSelect to their defaults so a mid-drag TOC splitter doesn’t leave the page in a drag state; locate the cleanup within the existing useEffect handling isOpen (around the code that aborts abortControllerRef and resets state) and add these restores there referencing isResizingRef, document.body.style.cursor and document.body.style.userSelect.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/ReadmeModal.tsx`:
- Around line 110-121: The TOC active-state tracking must resolve bilingual
headings the same way as the click/scroll path: when observing nodes (the
IntersectionObserver callback that updates activeHeadingId) resolve the DOM node
using the bilingual selector pattern used in translationWrapper and compute the
id to store as target.dataset.biHeadingId ?? target.id; update any code that
currently uses target.id directly to use dataset.biHeadingId ?? id so the TOC
highlight stays in sync with clicks that scroll via data-bi-heading-id (refer to
translationWrapper, container.scrollTo, activeHeadingId, and the observer
callback).
In `@src/services/translateService.ts`:
- Around line 202-207: The 401 handling in the translate request clears
cachedToken and localStorage but throws a generic Error so withTranslateRetry
treats it as non-transient; change the code in the response.ok 401 branch (and
the identical block around the other occurrence referenced) to throw a specific
transient auth-expired error (e.g., throw new Error('AuthExpired') with a unique
property like error.isAuthExpired = true or use a dedicated AuthExpiredError
class) so withTranslateRetry can detect the auth-expired case, re-run the auth
flow to fetch a fresh token, and retry the request once; ensure only the 401
branch uses this special error while other non-OK statuses continue throwing
their original non-transient errors.
- Around line 140-164: The global tokenPromise is being created with a
caller-specific signal which lets one caller's abort cancel the shared fetch;
instead create tokenPromise without any AbortSignal (call fetch(AUTH_URL, {
method: 'GET', credentials: 'omit' }) inside the async IIFE so the shared fetch
is signal-agnostic and still stores token via storeToken and resets tokenPromise
in its finally block), and in the caller use a local race between tokenPromise
and the caller's own abort signal (e.g., Promise.race between tokenPromise and a
promise that rejects on signal.abort) so each caller can cancel awaiting the
token without canceling the underlying shared fetch; reference identifiers:
tokenPromise, AUTH_URL, storeToken, signal.
In `@src/utils/domTextScanner.ts`:
- Around line 75-98: filterOutermostBlocks currently removes selectable child
block elements which causes descendant blocks to be concatenated (e.g.,
"IntroDetails"); change the scanning to preserve nested block structure by
either (A) stop filtering out inner blocks in filterOutermostBlocks so
scanDomForTranslation iterates allElements (from BLOCK_SELECTOR) and emits a
DomBlockSegment per matched element, or (B) if keeping outer-only selection,
update extractTextPreservingInlineCode (used in scanDomForTranslation) to detect
descendant block-level elements and insert explicit separators (e.g., "\n\n" or
a paragraph token) between them when building the segment text so paragraph
boundaries are preserved; adjust id assignment (idCounter) to handle additional
segments accordingly.
- Around line 50-52: The inline code branch currently injects el.textContent
verbatim into result (when tag === 'code' && !el.closest('pre')), which can
break the placeholder HTML for snippets containing <, >, or &; update that
branch to HTML-escape the inline code text (convert & to &, < to <, > to
>, and optionally " and ') before concatenating into result so the `<code>`
placeholder preserves the original literal characters; locate the inline branch
using the tag === 'code' check and the variables el.textContent, hasInlineCode,
and result to implement the escaping helper and use it when building the
`<code>...</code>` string.
---
Outside diff comments:
In `@src/components/ReadmeModal.tsx`:
- Around line 348-369: When closing the modal in the useEffect !isOpen branch,
clear any ongoing resize state and restore global body styles: set
isResizingRef.current = false and reset document.body.style.cursor and
document.body.style.userSelect to their defaults so a mid-drag TOC splitter
doesn’t leave the page in a drag state; locate the cleanup within the existing
useEffect handling isOpen (around the code that aborts abortControllerRef and
resets state) and add these restores there referencing isResizingRef,
document.body.style.cursor and document.body.style.userSelect.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 5ce2da6b-d2b7-4e2f-b190-4229be97075a
📒 Files selected for processing (4)
src/components/BilingualMarkdownRenderer.tsxsrc/components/ReadmeModal.tsxsrc/services/translateService.tssrc/utils/domTextScanner.ts
✅ Files skipped from review due to trivial changes (1)
- src/components/BilingualMarkdownRenderer.tsx
修复翻译服务中的认证过期处理,添加AuthExpiredError类标记认证过期错误 优化token获取逻辑,避免竞态条件和重复请求 添加对abort signal的支持,确保请求可被正确取消
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
src/components/BilingualMarkdownRenderer.tsx (1)
137-146:⚠️ Potential issue | 🟠 Major | ⚡ Quick winDetect the source language from scanned prose, not raw Markdown.
markdownincludes fences, URLs, inline HTML, and other syntax noise, so code-heavy READMEs can skew toward English and pick the wrong translation direction or skip translation entirely. Use the scanned segment text (or a joined sample of it) here instead.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/components/BilingualMarkdownRenderer.tsx` around lines 137 - 146, The language detection is being run on raw markdown (detectLanguage(markdown)) which includes fences/URLs and can misdetect; instead build a clean sample from the scanned prose segments and run detection on that sample. Replace the call to detectLanguage(markdown) with detection on a joined/scoped string derived from the scanned segments (e.g., concatenate the `.text` of the scan results or a sliced sample of those segments), keep targetLang = language, then proceed with the existing detected → getTranslateDirection(detected, targetLang) logic and the same setError/updateStatus handling if languages match. Ensure you reference the scanned segments used elsewhere in this component (the variable holding scan results) so the change stays localized to the detection step.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/components/BilingualMarkdownRenderer.tsx`:
- Around line 185-188: The current logic sets a single request-scoped textType
based on batchHasInlineCode which mixes segments serialized for 'html' with
plain texts (variables: batchHasInlineCode, batchIndices, segments, batchTexts,
textType, translateBatch), causing encoding/escaping mismatches; fix by
splitting the batch into two requests (one for segments where
segments[j].hasInlineCode === true and one for the rest) and call translateBatch
separately with textType='html' for the inline-code group and textType='plain'
for the plain group (or alternatively ensure every plain text is properly
escaped before sending when using the 'html' path).
In `@src/components/ReadmeModal.tsx`:
- Around line 110-121: The TOC scroll/observer logic currently always targets
`[data-bi-heading-id]` (translation wrappers) and never updates when
translation/display mode changes; update the target resolution to pick the first
visible heading for the current mode by checking for a translationWrapper
(`querySelector([data-bi-heading-id="${CSS.escape(id)}"])`) and if not
visible/found, fall back to the original heading element, and use that resolved
element for scrolling (`container.scrollTo` / `container.scrollTop`) and
observing; also ensure the observer rebinding logic includes the
translation/display state (add `translateStatus` and `displayMode` to the effect
deps that attaches the observer and the TOC click handler) so the observer is
torn down and reattached when translation or display mode changes.
In `@src/services/translateService.ts`:
- Around line 275-283: The loop in translateService (looping over batch, using
currentBatch/currentLength and calling translateBatchInternal) allows a single
text with text.length > maxChars to be pushed and sent, so add handling for
oversized items: if text.length > maxChars and currentBatch is empty, split that
text into chunks that are <= maxChars (implement a helper like
splitTextIntoChunks(text, maxChars)) and for each chunk call
translateBatchInternal (or accumulate chunks into currentBatch and process as
usual); alternatively, if splitting is not desired, explicitly throw/reject with
a clear error when encountering a single segment > maxChars. Ensure you
reference and update currentBatch/currentLength appropriately when processing
chunks so no request exceeds maxChars.
- Around line 105-131: The backoff sleep in withTranslateRetry should be
abortable so cancellation via the provided signal cancels the retry wait
immediately; modify sleep to accept an AbortSignal (or create an abortableSleep
helper) that rejects with an AbortError when signal.aborted, then pass the same
signal from withTranslateRetry into sleep (and ensure any callers like apiMsAuth
and isTransientError checks still use the original signal) so that awaiting
sleep(baseDelay * 2**(attempt-1), signal) will throw and let withTranslateRetry
propagate the abort instead of waiting the full delay.
---
Duplicate comments:
In `@src/components/BilingualMarkdownRenderer.tsx`:
- Around line 137-146: The language detection is being run on raw markdown
(detectLanguage(markdown)) which includes fences/URLs and can misdetect; instead
build a clean sample from the scanned prose segments and run detection on that
sample. Replace the call to detectLanguage(markdown) with detection on a
joined/scoped string derived from the scanned segments (e.g., concatenate the
`.text` of the scan results or a sliced sample of those segments), keep
targetLang = language, then proceed with the existing detected →
getTranslateDirection(detected, targetLang) logic and the same
setError/updateStatus handling if languages match. Ensure you reference the
scanned segments used elsewhere in this component (the variable holding scan
results) so the change stays localized to the detection step.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 006ee0ee-b593-432f-9339-68a3887f2ec8
📒 Files selected for processing (5)
src/components/BilingualMarkdownRenderer.tsxsrc/components/MarkdownRenderer.tsxsrc/components/ReadmeModal.tsxsrc/services/translateService.tssrc/utils/domTextScanner.ts
- 在ReadmeModal中添加对可见元素的检查,防止滚动到隐藏元素 - 改进翻译服务,支持大文本分块处理和取消操作 - 优化双语Markdown渲染器,区分处理纯文本和HTML内容 - 导出TranslateResult接口供外部使用
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/services/translateService.ts`:
- Around line 321-338: The loop in translateBatch (the batch processing block
using currentBatch/currentLength) fails to split an oversized text when a prior
flush just occurred because the split guard only runs when currentBatch.length
=== 0; after flushing you push the oversized text into currentBatch and send it,
violating the maxChars limit. Fix by changing the logic around
splitTextIntoChunks and translateBatchInternal so that any text with text.length
> maxChars is always split and processed via
splitTextIntoChunks/translateBatchInternal regardless of currentBatch state
(e.g., after you flush currentBatch and reset currentBatch/currentLength,
re-evaluate the same text against maxChars and call splitTextIntoChunks if
needed, otherwise push to currentBatch). Ensure references: splitTextIntoChunks,
translateBatchInternal, currentBatch, currentLength, maxChars, and the loop
variable text are updated accordingly.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e0a814d9-3bea-4b54-b33a-719dbb5918a3
📒 Files selected for processing (3)
src/components/BilingualMarkdownRenderer.tsxsrc/components/ReadmeModal.tsxsrc/services/translateService.ts
✅ Files skipped from review due to trivial changes (2)
- src/components/BilingualMarkdownRenderer.tsx
- src/components/ReadmeModal.tsx
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
|
我觉得差不多能合并了吧 |
|
可以了 |
Summary by CodeRabbit
New Features
Style