diff --git a/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeLive.swift b/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeLive.swift index b6264c5a60e7..735723c2c02d 100644 --- a/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeLive.swift +++ b/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeLive.swift @@ -136,7 +136,8 @@ public struct HomeLiveRun: Hashable, Sendable { /// The run's talk steps in order, joined by a blank line ("" before the first text). public var text: String public var activity: HomeLiveActivity? - /// The newest thought the run streams now (a thought step not yet ended), whole; nil when none. + /// The headline of the run's newest thought (``HomeThoughtHeadline``), kept after its step ends + /// until the next thought; nil when there is none. /// Home's running indicator shows its headline as the Chief's progress narration. public var thought: String? = nil diff --git a/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeLiveBook.swift b/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeLiveBook.swift index 3aca0e4587e2..98cc59dc9c94 100644 --- a/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeLiveBook.swift +++ b/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeLiveBook.swift @@ -267,7 +267,7 @@ struct HomeLiveBook { .sorted { (Self.place(run.steps[$0.element]), $0.offset) < (Self.place(run.steps[$1.element]), $1.offset) } .compactMap { run.steps[$0.element]?.text } .filter { !$0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty } - let thought = run.lastThought.flatMap { $0.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty ? nil : $0 } + let thought = run.lastThought.flatMap(HomeThoughtHeadline.of) return HomeLiveRun(participant: key.author, run: key.run, turn: turn(of: key), text: talk.joined(separator: "\n\n"), activity: run.activity, thought: thought) } diff --git a/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeThoughtHeadline.swift b/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeThoughtHeadline.swift new file mode 100644 index 000000000000..c47ec4097d5d --- /dev/null +++ b/Packages/Shared/CmuxHomeCore/Sources/CmuxHomeCore/Store/HomeThoughtHeadline.swift @@ -0,0 +1,45 @@ +import Foundation + +/// The headline of one of the Chief's thoughts: what its running indicator shows as progress narration. +/// +/// The live book publishes this, not the whole thought, so a streamed thought token changes the +/// store's live state only when the line a person sees changes. +public enum HomeThoughtHeadline { + /// Most characters a headline keeps. + public static let limit = 72 + + /// A thought's headline: its last bold heading line ("**Checking the tests**", how Claude and + /// Codex title their reasoning summaries), else its last sentence, as plain text of at most + /// ``limit`` characters. Nil for a thought with no words. + public static func of(_ thought: String) -> String? { + let lines = thought.split(whereSeparator: \.isNewline).map { $0.trimmingCharacters(in: .whitespaces) } + .filter { !$0.isEmpty } + let heading = lines.last { $0.count > 4 && $0.hasPrefix("**") && $0.hasSuffix("**") } + let raw: String + if let heading { + raw = String(heading.dropFirst(2).dropLast(2)) + } else if let last = lines.last { + raw = lastSentence(last) + } else { + return nil + } + let plain = raw.replacingOccurrences(of: "**", with: "").replacingOccurrences(of: "`", with: "") + .trimmingCharacters(in: CharacterSet(charactersIn: "*_#> ").union(.whitespaces)) + guard !plain.isEmpty else { return nil } + guard plain.count > limit else { return plain } + return String(plain.prefix(limit - 1)).trimmingCharacters(in: .whitespaces) + "…" + } + + /// The last sentence of `line` (after its last ". ", "! " or "? "), or the line. + static func lastSentence(_ line: String) -> String { + let trimmed = line.trimmingCharacters(in: .whitespaces) + let body = trimmed.last.map { ".!?".contains($0) } == true ? String(trimmed.dropLast()) : trimmed + // After the last ". ", then the last "! " after it, then the last "? ": after the last end of any kind. + var rest = body + for end in [". ", "! ", "? "] { + if let range = rest.range(of: end, options: .backwards) { rest = String(rest.suffix(from: range.upperBound)) } + } + let sentence = rest.trimmingCharacters(in: .whitespaces) + return sentence.isEmpty ? trimmed : sentence + } +} diff --git a/Packages/Shared/CmuxMessagesLab/Sources/MessagesLabHome/Cmux/HomeTurnProgress.swift b/Packages/Shared/CmuxMessagesLab/Sources/MessagesLabHome/Cmux/HomeTurnProgress.swift index 37fa8854d975..42f20753bd16 100644 --- a/Packages/Shared/CmuxMessagesLab/Sources/MessagesLabHome/Cmux/HomeTurnProgress.swift +++ b/Packages/Shared/CmuxMessagesLab/Sources/MessagesLabHome/Cmux/HomeTurnProgress.swift @@ -34,7 +34,7 @@ struct HomeTurnProgress: Equatable { /// Lines the owner sends for its own writing, not a step of the turn's work. static let notSteps: Set = ["Thinking", "Writing the reply", "Working"] /// Most characters a narration row keeps. - static let narrationLimit = 72 + static var narrationLimit: Int { HomeThoughtHeadline.limit } init(summary: String?, narration: String?, current: String) { self.summary = summary @@ -54,7 +54,8 @@ struct HomeTurnProgress: Equatable { } let finished = steps.filter { $0.end != nil }.map(\.line).filter { !Self.notSteps.contains($0) } let summary = Self.summary(finished) - var narration = style == .narrated ? thought.flatMap(Self.headline) : nil + // `thought` is already the headline (the live book publishes `HomeThoughtHeadline.of`). + var narration = style == .narrated ? thought : nil var current = line if let told = narration, activity.line == "Thinking" { // Thinking now: its headline is the running row, not a second row over "Thinking". @@ -126,38 +127,6 @@ struct HomeTurnProgress: Equatable { // MARK: Narration - /// A thought's headline: its last bold heading line ("**Checking the tests**", how Claude and - /// Codex title their reasoning summaries), else its last sentence, as plain text of at most - /// ``narrationLimit`` characters. Nil for a thought with no words. - static func headline(_ thought: String) -> String? { - let lines = thought.split(whereSeparator: \.isNewline).map { $0.trimmingCharacters(in: .whitespaces) } - .filter { !$0.isEmpty } - let heading = lines.last { $0.count > 4 && $0.hasPrefix("**") && $0.hasSuffix("**") } - let raw: String - if let heading { - raw = String(heading.dropFirst(2).dropLast(2)) - } else if let last = lines.last { - raw = lastSentence(last) - } else { - return nil - } - let plain = raw.replacingOccurrences(of: "**", with: "").replacingOccurrences(of: "`", with: "") - .trimmingCharacters(in: CharacterSet(charactersIn: "*_#> ").union(.whitespaces)) - guard !plain.isEmpty else { return nil } - guard plain.count > narrationLimit else { return plain } - return String(plain.prefix(narrationLimit - 1)).trimmingCharacters(in: .whitespaces) + "…" - } - - /// The last sentence of `line` (after its last ". ", "! " or "? "), or the line. - static func lastSentence(_ line: String) -> String { - let trimmed = line.trimmingCharacters(in: .whitespaces) - let body = trimmed.last.map { ".!?".contains($0) } == true ? String(trimmed.dropLast()) : trimmed - // After the last ". ", then the last "! " after it, then the last "? ": after the last end of any kind. - var rest = body - for end in [". ", "! ", "? "] { - if let range = rest.range(of: end, options: .backwards) { rest = String(rest.suffix(from: range.upperBound)) } - } - let sentence = rest.trimmingCharacters(in: .whitespaces) - return sentence.isEmpty ? trimmed : sentence - } + /// A thought's headline (``HomeThoughtHeadline``): the store already publishes it this way. + static func headline(_ thought: String) -> String? { HomeThoughtHeadline.of(thought) } } diff --git a/Packages/Shared/CmuxMessagesLab/Sources/MessagesLabHome/Resources/CmuxHome.xcstrings b/Packages/Shared/CmuxMessagesLab/Sources/MessagesLabHome/Resources/CmuxHome.xcstrings index 78e91687d676..881bcb704d79 100644 --- a/Packages/Shared/CmuxMessagesLab/Sources/MessagesLabHome/Resources/CmuxHome.xcstrings +++ b/Packages/Shared/CmuxMessagesLab/Sources/MessagesLabHome/Resources/CmuxHome.xcstrings @@ -3419,129 +3419,471 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Ran %lld commands" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Ran %lld command" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Ran %lld commands" + } + } + } } }, "ar": { - "stringUnit": { - "state": "needs_review", - "value": "تم تشغيل %lld أوامر" + "variations": { + "plural": { + "zero": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld أمر" + } + }, + "one": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld أمر" + } + }, + "two": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld أمرين" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld أوامر" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld أمرًا" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld أمر" + } + } + } } }, "bs": { - "stringUnit": { - "state": "needs_review", - "value": "Pokrenuto komandi: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Pokrenuta %lld komanda" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Pokrenute %lld komande" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Pokrenuto %lld komandi" + } + } + } } }, "da": { - "stringUnit": { - "state": "needs_review", - "value": "Kørte %lld kommandoer" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Kørte %lld kommando" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Kørte %lld kommandoer" + } + } + } } }, "de": { - "stringUnit": { - "state": "needs_review", - "value": "%lld Befehle ausgeführt" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Befehl ausgeführt" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Befehle ausgeführt" + } + } + } } }, "es": { - "stringUnit": { - "state": "needs_review", - "value": "Se ejecutaron %lld comandos" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Se ejecutó %lld comando" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Se ejecutaron %lld de comandos" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Se ejecutaron %lld comandos" + } + } + } } }, "fr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld commandes exécutées" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld commande exécutée" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de commandes exécutées" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld commandes exécutées" + } + } + } } }, "it": { - "stringUnit": { - "state": "needs_review", - "value": "Eseguiti %lld comandi" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Eseguito %lld comando" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Eseguiti %lld comandi" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Eseguiti %lld comandi" + } + } + } } }, "ja": { - "stringUnit": { - "state": "needs_review", - "value": "%lld 件のコマンドを実行しました" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 件のコマンドを実行しました" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 件のコマンドを実行しました" + } + } + } } }, "km": { - "stringUnit": { - "state": "needs_review", - "value": "បានដំណើរការពាក្យបញ្ជា %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "បានដំណើរការពាក្យបញ្ជា %lld" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "បានដំណើរការពាក្យបញ្ជា %lld" + } + } + } } }, "ko": { - "stringUnit": { - "state": "needs_review", - "value": "명령 %lld개 실행함" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "명령 %lld개 실행함" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "명령 %lld개 실행함" + } + } + } } }, "nb": { - "stringUnit": { - "state": "needs_review", - "value": "Kjørte %lld kommandoer" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Kjørte %lld kommando" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Kjørte %lld kommandoer" + } + } + } } }, "pl": { - "stringUnit": { - "state": "needs_review", - "value": "Uruchomiono poleceń: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Uruchomiono %lld polecenie" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Uruchomiono %lld polecenia" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Uruchomiono %lld poleceń" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Uruchomiono %lld polecenia" + } + } + } } }, "pt-BR": { - "stringUnit": { - "state": "needs_review", - "value": "%lld comandos executados" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld comando executado" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de comandos executados" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld comandos executados" + } + } + } } }, "ru": { - "stringUnit": { - "state": "needs_review", - "value": "Выполнено команд: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Выполнена %lld команда" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Выполнено %lld команды" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Выполнено %lld команд" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Выполнено %lld команды" + } + } + } } }, "th": { - "stringUnit": { - "state": "needs_review", - "value": "รันแล้ว %lld คำสั่ง" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "รันแล้ว %lld คำสั่ง" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "รันแล้ว %lld คำสั่ง" + } + } + } } }, "tr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld komut çalıştırıldı" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld komut çalıştırıldı" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld komut çalıştırıldı" + } + } + } } }, "uk": { - "stringUnit": { - "state": "needs_review", - "value": "Виконано команд: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Виконано %lld команду" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Виконано %lld команди" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Виконано %lld команд" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Виконано %lld команди" + } + } + } } }, "vi": { - "stringUnit": { - "state": "needs_review", - "value": "Đã chạy %lld lệnh" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Đã chạy %lld lệnh" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Đã chạy %lld lệnh" + } + } + } } }, "zh-Hans": { - "stringUnit": { - "state": "needs_review", - "value": "运行了 %lld 个命令" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "运行了 %lld 个命令" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "运行了 %lld 个命令" + } + } + } } }, "zh-Hant": { - "stringUnit": { - "state": "needs_review", - "value": "執行了 %lld 個指令" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "執行了 %lld 個指令" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "執行了 %lld 個指令" + } + } + } } } } @@ -3551,129 +3893,471 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Read %lld files" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Read %lld file" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Read %lld files" + } + } + } } }, "ar": { - "stringUnit": { - "state": "needs_review", - "value": "قراءة %lld ملفات" + "variations": { + "plural": { + "zero": { + "stringUnit": { + "state": "needs_review", + "value": "قراءة %lld ملف" + } + }, + "one": { + "stringUnit": { + "state": "needs_review", + "value": "قراءة %lld ملف" + } + }, + "two": { + "stringUnit": { + "state": "needs_review", + "value": "قراءة %lld ملفين" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "قراءة %lld ملفات" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "قراءة %lld ملفًا" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "قراءة %lld ملف" + } + } + } } }, "bs": { - "stringUnit": { - "state": "needs_review", - "value": "Pročitano datoteka: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Pročitana %lld datoteka" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Pročitane %lld datoteke" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Pročitano %lld datoteka" + } + } + } } }, "da": { - "stringUnit": { - "state": "needs_review", - "value": "Læste %lld filer" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Læste %lld fil" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Læste %lld filer" + } + } + } } }, "de": { - "stringUnit": { - "state": "needs_review", - "value": "%lld Dateien gelesen" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Datei gelesen" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Dateien gelesen" + } + } + } } }, "es": { - "stringUnit": { - "state": "needs_review", - "value": "Leyó %lld archivos" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Leyó %lld archivo" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Leyó %lld de archivos" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Leyó %lld archivos" + } + } + } } }, "fr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld fichiers lus" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld fichier lu" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de fichiers lus" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld fichiers lus" + } + } + } } }, "it": { - "stringUnit": { - "state": "needs_review", - "value": "Letti %lld file" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Letto %lld file" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Letti %lld file" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Letti %lld file" + } + } + } } }, "ja": { - "stringUnit": { - "state": "needs_review", - "value": "%lld 件のファイルを読みました" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 件のファイルを読みました" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 件のファイルを読みました" + } + } + } } }, "km": { - "stringUnit": { - "state": "needs_review", - "value": "បានអានឯកសារ %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "បានអានឯកសារ %lld" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "បានអានឯកសារ %lld" + } + } + } } }, "ko": { - "stringUnit": { - "state": "needs_review", - "value": "파일 %lld개 읽음" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "파일 %lld개 읽음" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "파일 %lld개 읽음" + } + } + } } }, "nb": { - "stringUnit": { - "state": "needs_review", - "value": "Leste %lld filer" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Leste %lld fil" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Leste %lld filer" + } + } + } } }, "pl": { - "stringUnit": { - "state": "needs_review", - "value": "Odczytano plików: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Odczytano %lld plik" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Odczytano %lld pliki" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Odczytano %lld plików" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Odczytano %lld pliku" + } + } + } } }, "pt-BR": { - "stringUnit": { - "state": "needs_review", - "value": "%lld arquivos lidos" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld arquivo lido" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de arquivos lidos" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld arquivos lidos" + } + } + } } }, "ru": { - "stringUnit": { - "state": "needs_review", - "value": "Прочитано файлов: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Прочитан %lld файл" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Прочитано %lld файла" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Прочитано %lld файлов" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Прочитано %lld файла" + } + } + } } }, "th": { - "stringUnit": { - "state": "needs_review", - "value": "อ่าน %lld ไฟล์" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "อ่าน %lld ไฟล์" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "อ่าน %lld ไฟล์" + } + } + } } }, "tr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld dosya okundu" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld dosya okundu" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld dosya okundu" + } + } + } } }, "uk": { - "stringUnit": { - "state": "needs_review", - "value": "Прочитано файлів: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Прочитано %lld файл" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Прочитано %lld файли" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Прочитано %lld файлів" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Прочитано %lld файлу" + } + } + } } }, "vi": { - "stringUnit": { - "state": "needs_review", - "value": "Đã đọc %lld tệp" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Đã đọc %lld tệp" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Đã đọc %lld tệp" + } + } + } } }, "zh-Hans": { - "stringUnit": { - "state": "needs_review", - "value": "读取了 %lld 个文件" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "读取了 %lld 个文件" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "读取了 %lld 个文件" + } + } + } } }, "zh-Hant": { - "stringUnit": { - "state": "needs_review", - "value": "讀取了 %lld 個檔案" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "讀取了 %lld 個檔案" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "讀取了 %lld 個檔案" + } + } + } } } } @@ -3683,129 +4367,471 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Edited %lld files" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Edited %lld file" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Edited %lld files" + } + } + } } }, "ar": { - "stringUnit": { - "state": "needs_review", - "value": "تحرير %lld ملفات" + "variations": { + "plural": { + "zero": { + "stringUnit": { + "state": "needs_review", + "value": "تحرير %lld ملف" + } + }, + "one": { + "stringUnit": { + "state": "needs_review", + "value": "تحرير %lld ملف" + } + }, + "two": { + "stringUnit": { + "state": "needs_review", + "value": "تحرير %lld ملفين" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "تحرير %lld ملفات" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "تحرير %lld ملفًا" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "تحرير %lld ملف" + } + } + } } }, "bs": { - "stringUnit": { - "state": "needs_review", - "value": "Uređeno datoteka: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Uređena %lld datoteka" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Uređene %lld datoteke" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Uređeno %lld datoteka" + } + } + } } }, "da": { - "stringUnit": { - "state": "needs_review", - "value": "Redigerede %lld filer" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Redigerede %lld fil" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Redigerede %lld filer" + } + } + } } }, "de": { - "stringUnit": { - "state": "needs_review", - "value": "%lld Dateien bearbeitet" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Datei bearbeitet" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Dateien bearbeitet" + } + } + } } }, "es": { - "stringUnit": { - "state": "needs_review", - "value": "Editó %lld archivos" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Editó %lld archivo" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Editó %lld de archivos" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Editó %lld archivos" + } + } + } } }, "fr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld fichiers modifiés" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld fichier modifié" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de fichiers modifiés" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld fichiers modifiés" + } + } + } } }, "it": { - "stringUnit": { - "state": "needs_review", - "value": "Modificati %lld file" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Modificato %lld file" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Modificati %lld file" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Modificati %lld file" + } + } + } } }, "ja": { - "stringUnit": { - "state": "needs_review", - "value": "%lld 件のファイルを編集しました" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 件のファイルを編集しました" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 件のファイルを編集しました" + } + } + } } }, "km": { - "stringUnit": { - "state": "needs_review", - "value": "បានកែសម្រួលឯកសារ %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "បានកែសម្រួលឯកសារ %lld" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "បានកែសម្រួលឯកសារ %lld" + } + } + } } }, "ko": { - "stringUnit": { - "state": "needs_review", - "value": "파일 %lld개 편집함" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "파일 %lld개 편집함" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "파일 %lld개 편집함" + } + } + } } }, "nb": { - "stringUnit": { - "state": "needs_review", - "value": "Redigerte %lld filer" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Redigerte %lld fil" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Redigerte %lld filer" + } + } + } } }, "pl": { - "stringUnit": { - "state": "needs_review", - "value": "Edytowano plików: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Edytowano %lld plik" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Edytowano %lld pliki" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Edytowano %lld plików" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Edytowano %lld pliku" + } + } + } } }, "pt-BR": { - "stringUnit": { - "state": "needs_review", - "value": "%lld arquivos editados" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld arquivo editado" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de arquivos editados" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld arquivos editados" + } + } + } } }, "ru": { - "stringUnit": { - "state": "needs_review", - "value": "Изменено файлов: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Изменён %lld файл" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Изменено %lld файла" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Изменено %lld файлов" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Изменено %lld файла" + } + } + } } }, "th": { - "stringUnit": { - "state": "needs_review", - "value": "แก้ไข %lld ไฟล์แล้ว" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "แก้ไข %lld ไฟล์แล้ว" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "แก้ไข %lld ไฟล์แล้ว" + } + } + } } }, "tr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld dosya düzenlendi" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld dosya düzenlendi" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld dosya düzenlendi" + } + } + } } }, "uk": { - "stringUnit": { - "state": "needs_review", - "value": "Відредаговано файлів: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Відредаговано %lld файл" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Відредаговано %lld файли" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Відредаговано %lld файлів" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Відредаговано %lld файлу" + } + } + } } }, "vi": { - "stringUnit": { - "state": "needs_review", - "value": "Đã chỉnh sửa %lld tệp" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Đã chỉnh sửa %lld tệp" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Đã chỉnh sửa %lld tệp" + } + } + } } }, "zh-Hans": { - "stringUnit": { - "state": "needs_review", - "value": "编辑了 %lld 个文件" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "编辑了 %lld 个文件" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "编辑了 %lld 个文件" + } + } + } } }, "zh-Hant": { - "stringUnit": { - "state": "needs_review", - "value": "編輯了 %lld 個檔案" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "編輯了 %lld 個檔案" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "編輯了 %lld 個檔案" + } + } + } } } } @@ -3815,129 +4841,471 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "Ran %lld searches" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "Ran %lld search" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "Ran %lld searches" + } + } + } } }, "ar": { - "stringUnit": { - "state": "needs_review", - "value": "تم تشغيل %lld عمليات بحث" + "variations": { + "plural": { + "zero": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld عملية بحث" + } + }, + "one": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld عملية بحث" + } + }, + "two": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld عمليتي بحث" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld عمليات بحث" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld عملية بحث" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "تم تشغيل %lld عملية بحث" + } + } + } } }, "bs": { - "stringUnit": { - "state": "needs_review", - "value": "Pokrenuto pretraga: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Pokrenuta %lld pretraga" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Pokrenute %lld pretrage" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Pokrenuto %lld pretraga" + } + } + } } }, "da": { - "stringUnit": { - "state": "needs_review", - "value": "Kørte %lld søgninger" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Kørte %lld søgning" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Kørte %lld søgninger" + } + } + } } }, "de": { - "stringUnit": { - "state": "needs_review", - "value": "%lld Suchen ausgeführt" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Suche ausgeführt" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Suchen ausgeführt" + } + } + } } }, "es": { - "stringUnit": { - "state": "needs_review", - "value": "Ejecutó %lld búsquedas" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Ejecutó %lld búsqueda" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Ejecutó %lld de búsquedas" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Ejecutó %lld búsquedas" + } + } + } } }, "fr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld recherches effectuées" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld recherche effectuée" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de recherches effectuées" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld recherches effectuées" + } + } + } } }, "it": { - "stringUnit": { - "state": "needs_review", - "value": "Eseguite %lld ricerche" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Eseguita %lld ricerca" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Eseguite %lld ricerche" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Eseguite %lld ricerche" + } + } + } } }, "ja": { - "stringUnit": { - "state": "needs_review", - "value": "%lld 回検索しました" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 回検索しました" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 回検索しました" + } + } + } } }, "km": { - "stringUnit": { - "state": "needs_review", - "value": "បានដំណើរការការស្វែងរក %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "បានដំណើរការការស្វែងរក %lld" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "បានដំណើរការការស្វែងរក %lld" + } + } + } } }, "ko": { - "stringUnit": { - "state": "needs_review", - "value": "검색 %lld회 실행함" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "검색 %lld회 실행함" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "검색 %lld회 실행함" + } + } + } } }, "nb": { - "stringUnit": { - "state": "needs_review", - "value": "Kjørte %lld søk" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Kjørte %lld søk" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Kjørte %lld søk" + } + } + } } }, "pl": { - "stringUnit": { - "state": "needs_review", - "value": "Wykonano wyszukiwań: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Wykonano %lld wyszukiwanie" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Wykonano %lld wyszukiwania" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Wykonano %lld wyszukiwań" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Wykonano %lld wyszukiwania" + } + } + } } }, "pt-BR": { - "stringUnit": { - "state": "needs_review", - "value": "%lld pesquisas executadas" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld pesquisa executada" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de pesquisas executadas" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld pesquisas executadas" + } + } + } } }, "ru": { - "stringUnit": { - "state": "needs_review", - "value": "Выполнено поисков: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Выполнен %lld поиск" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Выполнено %lld поиска" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Выполнено %lld поисков" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Выполнено %lld поиска" + } + } + } } }, "th": { - "stringUnit": { - "state": "needs_review", - "value": "ค้นหาแล้ว %lld ครั้ง" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "ค้นหาแล้ว %lld ครั้ง" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "ค้นหาแล้ว %lld ครั้ง" + } + } + } } }, "tr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld arama yapıldı" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld arama yapıldı" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld arama yapıldı" + } + } + } } }, "uk": { - "stringUnit": { - "state": "needs_review", - "value": "Виконано пошуків: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Виконано %lld пошук" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Виконано %lld пошуки" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Виконано %lld пошуків" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Виконано %lld пошуку" + } + } + } } }, "vi": { - "stringUnit": { - "state": "needs_review", - "value": "Đã chạy %lld lượt tìm kiếm" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Đã chạy %lld lượt tìm kiếm" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Đã chạy %lld lượt tìm kiếm" + } + } + } } }, "zh-Hans": { - "stringUnit": { - "state": "needs_review", - "value": "运行了 %lld 次搜索" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "运行了 %lld 次搜索" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "运行了 %lld 次搜索" + } + } + } } }, "zh-Hant": { - "stringUnit": { - "state": "needs_review", - "value": "執行了 %lld 次搜尋" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "執行了 %lld 次搜尋" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "執行了 %lld 次搜尋" + } + } + } } } } @@ -3947,129 +5315,471 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "%lld steps" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld step" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld steps" + } + } + } } }, "ar": { - "stringUnit": { - "state": "needs_review", - "value": "%lld خطوات" + "variations": { + "plural": { + "zero": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوة" + } + }, + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوة" + } + }, + "two": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوتان" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوات" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوة" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوة" + } + } + } } }, "bs": { - "stringUnit": { - "state": "needs_review", - "value": "%lld koraka" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld korak" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "%lld koraka" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld koraka" + } + } + } } }, "da": { - "stringUnit": { - "state": "needs_review", - "value": "%lld trin" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld trin" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld trin" + } + } + } } }, "de": { - "stringUnit": { - "state": "needs_review", - "value": "%lld Schritte" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Schritt" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld Schritte" + } + } + } } }, "es": { - "stringUnit": { - "state": "needs_review", - "value": "%lld pasos" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld paso" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de pasos" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld pasos" + } + } + } } }, "fr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld étapes" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld étape" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld d’étapes" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld étapes" + } + } + } } }, "it": { - "stringUnit": { - "state": "needs_review", - "value": "%lld passaggi" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld passaggio" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld passaggi" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld passaggi" + } + } + } } }, "ja": { - "stringUnit": { - "state": "needs_review", - "value": "%lld 個のステップ" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 個のステップ" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 個のステップ" + } + } + } } }, "km": { - "stringUnit": { - "state": "needs_review", - "value": "%lld ជំហាន" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld ជំហាន" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld ជំហាន" + } + } + } } }, "ko": { - "stringUnit": { - "state": "needs_review", - "value": "%lld단계" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld단계" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld단계" + } + } + } } }, "nb": { - "stringUnit": { - "state": "needs_review", - "value": "%lld trinn" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld trinn" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld trinn" + } + } + } } }, "pl": { - "stringUnit": { - "state": "needs_review", - "value": "Kroki: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld krok" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "%lld kroki" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld kroków" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld kroku" + } + } + } } }, "pt-BR": { - "stringUnit": { - "state": "needs_review", - "value": "%lld etapas" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld etapa" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de etapas" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld etapas" + } + } + } } }, "ru": { - "stringUnit": { - "state": "needs_review", - "value": "Шагов: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld шаг" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "%lld шага" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld шагов" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld шага" + } + } + } } }, "th": { - "stringUnit": { - "state": "needs_review", - "value": "%lld ขั้นตอน" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld ขั้นตอน" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld ขั้นตอน" + } + } + } } }, "tr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld adım" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld adım" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld adım" + } + } + } } }, "uk": { - "stringUnit": { - "state": "needs_review", - "value": "Кроків: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld крок" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "%lld кроки" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld кроків" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld кроку" + } + } + } } }, "vi": { - "stringUnit": { - "state": "needs_review", - "value": "%lld bước" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld bước" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld bước" + } + } + } } }, "zh-Hans": { - "stringUnit": { - "state": "needs_review", - "value": "%lld 个步骤" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 个步骤" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 个步骤" + } + } + } } }, "zh-Hant": { - "stringUnit": { - "state": "needs_review", - "value": "%lld 個步驟" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 個步驟" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld 個步驟" + } + } + } } } } @@ -4079,129 +5789,471 @@ "extractionState": "manual", "localizations": { "en": { - "stringUnit": { - "state": "translated", - "value": "%lld more steps" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "translated", + "value": "%lld more step" + } + }, + "other": { + "stringUnit": { + "state": "translated", + "value": "%lld more steps" + } + } + } } }, "ar": { - "stringUnit": { - "state": "needs_review", - "value": "%lld خطوات أخرى" + "variations": { + "plural": { + "zero": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوة أخرى" + } + }, + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوة أخرى" + } + }, + "two": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوتان أخريان" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوات أخرى" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوة أخرى" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld خطوة أخرى" + } + } + } } }, "bs": { - "stringUnit": { - "state": "needs_review", - "value": "još %lld koraka" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "još %lld korak" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "još %lld koraka" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "još %lld koraka" + } + } + } } }, "da": { - "stringUnit": { - "state": "needs_review", - "value": "%lld trin mere" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld trin mere" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld trin mere" + } + } + } } }, "de": { - "stringUnit": { - "state": "needs_review", - "value": "%lld weitere Schritte" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld weiterer Schritt" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld weitere Schritte" + } + } + } } }, "es": { - "stringUnit": { - "state": "needs_review", - "value": "%lld pasos más" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld paso más" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld de pasos más" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld pasos más" + } + } + } } }, "fr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld étapes de plus" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld étape de plus" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "%lld d’étapes de plus" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld étapes de plus" + } + } + } } }, "it": { - "stringUnit": { - "state": "needs_review", - "value": "altri %lld passaggi" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "altro %lld passaggio" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "altri %lld passaggi" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "altri %lld passaggi" + } + } + } } }, "ja": { - "stringUnit": { - "state": "needs_review", - "value": "他 %lld 個のステップ" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "他 %lld 個のステップ" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "他 %lld 個のステップ" + } + } + } } }, "km": { - "stringUnit": { - "state": "needs_review", - "value": "%lld ជំហានទៀត" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld ជំហានទៀត" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld ជំហានទៀត" + } + } + } } }, "ko": { - "stringUnit": { - "state": "needs_review", - "value": "%lld단계 더" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld단계 더" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld단계 더" + } + } + } } }, "nb": { - "stringUnit": { - "state": "needs_review", - "value": "%lld trinn til" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld trinn til" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld trinn til" + } + } + } } }, "pl": { - "stringUnit": { - "state": "needs_review", - "value": "Więcej kroków: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Jeszcze %lld krok" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Jeszcze %lld kroki" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Jeszcze %lld kroków" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Jeszcze %lld kroku" + } + } + } } }, "pt-BR": { - "stringUnit": { - "state": "needs_review", - "value": "mais %lld etapas" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "mais %lld etapa" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "mais %lld de etapas" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "mais %lld etapas" + } + } + } } }, "ru": { - "stringUnit": { - "state": "needs_review", - "value": "Ещё шагов: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Ещё %lld шаг" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Ещё %lld шага" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Ещё %lld шагов" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Ещё %lld шага" + } + } + } } }, "th": { - "stringUnit": { - "state": "needs_review", - "value": "อีก %lld ขั้นตอน" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "อีก %lld ขั้นตอน" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "อีก %lld ขั้นตอน" + } + } + } } }, "tr": { - "stringUnit": { - "state": "needs_review", - "value": "%lld adım daha" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "%lld adım daha" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "%lld adım daha" + } + } + } } }, "uk": { - "stringUnit": { - "state": "needs_review", - "value": "Ще кроків: %lld" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "Ще %lld крок" + } + }, + "few": { + "stringUnit": { + "state": "needs_review", + "value": "Ще %lld кроки" + } + }, + "many": { + "stringUnit": { + "state": "needs_review", + "value": "Ще %lld кроків" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "Ще %lld кроку" + } + } + } } }, "vi": { - "stringUnit": { - "state": "needs_review", - "value": "thêm %lld bước" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "thêm %lld bước" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "thêm %lld bước" + } + } + } } }, "zh-Hans": { - "stringUnit": { - "state": "needs_review", - "value": "另外 %lld 个步骤" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "另外 %lld 个步骤" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "另外 %lld 个步骤" + } + } + } } }, "zh-Hant": { - "stringUnit": { - "state": "needs_review", - "value": "另外 %lld 個步驟" + "variations": { + "plural": { + "one": { + "stringUnit": { + "state": "needs_review", + "value": "另外 %lld 個步驟" + } + }, + "other": { + "stringUnit": { + "state": "needs_review", + "value": "另外 %lld 個步驟" + } + } + } } } } diff --git a/Packages/Shared/CmuxMessagesLab/Tests/MessagesLabHomeTests/HomeTurnProgressTests.swift b/Packages/Shared/CmuxMessagesLab/Tests/MessagesLabHomeTests/HomeTurnProgressTests.swift index 382f953c2cb4..08f724b87179 100644 --- a/Packages/Shared/CmuxMessagesLab/Tests/MessagesLabHomeTests/HomeTurnProgressTests.swift +++ b/Packages/Shared/CmuxMessagesLab/Tests/MessagesLabHomeTests/HomeTurnProgressTests.swift @@ -17,10 +17,11 @@ import Testing return steps } + /// The indicator for `lines` with the raw `thought`, headlined the way the live book publishes it. static func progress(_ lines: [String], thought: String? = nil, style: HomeTurnProgressStyle = .narrated) -> HomeTurnProgress { let steps = steps(lines) let current = HomeLiveActivity(line: lines.last ?? "Thinking", since: t0.addingTimeInterval(Double(lines.count - 1) * 10)) - return HomeTurnProgress(steps: steps.steps, current: current, thought: thought, + return HomeTurnProgress(steps: steps.steps, current: current, thought: thought.flatMap(HomeThoughtHeadline.of), now: current.since.addingTimeInterval(5), style: style) } @@ -70,6 +71,14 @@ import Testing #expect(line.rows == ["Checking on a31 · 5s"]) } + @Test func thePublishedHeadlineShowsAsItIs() { + // A heading with a sentence end inside it stays whole: the indicator does not headline it again. + let progress = Self.progress(["Telling a31", "Checking on a31"], thought: "**Checking a31. Then a7**") + #expect(progress.narration == "Checking a31. Then a7") + let done = Self.progress(["Telling a31", "Checking on a31"], thought: "**Done!**") + #expect(done.narration == "Done!") + } + @Test func whileThinkingTheThoughtIsTheStepNow() { let progress = Self.progress(["Telling a31", "Thinking"], thought: "Let me look. I should check whether a31 finished") #expect(progress.rows == ["Telling a31 ›", "I should check whether a31 finished · 5s"]) @@ -100,7 +109,7 @@ import Testing line.dispatch = { shown.append($0) } let activity = HomeLiveActivity(line: "Checking on a31", since: Self.t0) line.show(activity) - line.show(activity, thought: "**Waiting for the tests**") + line.show(activity, thought: "Waiting for the tests") #expect(shown.last == "Waiting for the tests\nChecking on a31") line.stop() } @@ -116,12 +125,13 @@ import Testing activity: HomeLiveActivity(line: "Checking on a31", since: Date()))))) rig.store.handle(.live(.delta(HomeLiveDelta(conversation: conversation, author: rig.chief, run: "r1", step: "thought:0", isTalk: false, seq: 0, text: "**Waiting for a31**", isFinal: false)))) - #expect(rig.store.liveRun(in: conversation)?.thought == "**Waiting for a31**") + // The store publishes the thought's headline, not its whole text. + #expect(rig.store.liveRun(in: conversation)?.thought == "Waiting for a31") // Its last frame ends the step; the thought stays the run's narration until the next one. rig.store.handle(.live(.delta(HomeLiveDelta(conversation: conversation, author: rig.chief, run: "r1", step: "thought:0", - isTalk: false, seq: 1, text: "\n\nIt runs its tests.", isFinal: true)))) - #expect(rig.store.liveRun(in: conversation)?.thought == "**Waiting for a31**\n\nIt runs its tests.") + isTalk: false, seq: 1, text: "\n\n**Reading its test log**", isFinal: true)))) + #expect(rig.store.liveRun(in: conversation)?.thought == "Reading its test log") rig.frame() - #expect(rig.view.debugStatusLine?.components(separatedBy: "\n").first == "Waiting for a31") + #expect(rig.view.debugStatusLine?.components(separatedBy: "\n").first == "Reading its test log") } } diff --git a/scripts/localization-plurals.json b/scripts/localization-plurals.json index 1b51c52126a3..cb6519ede8cc 100644 --- a/scripts/localization-plurals.json +++ b/scripts/localization-plurals.json @@ -621,5 +621,41 @@ "arguments": [ 1 ] + }, + "home.turn.ranCommands": { + "source": "Ran %lld commands", + "arguments": [ + 1 + ] + }, + "home.turn.readFiles": { + "source": "Read %lld files", + "arguments": [ + 1 + ] + }, + "home.turn.editedFiles": { + "source": "Edited %lld files", + "arguments": [ + 1 + ] + }, + "home.turn.ranSearches": { + "source": "Ran %lld searches", + "arguments": [ + 1 + ] + }, + "home.turn.steps": { + "source": "%lld steps", + "arguments": [ + 1 + ] + }, + "home.turn.moreSteps": { + "source": "%lld more steps", + "arguments": [ + 1 + ] } }