diff --git a/ConsoleInteractive b/ConsoleInteractive index a9afc0df..ff6d2129 160000 --- a/ConsoleInteractive +++ b/ConsoleInteractive @@ -1 +1 @@ -Subproject commit a9afc0df4ce79450b76acedffa1b549449cf69cb +Subproject commit ff6d2129e9f1e0fc6c7032741bdc42a2f0fa263e diff --git a/MinecraftClient/ClassicConsoleBackend.cs b/MinecraftClient/ClassicConsoleBackend.cs index 099447b2..ac4912c9 100644 --- a/MinecraftClient/ClassicConsoleBackend.cs +++ b/MinecraftClient/ClassicConsoleBackend.cs @@ -1,6 +1,4 @@ using System; -using System.Text.RegularExpressions; -using static MinecraftClient.Settings.ConsoleConfigHealper.ConsoleConfig; namespace MinecraftClient { @@ -28,29 +26,11 @@ namespace MinecraftClient ConsoleInteractive.ConsoleWriter.WriteLine(text); } - private static readonly Regex HexColorRegex = new(@"§#([0-9a-fA-F]{6})", RegexOptions.Compiled); - public void WriteLineFormatted(string text) { - bool hasHex = text.Contains("§#"); - if (hasHex) - text = ResolveHexColors(text); ConsoleInteractive.ConsoleWriter.WriteLineFormatted(text); } - private static string ResolveHexColors(string text) - { - var mode = Settings.Config.Console.General.ConsoleColorMode; - return HexColorRegex.Replace(text, match => - { - ReadOnlySpan hex = match.Groups[1].ValueSpan; - byte r = Convert.ToByte(hex[..2].ToString(), 16); - byte g = Convert.ToByte(hex[2..4].ToString(), 16); - byte b = Convert.ToByte(hex[4..6].ToString(), 16); - return ColorHelper.GetColorEscapeCode(r, g, b, foreground: true, mode); - }); - } - public void BeginReadThread() { ConsoleInteractive.ConsoleReader.MessageReceived += ForwardMessage; diff --git a/MinecraftClient/ColorHelper.cs b/MinecraftClient/ColorHelper.cs index 54559d58..4c7880aa 100644 --- a/MinecraftClient/ColorHelper.cs +++ b/MinecraftClient/ColorHelper.cs @@ -1,4 +1,4 @@ -using System; +using System; using static MinecraftClient.Settings.ConsoleConfigHealper.ConsoleConfig; namespace MinecraftClient @@ -100,9 +100,9 @@ namespace MinecraftClient } } if (foreground) - return $"§{best_idx:X}"; + return $"§{best_idx:x}"; else - return $"§§{best_idx:X}"; + return $"§§{best_idx:x}"; } case ConsoleColorModeType.vt100_4bit: diff --git a/MinecraftClient/Program.cs b/MinecraftClient/Program.cs index ae706296..83297eda 100644 --- a/MinecraftClient/Program.cs +++ b/MinecraftClient/Program.cs @@ -202,6 +202,11 @@ namespace MinecraftClient { ConsoleIO.Backend = new ClassicConsoleBackend(); ConsoleIO.Backend.Init(); + + // Config deserialization triggers OnSettingUpdate before the backend + // exists, so console-specific settings (UseVT100ColorCode, colors, etc.) + // are never applied. Re-apply them now that the backend is ready. + Config.Console.OnSettingUpdate(); } if (!ProcessStartupState(startupState)) @@ -240,6 +245,7 @@ namespace MinecraftClient ConsoleIO.Backend = new ClassicConsoleBackend(); ConsoleIO.Backend.Init(); + Config.Console.OnSettingUpdate(); ConsoleIO.WriteLineFormatted("§c" + Translations.mcc_tui_startup_failed); ConsoleIO.WriteLine(exception.ToString()); diff --git a/tools/translate_crowdin.py b/tools/translate_crowdin.py index 39c76679..976a36ef 100644 --- a/tools/translate_crowdin.py +++ b/tools/translate_crowdin.py @@ -141,9 +141,17 @@ class TransUnit: # XLIFF parsing # --------------------------------------------------------------------------- -def parse_xliff(path: Path, *, exclude_paths: list[str] | None = None) -> list[TransUnit]: +def parse_xliff( + path: Path, *, + exclude_paths: list[str] | None = None, + include_paths: list[str] | None = None, +) -> list[TransUnit]: """Parse an XLIFF 1.2 file, return trans-units with state=needs-translation. + include_paths: if set, only keep elements whose ``original`` + starts with (or equals) one of these prefixes. Takes priority over + exclude_paths. + exclude_paths: skip elements whose ``original`` starts with any of these prefixes (e.g. ``["/docs/"]``). """ @@ -153,7 +161,12 @@ def parse_xliff(path: Path, *, exclude_paths: list[str] | None = None) -> list[T for file_elem in root.findall(f"{{{XLIFF_NS}}}file"): original = file_elem.get("original", "") - if exclude_paths and any(original.startswith(p) for p in exclude_paths): + if include_paths: + if not any(original == p or original.startswith(p.rstrip("/") + "/") + or original == p.rstrip("/") + for p in include_paths): + continue + elif exclude_paths and any(original.startswith(p) for p in exclude_paths): continue finfo = FileInfo( file_id=file_elem.get("id", ""), @@ -695,6 +708,7 @@ def process_language( dry_run: bool, skip_upload: bool, exclude_paths: list[str] | None = None, + include_paths: list[str] | None = None, ) -> None: """Full pipeline for one language.""" lang_info = LANGUAGE_MAP.get(locale) @@ -706,7 +720,8 @@ def process_language( log.info("=" * 60) log.info("Processing %s -> %s", locale, target_lang) - units = parse_xliff(xliff_path, exclude_paths=exclude_paths) + units = parse_xliff(xliff_path, exclude_paths=exclude_paths, + include_paths=include_paths) log.info(" Found %d needs-translation entries", len(units)) if not units: @@ -878,6 +893,10 @@ def build_parser() -> argparse.ArgumentParser: help="Output directory (default: /translated/)") p.add_argument("--include-docs", action="store_true", help="Include /docs/ files in translation (skipped by default)") + p.add_argument("-f", "--files", type=str, default=None, + help="Comma-separated file paths to translate (e.g. " + "/docs/guide/README.md,/MinecraftClient/Resources/Translations/Translations.resx). " + "Overrides --include-docs") p.add_argument("-v", "--verbose", action="store_true", help="Enable debug logging") return p @@ -933,9 +952,15 @@ def main() -> None: output_dir.mkdir(parents=True, exist_ok=True) log.info("Output directory: %s", output_dir) - exclude_paths: list[str] | None = None if args.include_docs else ["/docs/"] - if exclude_paths: - log.info("Excluding XLIFF files under: %s (use --include-docs to include)", + include_paths: list[str] | None = None + if args.files: + include_paths = [f.strip() for f in args.files.split(",")] + log.info("Filtering to files: %s", ", ".join(include_paths)) + + exclude_paths: list[str] | None = None + if not include_paths and not args.include_docs: + exclude_paths = ["/docs/"] + log.info("Excluding XLIFF files under: %s (use --include-docs or --files to include)", ", ".join(exclude_paths)) xliff_files = find_xliff_files(bundle_dir, locales) @@ -959,6 +984,7 @@ def main() -> None: dry_run=args.dry_run, skip_upload=args.skip_upload, exclude_paths=exclude_paths, + include_paths=include_paths, ) except KeyboardInterrupt: log.warning("Interrupted by user. Partial results have been saved.")