From ed1da24be88295b61c7c543ec43051605ab0b21f Mon Sep 17 00:00:00 2001 From: neriousy Date: Fri, 13 Feb 2026 10:42:28 +0100 Subject: [PATCH 1/2] perf: showing file content & diffs --- packages/app/src/pages/session/file-tabs.tsx | 23 +- packages/ui/src/components/code.tsx | 118 +++++++-- packages/ui/src/components/diff.tsx | 38 ++- packages/ui/src/components/session-review.css | 26 ++ packages/ui/src/components/session-review.tsx | 224 +++++++++++------- packages/util/src/encode.ts | 21 ++ 6 files changed, 323 insertions(+), 127 deletions(-) diff --git a/packages/app/src/pages/session/file-tabs.tsx b/packages/app/src/pages/session/file-tabs.tsx index 5b3f57dbed98..d22fa358b028 100644 --- a/packages/app/src/pages/session/file-tabs.tsx +++ b/packages/app/src/pages/session/file-tabs.tsx @@ -1,7 +1,7 @@ import { type ValidComponent, createEffect, createMemo, For, Match, on, onCleanup, Show, Switch } from "solid-js" import { createStore, produce } from "solid-js/store" import { Dynamic } from "solid-js/web" -import { checksum } from "@opencode-ai/util/encode" +import { sampledChecksum } from "@opencode-ai/util/encode" import { decode64 } from "@/utils/base64" import { showToast } from "@opencode-ai/ui/toast" import { LineComment as LineCommentView, LineCommentEditor } from "@opencode-ai/ui/line-comment" @@ -49,7 +49,7 @@ export function FileTabContent(props: { return props.file.get(p) }) const contents = createMemo(() => state()?.content?.content ?? "") - const cacheKey = createMemo(() => checksum(contents())) + const cacheKey = createMemo(() => sampledChecksum(contents())) const isImage = createMemo(() => { const c = state()?.content return c?.encoding === "base64" && c?.mimeType?.startsWith("image/") && c?.mimeType !== "image/svg+xml" @@ -163,11 +163,20 @@ export function FileTabContent(props: { return } + const estimateTop = (range: SelectedLineRange) => { + const line = Math.max(range.start, range.end) + const height = 24 + const offset = 2 + return Math.max(0, (line - 1) * height + offset) + } + + const large = contents().length > 500_000 + const next: Record = {} for (const comment of fileComments()) { const marker = findMarker(root, comment.selection) - if (!marker) continue - next[comment.id] = markerTop(el, marker) + if (marker) next[comment.id] = markerTop(el, marker) + else if (large) next[comment.id] = estimateTop(comment.selection) } const removed = Object.keys(note.positions).filter((id) => next[id] === undefined) @@ -194,12 +203,12 @@ export function FileTabContent(props: { } const marker = findMarker(root, range) - if (!marker) { - setNote("draftTop", undefined) + if (marker) { + setNote("draftTop", markerTop(el, marker)) return } - setNote("draftTop", markerTop(el, marker)) + setNote("draftTop", large ? estimateTop(range) : undefined) } const scheduleComments = () => { diff --git a/packages/ui/src/components/code.tsx b/packages/ui/src/components/code.tsx index abe0d7ca9e4e..837cc5337647 100644 --- a/packages/ui/src/components/code.tsx +++ b/packages/ui/src/components/code.tsx @@ -1,10 +1,27 @@ -import { type FileContents, File, FileOptions, LineAnnotation, type SelectedLineRange } from "@pierre/diffs" +import { + DEFAULT_VIRTUAL_FILE_METRICS, + type FileContents, + File, + FileOptions, + LineAnnotation, + type SelectedLineRange, + type VirtualFileMetrics, + VirtualizedFile, + Virtualizer, +} from "@pierre/diffs" import { ComponentProps, createEffect, createMemo, createSignal, onCleanup, onMount, Show, splitProps } from "solid-js" import { Portal } from "solid-js/web" import { createDefaultOptions, styleVariables } from "../pierre" import { getWorkerPool } from "../pierre/worker" import { Icon } from "./icon" +const VIRTUALIZE_BYTES = 500_000 +const codeMetrics = { + ...DEFAULT_VIRTUAL_FILE_METRICS, + lineHeight: 24, + fileGap: 0, +} satisfies Partial + type SelectionSide = "additions" | "deletions" export type CodeProps = FileOptions & { @@ -160,16 +177,28 @@ export function Code(props: CodeProps) { const [findPos, setFindPos] = createSignal<{ top: number; right: number }>({ top: 8, right: 8 }) - const file = createMemo( - () => - new File( - { - ...createDefaultOptions("unified"), - ...others, - }, - getWorkerPool("unified"), - ), - ) + let instance: File | VirtualizedFile | undefined + let virtualizer: Virtualizer | undefined + let virtualRoot: Document | HTMLElement | undefined + + const bytes = createMemo(() => { + const value = local.file.contents as unknown + if (typeof value === "string") return value.length + if (Array.isArray(value)) { + return value.reduce( + (acc, part) => acc + (typeof part === "string" ? part.length + 1 : String(part).length + 1), + 0, + ) + } + if (value == null) return 0 + return String(value).length + }) + const virtual = createMemo(() => bytes() > VIRTUALIZE_BYTES) + + const options = createMemo(() => ({ + ...createDefaultOptions("unified"), + ...others, + })) const getRoot = () => { const host = container.querySelector("diffs-container") @@ -577,6 +606,14 @@ export function Code(props: CodeProps) { } const applySelection = (range: SelectedLineRange | null) => { + const current = instance + if (!current) return false + + if (virtual()) { + current.setSelectedLines(range) + return true + } + const root = getRoot() if (!root) return false @@ -584,7 +621,7 @@ export function Code(props: CodeProps) { if (root.querySelectorAll("[data-line]").length < lines) return false if (!range) { - file().setSelectedLines(null) + current.setSelectedLines(null) return true } @@ -592,12 +629,12 @@ export function Code(props: CodeProps) { const end = Math.max(range.start, range.end) if (start < 1 || end > lines) { - file().setSelectedLines(null) + current.setSelectedLines(null) return true } if (!root.querySelector(`[data-line="${start}"]`) || !root.querySelector(`[data-line="${end}"]`)) { - file().setSelectedLines(null) + current.setSelectedLines(null) return true } @@ -608,7 +645,7 @@ export function Code(props: CodeProps) { return { start: range.start, end: range.end } })() - file().setSelectedLines(normalized) + current.setSelectedLines(normalized) return true } @@ -619,9 +656,12 @@ export function Code(props: CodeProps) { const token = renderToken - const lines = lineCount() + const lines = virtual() ? undefined : lineCount() - const isReady = (root: ShadowRoot) => root.querySelectorAll("[data-line]").length >= lines + const isReady = (root: ShadowRoot) => + virtual() + ? root.querySelector("[data-line]") != null + : root.querySelectorAll("[data-line]").length >= (lines ?? 0) const notify = () => { if (token !== renderToken) return @@ -844,20 +884,41 @@ export function Code(props: CodeProps) { } createEffect(() => { - const current = file() + const opts = options() + const workerPool = getWorkerPool("unified") + const isVirtual = virtual() - onCleanup(() => { - current.cleanUp() - }) - }) - - createEffect(() => { observer?.disconnect() observer = undefined + instance?.cleanUp() + instance = undefined + + if (!isVirtual && virtualizer) { + virtualizer.cleanUp() + virtualizer = undefined + virtualRoot = undefined + } + + const v = (() => { + if (!isVirtual) return + if (typeof document === "undefined") return + + const root = getScrollParent(wrapper) ?? document + if (virtualizer && virtualRoot === root) return virtualizer + + virtualizer?.cleanUp() + virtualizer = new Virtualizer() + virtualRoot = root + virtualizer.setup(root, root instanceof Document ? undefined : wrapper) + return virtualizer + })() + + instance = isVirtual && v ? new VirtualizedFile(opts, v, codeMetrics, workerPool) : new File(opts, workerPool) + container.innerHTML = "" const value = text() - file().render({ + instance.render({ file: typeof local.file.contents === "string" ? local.file : { ...local.file, contents: value }, lineAnnotations: local.annotations, containerWrapper: container, @@ -910,6 +971,13 @@ export function Code(props: CodeProps) { onCleanup(() => { observer?.disconnect() + instance?.cleanUp() + instance = undefined + + virtualizer?.cleanUp() + virtualizer = undefined + virtualRoot = undefined + clearOverlayScroll() clearOverlay() if (findCurrent === host) { diff --git a/packages/ui/src/components/diff.tsx b/packages/ui/src/components/diff.tsx index 0966db75e036..0002232b01c8 100644 --- a/packages/ui/src/components/diff.tsx +++ b/packages/ui/src/components/diff.tsx @@ -1,5 +1,5 @@ -import { checksum } from "@opencode-ai/util/encode" -import { FileDiff, type SelectedLineRange, VirtualizedFileDiff } from "@pierre/diffs" +import { sampledChecksum } from "@opencode-ai/util/encode" +import { FileDiff, type FileDiffOptions, type SelectedLineRange, VirtualizedFileDiff } from "@pierre/diffs" import { createMediaQuery } from "@solid-primitives/media" import { createEffect, createMemo, createSignal, onCleanup, splitProps } from "solid-js" import { createDefaultOptions, type DiffProps, styleVariables } from "../pierre" @@ -78,14 +78,29 @@ export function Diff(props: DiffProps) { const mobile = createMediaQuery("(max-width: 640px)") - const options = createMemo(() => { - const opts = { + const large = createMemo(() => { + const before = typeof local.before?.contents === "string" ? local.before.contents : "" + const after = typeof local.after?.contents === "string" ? local.after.contents : "" + return Math.max(before.length, after.length) > 500_000 + }) + + const largeOptions = { + lineDiffType: "none", + maxLineDiffLength: 0, + tokenizeMaxLineLength: 1, + } satisfies Pick, "lineDiffType" | "maxLineDiffLength" | "tokenizeMaxLineLength"> + + const options = createMemo>(() => { + const base = { ...createDefaultOptions(props.diffStyle), ...others, } - if (!mobile()) return opts + + const perf = large() ? { ...base, ...largeOptions } : base + if (!mobile()) return perf + return { - ...opts, + ...perf, disableLineNumbers: true, } }) @@ -528,12 +543,17 @@ export function Diff(props: DiffProps) { createEffect(() => { const opts = options() - const workerPool = getWorkerPool(props.diffStyle) + const workerPool = large() ? getWorkerPool("unified") : getWorkerPool(props.diffStyle) const virtualizer = getVirtualizer() const annotations = local.annotations const beforeContents = typeof local.before?.contents === "string" ? local.before.contents : "" const afterContents = typeof local.after?.contents === "string" ? local.after.contents : "" + const cacheKey = (contents: string) => { + if (!large()) return sampledChecksum(contents, contents.length) + return sampledChecksum(contents) + } + instance?.cleanUp() instance = virtualizer ? new VirtualizedFileDiff(opts, virtualizer, virtualMetrics, workerPool) @@ -545,12 +565,12 @@ export function Diff(props: DiffProps) { oldFile: { ...local.before, contents: beforeContents, - cacheKey: checksum(beforeContents), + cacheKey: cacheKey(beforeContents), }, newFile: { ...local.after, contents: afterContents, - cacheKey: checksum(afterContents), + cacheKey: cacheKey(afterContents), }, lineAnnotations: annotations, containerWrapper: container, diff --git a/packages/ui/src/components/session-review.css b/packages/ui/src/components/session-review.css index 30bfe3b712a9..46473b75e5f2 100644 --- a/packages/ui/src/components/session-review.css +++ b/packages/ui/src/components/session-review.css @@ -222,4 +222,30 @@ --line-comment-popover-z: 30; --line-comment-open-z: 6; } + + [data-slot="session-review-large-diff"] { + padding: 12px; + background: var(--background-stronger); + } + + [data-slot="session-review-large-diff-title"] { + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + font-weight: var(--font-weight-medium); + color: var(--text-strong); + margin-bottom: 4px; + } + + [data-slot="session-review-large-diff-meta"] { + font-family: var(--font-family-sans); + font-size: var(--font-size-small); + color: var(--text-weak); + word-break: break-word; + } + + [data-slot="session-review-large-diff-actions"] { + display: flex; + gap: 8px; + margin-top: 10px; + } } diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx index fe2475548ea4..ecdb3f14da21 100644 --- a/packages/ui/src/components/session-review.tsx +++ b/packages/ui/src/components/session-review.tsx @@ -17,6 +17,26 @@ import { PreloadMultiFileDiffResult } from "@pierre/diffs/ssr" import { type SelectedLineRange } from "@pierre/diffs" import { Dynamic } from "solid-js/web" +const MAX_DIFF_LINES = 20_000 +const MAX_DIFF_BYTES = 2_000_000 + +function linesOver(text: string, max: number) { + let lines = 1 + for (let i = 0; i < text.length; i++) { + if (text.charCodeAt(i) !== 10) continue + lines++ + if (lines > max) return true + } + return lines > max +} + +function formatBytes(bytes: number) { + if (!Number.isFinite(bytes) || bytes <= 0) return "0 B" + if (bytes < 1024) return `${bytes} B` + if (bytes < 1024 * 1024) return `${Math.round((bytes / 1024) * 10) / 10} KB` + return `${Math.round((bytes / (1024 * 1024)) * 10) / 10} MB` +} + export type SessionReviewDiffStyle = "unified" | "split" export type SessionReviewComment = { @@ -326,12 +346,28 @@ export const SessionReview = (props: SessionReviewProps) => { {(diff) => { let wrapper: HTMLDivElement | undefined + const expanded = createMemo(() => open().includes(diff.file)) + const [force, setForce] = createSignal(false) + const comments = createMemo(() => (props.comments ?? []).filter((c) => c.file === diff.file)) const commentedLines = createMemo(() => comments().map((c) => c.selection)) const beforeText = () => (typeof diff.before === "string" ? diff.before : "") const afterText = () => (typeof diff.after === "string" ? diff.after : "") + const tooLarge = createMemo(() => { + if (!expanded()) return false + if (force()) return false + if (isImageFile(diff.file)) return false + + const before = beforeText() + const after = afterText() + + if (before.length > MAX_DIFF_BYTES || after.length > MAX_DIFF_BYTES) return true + if (linesOver(before, MAX_DIFF_LINES) || linesOver(after, MAX_DIFF_LINES)) return true + return false + }) + const isAdded = () => diff.status === "added" || (beforeText().length === 0 && afterText().length > 0) const isDeleted = () => diff.status === "deleted" || (afterText().length === 0 && beforeText().length > 0) @@ -571,94 +607,110 @@ export const SessionReview = (props: SessionReviewProps) => { scheduleAnchors() }} > - - -
- {diff.file} -
-
- -
- - {i18n.t("ui.sessionReview.change.removed")} - -
-
- -
- - {imageStatus() === "loading" ? "Loading..." : "Image"} - -
-
- - { - props.onDiffRendered?.() - scheduleAnchors() - }} - enableLineSelection={props.onLineComment != null} - onLineSelected={handleLineSelected} - onLineSelectionEnd={handleLineSelectionEnd} - selectedLines={selectedLines()} - commentedLines={commentedLines()} - before={{ - name: diff.file!, - contents: typeof diff.before === "string" ? diff.before : "", - }} - after={{ - name: diff.file!, - contents: typeof diff.after === "string" ? diff.after : "", - }} - /> - -
- - - {(comment) => ( - setSelection({ file: comment.file, range: comment.selection })} - onClick={() => { - if (isCommentOpen(comment)) { - setOpened(null) - return - } - - openComment(comment) - }} - open={isCommentOpen(comment)} - comment={comment.comment} - selection={selectionLabel(comment.selection)} - /> - )} - - - - {(range) => ( - - setCommenting(null)} - onSubmit={(comment) => { - props.onLineComment?.({ - file: diff.file, - selection: range(), - comment, - preview: selectionPreview(diff, range()), - }) - setCommenting(null) + + + +
+ {diff.file} +
+
+ +
+ + {i18n.t("ui.sessionReview.change.removed")} + +
+
+ +
+ + {imageStatus() === "loading" ? "Loading..." : "Image"} + +
+
+ +
+
Diff too large to render
+
+ Limit: {MAX_DIFF_LINES.toLocaleString()} lines / {formatBytes(MAX_DIFF_BYTES)}. + Current: {formatBytes(Math.max(beforeText().length, afterText().length))}. +
+
+ +
+
+
+ + { + props.onDiffRendered?.() + scheduleAnchors() + }} + enableLineSelection={props.onLineComment != null} + onLineSelected={handleLineSelected} + onLineSelectionEnd={handleLineSelectionEnd} + selectedLines={selectedLines()} + commentedLines={commentedLines()} + before={{ + name: diff.file!, + contents: typeof diff.before === "string" ? diff.before : "", }} + after={{ + name: diff.file!, + contents: typeof diff.after === "string" ? diff.after : "", + }} + /> + +
+ + + {(comment) => ( + setSelection({ file: comment.file, range: comment.selection })} + onClick={() => { + if (isCommentOpen(comment)) { + setOpened(null) + return + } + + openComment(comment) + }} + open={isCommentOpen(comment)} + comment={comment.comment} + selection={selectionLabel(comment.selection)} /> -
- )} + )} + + + + {(range) => ( + + setCommenting(null)} + onSubmit={(comment) => { + props.onLineComment?.({ + file: diff.file, + selection: range(), + comment, + preview: selectionPreview(diff, range()), + }) + setCommenting(null) + }} + /> + + )} +
diff --git a/packages/util/src/encode.ts b/packages/util/src/encode.ts index 138cf16086df..e4c6e70acb49 100644 --- a/packages/util/src/encode.ts +++ b/packages/util/src/encode.ts @@ -28,3 +28,24 @@ export function checksum(content: string): string | undefined { } return (hash >>> 0).toString(36) } + +export function sampledChecksum(content: string, limit = 500_000): string | undefined { + if (!content) return undefined + if (content.length <= limit) return checksum(content) + + const size = 4096 + const points = [ + 0, + Math.floor(content.length * 0.25), + Math.floor(content.length * 0.5), + Math.floor(content.length * 0.75), + content.length - size, + ] + const hashes = points + .map((point) => { + const start = Math.max(0, Math.min(content.length - size, point - Math.floor(size / 2))) + return checksum(content.slice(start, start + size)) ?? "" + }) + .join(":") + return `${content.length}:${hashes}` +} From 0b3eac5696014a93817ba1dab998c0325b2aeba9 Mon Sep 17 00:00:00 2001 From: neriousy Date: Fri, 13 Feb 2026 11:04:35 +0100 Subject: [PATCH 2/2] chore: i18n --- packages/ui/src/components/session-review.tsx | 10 +++++++--- packages/ui/src/i18n/ar.ts | 5 +++++ packages/ui/src/i18n/br.ts | 5 +++++ packages/ui/src/i18n/bs.ts | 5 +++++ packages/ui/src/i18n/da.ts | 5 +++++ packages/ui/src/i18n/de.ts | 5 +++++ packages/ui/src/i18n/en.ts | 5 +++++ packages/ui/src/i18n/es.ts | 5 +++++ packages/ui/src/i18n/fr.ts | 5 +++++ packages/ui/src/i18n/ja.ts | 5 +++++ packages/ui/src/i18n/ko.ts | 5 +++++ packages/ui/src/i18n/no.ts | 5 +++++ packages/ui/src/i18n/pl.ts | 5 +++++ packages/ui/src/i18n/ru.ts | 5 +++++ packages/ui/src/i18n/th.ts | 5 +++++ packages/ui/src/i18n/zh.ts | 5 +++++ packages/ui/src/i18n/zht.ts | 5 +++++ 17 files changed, 87 insertions(+), 3 deletions(-) diff --git a/packages/ui/src/components/session-review.tsx b/packages/ui/src/components/session-review.tsx index ecdb3f14da21..5f1e6b1aba5f 100644 --- a/packages/ui/src/components/session-review.tsx +++ b/packages/ui/src/components/session-review.tsx @@ -624,20 +624,24 @@ export const SessionReview = (props: SessionReviewProps) => {
- {imageStatus() === "loading" ? "Loading..." : "Image"} + {imageStatus() === "loading" + ? i18n.t("ui.sessionReview.image.loading") + : i18n.t("ui.sessionReview.image.placeholder")}
-
Diff too large to render
+
+ {i18n.t("ui.sessionReview.largeDiff.title")} +
Limit: {MAX_DIFF_LINES.toLocaleString()} lines / {formatBytes(MAX_DIFF_BYTES)}. Current: {formatBytes(Math.max(beforeText().length, afterText().length))}.
diff --git a/packages/ui/src/i18n/ar.ts b/packages/ui/src/i18n/ar.ts index 7ee17e2e0102..9a6c8dcbd050 100644 --- a/packages/ui/src/i18n/ar.ts +++ b/packages/ui/src/i18n/ar.ts @@ -8,6 +8,11 @@ export const dict = { "ui.sessionReview.change.added": "مضاف", "ui.sessionReview.change.removed": "محذوف", "ui.sessionReview.change.modified": "معدل", + "ui.sessionReview.image.loading": "جار التحميل...", + "ui.sessionReview.image.placeholder": "صورة", + "ui.sessionReview.largeDiff.title": "Diff كبير جدا لعرضه", + "ui.sessionReview.largeDiff.meta": "الحد: {{lines}} سطر / {{limit}}. الحالي: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "اعرض على أي حال", "ui.lineComment.label.prefix": "تعليق على ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/br.ts b/packages/ui/src/i18n/br.ts index 6d7449d8457d..148b0ae17419 100644 --- a/packages/ui/src/i18n/br.ts +++ b/packages/ui/src/i18n/br.ts @@ -8,6 +8,11 @@ export const dict = { "ui.sessionReview.change.added": "Adicionado", "ui.sessionReview.change.removed": "Removido", "ui.sessionReview.change.modified": "Modificado", + "ui.sessionReview.image.loading": "Carregando...", + "ui.sessionReview.image.placeholder": "Imagem", + "ui.sessionReview.largeDiff.title": "Diff grande demais para renderizar", + "ui.sessionReview.largeDiff.meta": "Limite: {{lines}} linhas / {{limit}}. Atual: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Renderizar mesmo assim", "ui.lineComment.label.prefix": "Comentar em ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/bs.ts b/packages/ui/src/i18n/bs.ts index 24e4c12068ee..7614af087f90 100644 --- a/packages/ui/src/i18n/bs.ts +++ b/packages/ui/src/i18n/bs.ts @@ -12,6 +12,11 @@ export const dict = { "ui.sessionReview.change.added": "Dodano", "ui.sessionReview.change.removed": "Uklonjeno", "ui.sessionReview.change.modified": "Izmijenjeno", + "ui.sessionReview.image.loading": "Učitavanje...", + "ui.sessionReview.image.placeholder": "Slika", + "ui.sessionReview.largeDiff.title": "Diff je prevelik za prikaz", + "ui.sessionReview.largeDiff.meta": "Limit: {{lines}} linija / {{limit}}. Trenutno: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Prikaži svejedno", "ui.lineComment.label.prefix": "Komentar na ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/da.ts b/packages/ui/src/i18n/da.ts index 218f3b26a494..2f49a94344cf 100644 --- a/packages/ui/src/i18n/da.ts +++ b/packages/ui/src/i18n/da.ts @@ -9,6 +9,11 @@ export const dict = { "ui.sessionReview.change.added": "Tilføjet", "ui.sessionReview.change.removed": "Fjernet", "ui.sessionReview.change.modified": "Ændret", + "ui.sessionReview.image.loading": "Indlæser...", + "ui.sessionReview.image.placeholder": "Billede", + "ui.sessionReview.largeDiff.title": "Diff er for stor til at blive vist", + "ui.sessionReview.largeDiff.meta": "Grænse: {{lines}} linjer / {{limit}}. Nuværende: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Vis alligevel", "ui.lineComment.label.prefix": "Kommenter på ", "ui.lineComment.label.suffix": "", "ui.lineComment.editorLabel.prefix": "Kommenterer på ", diff --git a/packages/ui/src/i18n/de.ts b/packages/ui/src/i18n/de.ts index 921a12c99675..44090b7bdb8c 100644 --- a/packages/ui/src/i18n/de.ts +++ b/packages/ui/src/i18n/de.ts @@ -13,6 +13,11 @@ export const dict = { "ui.sessionReview.change.added": "Hinzugefügt", "ui.sessionReview.change.removed": "Entfernt", "ui.sessionReview.change.modified": "Geändert", + "ui.sessionReview.image.loading": "Wird geladen...", + "ui.sessionReview.image.placeholder": "Bild", + "ui.sessionReview.largeDiff.title": "Diff zu groß zum Rendern", + "ui.sessionReview.largeDiff.meta": "Limit: {{lines}} Zeilen / {{limit}}. Aktuell: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Trotzdem rendern", "ui.lineComment.label.prefix": "Kommentar zu ", "ui.lineComment.label.suffix": "", "ui.lineComment.editorLabel.prefix": "Kommentiere ", diff --git a/packages/ui/src/i18n/en.ts b/packages/ui/src/i18n/en.ts index 631bc660a65d..9b6ab0bd6d9e 100644 --- a/packages/ui/src/i18n/en.ts +++ b/packages/ui/src/i18n/en.ts @@ -8,6 +8,11 @@ export const dict = { "ui.sessionReview.change.added": "Added", "ui.sessionReview.change.removed": "Removed", "ui.sessionReview.change.modified": "Modified", + "ui.sessionReview.image.loading": "Loading...", + "ui.sessionReview.image.placeholder": "Image", + "ui.sessionReview.largeDiff.title": "Diff too large to render", + "ui.sessionReview.largeDiff.meta": "Limit: {{lines}} lines / {{limit}}. Current: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Render anyway", "ui.lineComment.label.prefix": "Comment on ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/es.ts b/packages/ui/src/i18n/es.ts index 4fd921b606b1..c2f8ac3b9d5c 100644 --- a/packages/ui/src/i18n/es.ts +++ b/packages/ui/src/i18n/es.ts @@ -8,6 +8,11 @@ export const dict = { "ui.sessionReview.change.added": "Añadido", "ui.sessionReview.change.removed": "Eliminado", "ui.sessionReview.change.modified": "Modificado", + "ui.sessionReview.image.loading": "Cargando...", + "ui.sessionReview.image.placeholder": "Imagen", + "ui.sessionReview.largeDiff.title": "Diff demasiado grande para renderizar", + "ui.sessionReview.largeDiff.meta": "Límite: {{lines}} líneas / {{limit}}. Actual: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Renderizar de todos modos", "ui.lineComment.label.prefix": "Comentar en ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/fr.ts b/packages/ui/src/i18n/fr.ts index 537d01bba941..679d56fa76ff 100644 --- a/packages/ui/src/i18n/fr.ts +++ b/packages/ui/src/i18n/fr.ts @@ -8,6 +8,11 @@ export const dict = { "ui.sessionReview.change.added": "Ajouté", "ui.sessionReview.change.removed": "Supprimé", "ui.sessionReview.change.modified": "Modifié", + "ui.sessionReview.image.loading": "Chargement...", + "ui.sessionReview.image.placeholder": "Image", + "ui.sessionReview.largeDiff.title": "Diff trop volumineux pour être affiché", + "ui.sessionReview.largeDiff.meta": "Limite : {{lines}} lignes / {{limit}}. Actuel : {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Afficher quand même", "ui.lineComment.label.prefix": "Commenter sur ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/ja.ts b/packages/ui/src/i18n/ja.ts index 6086070bdb2c..bf85807d0052 100644 --- a/packages/ui/src/i18n/ja.ts +++ b/packages/ui/src/i18n/ja.ts @@ -9,6 +9,11 @@ export const dict = { "ui.sessionReview.change.added": "追加", "ui.sessionReview.change.removed": "削除", "ui.sessionReview.change.modified": "変更", + "ui.sessionReview.image.loading": "読み込み中...", + "ui.sessionReview.image.placeholder": "画像", + "ui.sessionReview.largeDiff.title": "差分が大きすぎて表示できません", + "ui.sessionReview.largeDiff.meta": "上限: {{lines}} 行 / {{limit}}。現在: {{current}}。", + "ui.sessionReview.largeDiff.renderAnyway": "それでも表示する", "ui.lineComment.label.prefix": "", "ui.lineComment.label.suffix": "へのコメント", "ui.lineComment.editorLabel.prefix": "", diff --git a/packages/ui/src/i18n/ko.ts b/packages/ui/src/i18n/ko.ts index fd394dbb7b52..aba793a11b8d 100644 --- a/packages/ui/src/i18n/ko.ts +++ b/packages/ui/src/i18n/ko.ts @@ -8,6 +8,11 @@ export const dict = { "ui.sessionReview.change.added": "추가됨", "ui.sessionReview.change.removed": "삭제됨", "ui.sessionReview.change.modified": "수정됨", + "ui.sessionReview.image.loading": "로딩 중...", + "ui.sessionReview.image.placeholder": "이미지", + "ui.sessionReview.largeDiff.title": "차이가 너무 커서 렌더링할 수 없습니다", + "ui.sessionReview.largeDiff.meta": "제한: {{lines}}줄 / {{limit}}. 현재: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "그래도 렌더링", "ui.lineComment.label.prefix": "", "ui.lineComment.label.suffix": "에 댓글 달기", diff --git a/packages/ui/src/i18n/no.ts b/packages/ui/src/i18n/no.ts index dcb353614d30..7982b3ac75ed 100644 --- a/packages/ui/src/i18n/no.ts +++ b/packages/ui/src/i18n/no.ts @@ -11,6 +11,11 @@ export const dict: Record = { "ui.sessionReview.change.added": "Lagt til", "ui.sessionReview.change.removed": "Fjernet", "ui.sessionReview.change.modified": "Endret", + "ui.sessionReview.image.loading": "Laster...", + "ui.sessionReview.image.placeholder": "Bilde", + "ui.sessionReview.largeDiff.title": "Diff er for stor til å gjengi", + "ui.sessionReview.largeDiff.meta": "Grense: {{lines}} linjer / {{limit}}. Nåværende: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Gjengi likevel", "ui.lineComment.label.prefix": "Kommenter på ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/pl.ts b/packages/ui/src/i18n/pl.ts index fb10debbb92d..2489ac7f2ee4 100644 --- a/packages/ui/src/i18n/pl.ts +++ b/packages/ui/src/i18n/pl.ts @@ -9,6 +9,11 @@ export const dict = { "ui.sessionReview.change.added": "Dodano", "ui.sessionReview.change.removed": "Usunięto", "ui.sessionReview.change.modified": "Zmodyfikowano", + "ui.sessionReview.image.loading": "Ładowanie...", + "ui.sessionReview.image.placeholder": "Obraz", + "ui.sessionReview.largeDiff.title": "Diff jest zbyt duży, aby go wyrenderować", + "ui.sessionReview.largeDiff.meta": "Limit: {{lines}} linii / {{limit}}. Obecnie: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Renderuj mimo to", "ui.lineComment.label.prefix": "Komentarz do ", "ui.lineComment.label.suffix": "", "ui.lineComment.editorLabel.prefix": "Komentowanie: ", diff --git a/packages/ui/src/i18n/ru.ts b/packages/ui/src/i18n/ru.ts index 417fe0ce8bfe..8e6bb678f249 100644 --- a/packages/ui/src/i18n/ru.ts +++ b/packages/ui/src/i18n/ru.ts @@ -9,6 +9,11 @@ export const dict = { "ui.sessionReview.change.added": "Добавлено", "ui.sessionReview.change.removed": "Удалено", "ui.sessionReview.change.modified": "Изменено", + "ui.sessionReview.image.loading": "Загрузка...", + "ui.sessionReview.image.placeholder": "Изображение", + "ui.sessionReview.largeDiff.title": "Diff слишком большой для отображения", + "ui.sessionReview.largeDiff.meta": "Лимит: {{lines}} строк / {{limit}}. Текущий: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "Отобразить всё равно", "ui.lineComment.label.prefix": "Комментарий к ", "ui.lineComment.label.suffix": "", "ui.lineComment.editorLabel.prefix": "Комментирование: ", diff --git a/packages/ui/src/i18n/th.ts b/packages/ui/src/i18n/th.ts index 68bb0d733d99..b036eca2e8ae 100644 --- a/packages/ui/src/i18n/th.ts +++ b/packages/ui/src/i18n/th.ts @@ -8,6 +8,11 @@ export const dict = { "ui.sessionReview.change.added": "เพิ่ม", "ui.sessionReview.change.removed": "ลบ", "ui.sessionReview.change.modified": "แก้ไข", + "ui.sessionReview.image.loading": "กำลังโหลด...", + "ui.sessionReview.image.placeholder": "รูปภาพ", + "ui.sessionReview.largeDiff.title": "Diff มีขนาดใหญ่เกินไปจนไม่สามารถแสดงผลได้", + "ui.sessionReview.largeDiff.meta": "ขีดจำกัด: {{lines}} บรรทัด / {{limit}}. ปัจจุบัน: {{current}}.", + "ui.sessionReview.largeDiff.renderAnyway": "แสดงผลต่อไป", "ui.lineComment.label.prefix": "แสดงความคิดเห็นบน ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/zh.ts b/packages/ui/src/i18n/zh.ts index 53beeb1e4f0f..dcb8062a3365 100644 --- a/packages/ui/src/i18n/zh.ts +++ b/packages/ui/src/i18n/zh.ts @@ -12,6 +12,11 @@ export const dict = { "ui.sessionReview.change.added": "已添加", "ui.sessionReview.change.removed": "已移除", "ui.sessionReview.change.modified": "已修改", + "ui.sessionReview.image.loading": "加载中...", + "ui.sessionReview.image.placeholder": "图片", + "ui.sessionReview.largeDiff.title": "差异过大,无法渲染", + "ui.sessionReview.largeDiff.meta": "限制:{{lines}} 行 / {{limit}}。当前:{{current}}。", + "ui.sessionReview.largeDiff.renderAnyway": "仍然渲染", "ui.lineComment.label.prefix": "评论 ", "ui.lineComment.label.suffix": "", diff --git a/packages/ui/src/i18n/zht.ts b/packages/ui/src/i18n/zht.ts index 1449b0530ac1..271a6ded3253 100644 --- a/packages/ui/src/i18n/zht.ts +++ b/packages/ui/src/i18n/zht.ts @@ -12,6 +12,11 @@ export const dict = { "ui.sessionReview.change.added": "已新增", "ui.sessionReview.change.removed": "已移除", "ui.sessionReview.change.modified": "已修改", + "ui.sessionReview.image.loading": "載入中...", + "ui.sessionReview.image.placeholder": "圖片", + "ui.sessionReview.largeDiff.title": "差異過大,無法渲染", + "ui.sessionReview.largeDiff.meta": "限制:{{lines}} 行 / {{limit}}。目前:{{current}}。", + "ui.sessionReview.largeDiff.renderAnyway": "仍然渲染", "ui.lineComment.label.prefix": "評論 ", "ui.lineComment.label.suffix": "",