From f0423610af0fe74673a3db7ec9a346bd96d01a84 Mon Sep 17 00:00:00 2001 From: Kurt Date: Fri, 22 Aug 2025 16:28:03 -0500 Subject: [PATCH] Add localization for ShowdownSet parse fail popup --- .../Errors/BattleTemplateParseError.cs | 8 ++ .../BattleTemplateParseErrorLocalization.cs | 55 ++++++++ .../Errors/BattleTemplateParseErrorType.cs | 75 +++++++++++ .../BattleTemplate/Showdown/ShowdownSet.cs | 126 +++++++++++------- PKHeX.Core/Legality/Tables/SpeciesCategory.cs | 16 +++ .../localize/battle/setparse_de.json | 23 ++++ .../localize/battle/setparse_en.json | 23 ++++ .../localize/battle/setparse_es.json | 23 ++++ .../localize/battle/setparse_fr.json | 23 ++++ .../localize/battle/setparse_it.json | 23 ++++ .../localize/battle/setparse_ja.json | 23 ++++ .../localize/battle/setparse_ko.json | 23 ++++ .../localize/battle/setparse_zh-hans.json | 23 ++++ .../localize/battle/setparse_zh-hant.json | 23 ++++ PKHeX.WinForms/MainWindow/Main.cs | 12 +- 15 files changed, 446 insertions(+), 53 deletions(-) create mode 100644 PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseError.cs create mode 100644 PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseErrorLocalization.cs create mode 100644 PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseErrorType.cs create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_de.json create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_en.json create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_es.json create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_fr.json create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_it.json create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_ja.json create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_ko.json create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_zh-hans.json create mode 100644 PKHeX.Core/Resources/localize/battle/setparse_zh-hant.json diff --git a/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseError.cs b/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseError.cs new file mode 100644 index 000000000..64cdce07a --- /dev/null +++ b/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseError.cs @@ -0,0 +1,8 @@ +using System; + +namespace PKHeX.Core; + +public readonly record struct BattleTemplateParseError(BattleTemplateParseErrorType Type, string Value) +{ + public string Humanize(BattleTemplateParseErrorLocalization localization) => Type.Humanize(localization, Value); +} diff --git a/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseErrorLocalization.cs b/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseErrorLocalization.cs new file mode 100644 index 000000000..912645187 --- /dev/null +++ b/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseErrorLocalization.cs @@ -0,0 +1,55 @@ +using System.Text.Json.Serialization; + +namespace PKHeX.Core; + +/// +/// Localized strings for values. +/// Each enum member maps 1:1 to a property for JSON (de)serialization. +/// +public sealed class BattleTemplateParseErrorLocalization +{ + private static readonly BattleTemplateParseErrorLocalizationContext Context = new(LocalizationStorage.Options); + public static readonly LocalizationStorage Cache = new("setparse", Context.BattleTemplateParseErrorLocalization); + public static BattleTemplateParseErrorLocalization Get(string language = GameLanguage.DefaultLanguage) => Cache.Get(language); + public static BattleTemplateParseErrorLocalization Get(LanguageID language) => Cache.Get(language.GetLanguageCode()); + + // General / structural + public required string LineLength { get; init; } = "Line exceeded the maximum supported length: {0}"; + + // Token issues + public required string TokenUnknown { get; init; } = "Unrecognized: {0}"; + public required string TokenFailParse { get; init; } = "Token could not be parsed: {0}"; + + // Move issues + public required string MoveCountTooMany { get; init; } = "Too many moves specified: {0}"; + public required string MoveSlotAlreadyUsed { get; init; } = "Move slot already used: {0}"; + public required string MoveDuplicate { get; init; } = "Duplicate move specified: {0}"; + public required string MoveUnrecognized { get; init; } = "Move not recognized: {0}"; + + // Item + public required string ItemUnrecognized { get; init; } = "Held item not recognized: {0}"; + + // Ability + public required string AbilityDeclaration { get; init; } = "Ability already declared: {0}"; + public required string AbilityUnrecognized { get; init; } = "Ability not recognized: {0}"; + public required string AbilityAlreadySpecified { get; init; } = "Ability already specified: {0}"; + + // Nature + public required string NatureUnrecognized { get; init; } = "Nature not recognized: {0}"; + public required string NatureAlreadySpecified { get; init; } = "Nature already specified: {0}"; + + // Hidden Power + public required string HiddenPowerUnknownType { get; init; } = "Hidden Power type not recognized: {0}"; + public required string HiddenPowerIncompatibleIVs { get; init; } = "Hidden Power type incompatible with IVs: {0}"; + + // EffortValue Nature Amp (Stat modifiers with + / - ) + public required string NatureEffortAmpDeclaration { get; init; } = "Nature / effort amp already declared: {0}"; + public required string NatureEffortAmpUnknown { get; init; } = "Unknown nature effort amp token: {0}"; + public required string NatureEffortAmpAlreadySpecified { get; init; } = "Nature effort amp already specified: {0}"; + public required string NatureEffortAmpConflictNature { get; init; } = "Declared effort amp conflicts with previously specified nature."; + public required string NatureAmpNoPlus { get; init; } = "Missing '+' nature amp token."; + public required string NatureAmpNoMinus { get; init; } = "Missing '-' nature amp token."; +} + +[JsonSerializable(typeof(BattleTemplateParseErrorLocalization))] +public sealed partial class BattleTemplateParseErrorLocalizationContext : JsonSerializerContext; diff --git a/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseErrorType.cs b/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseErrorType.cs new file mode 100644 index 000000000..a2072f424 --- /dev/null +++ b/PKHeX.Core/Editing/BattleTemplate/Errors/BattleTemplateParseErrorType.cs @@ -0,0 +1,75 @@ +using System; +using static PKHeX.Core.BattleTemplateParseErrorType; + +namespace PKHeX.Core; + +public enum BattleTemplateParseErrorType : byte +{ + None = 0, + LineLength, + TokenUnknown, + TokenFailParse, + MoveCountTooMany, + MoveSlotAlreadyUsed, + MoveDuplicate, + MoveUnrecognized, + + ItemUnrecognized, + AbilityDeclaration, + AbilityUnrecognized, + AbilityAlreadySpecified, + NatureUnrecognized, + NatureAlreadySpecified, + + HiddenPowerUnknownType, + HiddenPowerIncompatibleIVs, + + NatureEffortAmpDeclaration, + NatureEffortAmpUnknown, + NatureEffortAmpAlreadySpecified, + NatureEffortAmpConflictNature, + NatureAmpNoPlus, + NatureAmpNoMinus, +} + +public static class BattleTemplateParseErrorExtensions +{ + /// + /// Returns the localized string for the provided . + /// Falls back to the enum name if no mapping exists. + /// + public static string Humanize(this BattleTemplateParseErrorType type, BattleTemplateParseErrorLocalization localization, string value) + { + var template = GetTemplate(type, localization); + if (value.Length == 0) + return template; + return string.Format(template, value); + } + + private static string GetTemplate(BattleTemplateParseErrorType type, BattleTemplateParseErrorLocalization localization) => type switch + { + None => "", + LineLength => localization.LineLength, + TokenUnknown => localization.TokenUnknown, + TokenFailParse => localization.TokenFailParse, + MoveCountTooMany => localization.MoveCountTooMany, + MoveSlotAlreadyUsed => localization.MoveSlotAlreadyUsed, + MoveDuplicate => localization.MoveDuplicate, + MoveUnrecognized => localization.MoveUnrecognized, + ItemUnrecognized => localization.ItemUnrecognized, + AbilityDeclaration => localization.AbilityDeclaration, + AbilityUnrecognized => localization.AbilityUnrecognized, + AbilityAlreadySpecified => localization.AbilityAlreadySpecified, + NatureUnrecognized => localization.NatureUnrecognized, + NatureAlreadySpecified => localization.NatureAlreadySpecified, + HiddenPowerUnknownType => localization.HiddenPowerUnknownType, + HiddenPowerIncompatibleIVs => localization.HiddenPowerIncompatibleIVs, + NatureEffortAmpDeclaration => localization.NatureEffortAmpDeclaration, + NatureEffortAmpUnknown => localization.NatureEffortAmpUnknown, + NatureEffortAmpAlreadySpecified => localization.NatureEffortAmpAlreadySpecified, + NatureEffortAmpConflictNature => localization.NatureEffortAmpConflictNature, + NatureAmpNoPlus => localization.NatureAmpNoPlus, + NatureAmpNoMinus => localization.NatureAmpNoMinus, + _ => throw new ArgumentOutOfRangeException(nameof(type), type, null), + }; +} diff --git a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs index 0f4b9e3c2..da8b33f84 100644 --- a/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs +++ b/PKHeX.Core/Editing/BattleTemplate/Showdown/ShowdownSet.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Text; using static PKHeX.Core.Species; +using static PKHeX.Core.BattleTemplateParseErrorType; namespace PKHeX.Core; @@ -47,7 +48,10 @@ public sealed class ShowdownSet : IBattleTemplate /// /// Any lines that failed to be parsed. /// - public readonly List InvalidLines = new(0); + public readonly List InvalidLines = new(0); + + private void LogError(BattleTemplateParseErrorType type, ReadOnlySpan text = default) + => InvalidLines.Add(new(type, text.ToString())); /// /// Loads a new from the input string. @@ -137,7 +141,7 @@ private void ParseLines(SpanLineEnumerator lines, BattleTemplateLocalization loc first = false; continue; } - InvalidLines.Add(line.ToString()); + LogError(LineLength, line); continue; } @@ -168,7 +172,7 @@ private void ParseLines(IEnumerable lines, BattleTemplateLocalization lo first = false; continue; } - InvalidLines.Add(line); + LogError(LineLength, line); continue; } @@ -183,64 +187,84 @@ private void ParseLines(IEnumerable lines, BattleTemplateLocalization lo } } - private void ParseLine(ReadOnlySpan line, ref int movectr, BattleTemplateLocalization localization) + private void ParseLine(ReadOnlySpan line, ref int countMoves, BattleTemplateLocalization localization) { - var moves = Moves.AsSpan(); + // Check the first char, to see if it is a move input. var firstChar = line[0]; if (firstChar is '-' or '–') { - if (movectr >= MaxMoveCount) - { - InvalidLines.Add($"Too many moves: {line}"); - return; - } - var moveString = ParseLineMove(line, localization.Strings); - int move = StringUtil.FindIndexIgnoreCase(localization.Strings.movelist, moveString); - if (move < 0) - InvalidLines.Add($"Unknown Move: {moveString}"); - else if (moves.Contains((ushort)move)) - InvalidLines.Add($"Duplicate Move: {moveString}"); - else - moves[movectr++] = (ushort)move; + ParseMoveLine(line, ref countMoves, localization); return; } + // Check if it is a directional move input. var dirMove = BattleTemplateConfig.GetMoveDisplay(MoveDisplayStyle.Directional); var dirMoveIndex = dirMove.IndexOf(firstChar); if (dirMoveIndex != -1) { - if (moves[dirMoveIndex] != 0) - { - InvalidLines.Add($"Move slot already specified: {line}"); - return; - } - var moveString = ParseLineMove(line, localization.Strings); - int move = StringUtil.FindIndexIgnoreCase(localization.Strings.movelist, moveString); - if (move < 0) - InvalidLines.Add($"Unknown Move: {moveString}"); - else if (moves.Contains((ushort)move)) - InvalidLines.Add($"Duplicate Move: {moveString}"); - else - moves[dirMoveIndex] = (ushort)move; - movectr++; + ParseMoveLineIndex(line, ref countMoves, localization, dirMoveIndex); return; } - if (firstChar is '[' or '@') // Ability + // Check if it is an Ability selection/line + if (firstChar is '[' or '@') { ParseLineAbilityBracket(line, localization.Strings); return; } + // Otherwise, tokenized input line. var token = localization.Config.TryParse(line, out var value); if (token == BattleTemplateToken.None) { - InvalidLines.Add($"Unknown Token: {line}"); + LogError(TokenUnknown, line); return; } var valid = ParseEntry(token, value, localization); if (!valid) - InvalidLines.Add(line.ToString()); + LogError(TokenFailParse, line); + } + + private void ParseMoveLine(ReadOnlySpan line, ref int countMoves, BattleTemplateLocalization localization) + { + if (countMoves >= MaxMoveCount) + { + LogError(MoveCountTooMany, line); + return; + } + TryAddMoveAtIndex(line, ref countMoves, localization, countMoves); + } + + private void ParseMoveLineIndex(ReadOnlySpan line, ref int countMoves, BattleTemplateLocalization localization, int index) + { + if (Moves[index] != 0) + { + LogError(MoveSlotAlreadyUsed, line); + return; + } + TryAddMoveAtIndex(line, ref countMoves, localization, index); + } + + private void TryAddMoveAtIndex(ReadOnlySpan line, ref int countMoves, BattleTemplateLocalization localization, int index) + { + var strings = localization.Strings; + var movelist = strings.movelist; + var moveString = ParseLineMove(line, strings); + int move = StringUtil.FindIndexIgnoreCase(movelist, moveString); + var moves = Moves.AsSpan(); + if (move < 0) + { + LogError(MoveUnrecognized, moveString); + } + else if (moves.Contains((ushort)move)) + { + LogError(MoveDuplicate, moveString); + } + else + { + moves[index] = (ushort)move; + countMoves++; + } } private void ParseLineAbilityBracket(ReadOnlySpan line, GameStrings localizationStrings) @@ -251,7 +275,7 @@ private void ParseLineAbilityBracket(ReadOnlySpan line, GameStrings locali { var itemName = line[(itemStart + 1)..].TrimStart(); if (!ParseItemName(itemName, localizationStrings)) - InvalidLines.Add($"Unknown Item: {itemName}"); + LogError(ItemUnrecognized, itemName); line = line[..itemStart]; } @@ -259,7 +283,7 @@ private void ParseLineAbilityBracket(ReadOnlySpan line, GameStrings locali var abilityEnd = line.IndexOf(']'); if (abilityEnd == -1 || line.Length == 1) // '[' should be present if ']' is; length check. { - InvalidLines.Add($"Invalid Ability declaration: {line}"); + LogError(AbilityDeclaration, line); return; // invalid line } @@ -267,7 +291,7 @@ private void ParseLineAbilityBracket(ReadOnlySpan line, GameStrings locali var abilityIndex = StringUtil.FindIndexIgnoreCase(localizationStrings.abilitylist, abilityName); if (abilityIndex < 0) { - InvalidLines.Add($"Unknown Ability: {abilityName}"); + LogError(AbilityUnrecognized, abilityName); return; // invalid line } Ability = abilityIndex; @@ -296,12 +320,12 @@ private bool ParseLineAbility(ReadOnlySpan value, ReadOnlySpan abi var index = StringUtil.FindIndexIgnoreCase(abilityNames, value); if (index < 0) { - InvalidLines.Add($"Unknown Ability: {value}"); + LogError(AbilityUnrecognized, value); return false; } if (Ability != -1 && Ability != index) { - InvalidLines.Add($"Different ability already specified: {value}"); + LogError(AbilityAlreadySpecified, value); return false; } @@ -318,12 +342,12 @@ private bool ParseLineNature(ReadOnlySpan value, ReadOnlySpan natu var nature = (Nature)index; if (!nature.IsFixed()) { - InvalidLines.Add($"Invalid Nature: {value}"); + LogError(NatureUnrecognized, value); return false; } if (Nature != Nature.Random && Nature != nature) { - InvalidLines.Add($"Different nature already specified: {value}"); + LogError(NatureAlreadySpecified, value); return false; } @@ -816,7 +840,7 @@ private void ParseFirstLine(ReadOnlySpan first, GameStrings strings) var speciesName = first[..itemSplit].TrimEnd(); if (!ParseItemName(itemName, strings)) - InvalidLines.Add($"Unknown Item: {itemName}"); + LogError(ItemUnrecognized, itemName); ParseFirstLineNoItem(speciesName, strings); } else @@ -1004,7 +1028,7 @@ private ReadOnlySpan ParseLineMove(ReadOnlySpan line, GameStrings st if (IVs.AsSpan().ContainsAnyExcept(maxIV)) { if (!HiddenPower.SetIVsForType(hpVal, IVs, Context)) - InvalidLines.Add($"Invalid IVs for Hidden Power Type: {type}"); + LogError(HiddenPowerIncompatibleIVs, type); } else if (hpVal >= 0) { @@ -1012,7 +1036,7 @@ private ReadOnlySpan ParseLineMove(ReadOnlySpan line, GameStrings st } else { - InvalidLines.Add($"Invalid Hidden Power Type: {type}"); + LogError(HiddenPowerUnknownType, type); } return hiddenPowerName; } @@ -1042,19 +1066,19 @@ private bool ParseLineEVs(ReadOnlySpan line, BattleTemplateLocalization lo var end = natureName.IndexOf(')'); if (end == -1) { - InvalidLines.Add($"Invalid EV nature: {natureName}"); + LogError(NatureEffortAmpDeclaration, natureName); return false; // invalid line } natureName = natureName[..end].Trim(); var natureIndex = StringUtil.FindIndexIgnoreCase(localization.Strings.natures, natureName); if (natureIndex == -1) { - InvalidLines.Add($"Invalid EV nature: {natureName}"); + LogError(NatureEffortAmpUnknown, natureName); return false; // invalid line } if (Nature != Nature.Random) // specified in a separate Nature line - InvalidLines.Add($"EV nature ignored, specified previously: {natureName}"); + LogError(NatureEffortAmpAlreadySpecified, natureName); else Nature = (Nature)natureIndex; @@ -1074,7 +1098,7 @@ private bool ParseLineEVs(ReadOnlySpan line, BattleTemplateLocalization lo success &= ampNature; if (ampNature && currentNature != Nature.Random && currentNature != Nature) { - InvalidLines.Add($"EV +/- nature does not match specified nature: {currentNature}"); + LogError(NatureEffortAmpConflictNature); Nature = currentNature; // revert to original } return success; @@ -1090,9 +1114,9 @@ private bool ParseLineIVs(ReadOnlySpan line, BattleTemplateConfig config) private bool AdjustNature(sbyte plus, sbyte minus) { if (plus == StatParseResult.NoStatAmp) - InvalidLines.Add("Invalid Nature adjustment, missing plus stat."); + LogError(NatureAmpNoPlus); if (minus == StatParseResult.NoStatAmp) - InvalidLines.Add("Invalid Nature adjustment, missing minus stat."); + LogError(NatureAmpNoMinus); else Nature = NatureAmp.CreateNatureFromAmps(plus, minus); return true; diff --git a/PKHeX.Core/Legality/Tables/SpeciesCategory.cs b/PKHeX.Core/Legality/Tables/SpeciesCategory.cs index c685e5ca5..11485337e 100644 --- a/PKHeX.Core/Legality/Tables/SpeciesCategory.cs +++ b/PKHeX.Core/Legality/Tables/SpeciesCategory.cs @@ -70,6 +70,9 @@ public static bool IsParadox(ushort species) => species is (>= (int)GreatTusk an or (int)WalkingWake or (int)IronLeaves or (int)GougingFire or (int)RagingBolt or (int)IronBoulder or (int)IronCrown; + /// + /// Checks if the is a species that evolved from a bi-gendered species into a single-gendered species/form. + /// public static bool IsFixedGenderFromDual(ushort currentSpecies) => currentSpecies switch { (int)Shedinja => true, // Genderless @@ -84,7 +87,20 @@ public static bool IsParadox(ushort species) => species is (>= (int)GreatTusk an (int)Meowstic => true, // (M/F) form specific (int)Salazzle => true, // (F) (int)Oinkologne => true, // (M/F) form specific + (int)Basculegion => true, // (M/F) form specific _ => false, }; + + /// + /// Checks if the is a species that has each gender as a different form. + /// + public static bool IsFormGenderSpecific(ushort currentSpecies) => currentSpecies switch + { + (int)Meowstic => true, + (int)Indeedee => true, + (int)Basculegion => true, + (int)Oinkologne => true, + _ => false, + }; } diff --git a/PKHeX.Core/Resources/localize/battle/setparse_de.json b/PKHeX.Core/Resources/localize/battle/setparse_de.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_de.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.Core/Resources/localize/battle/setparse_en.json b/PKHeX.Core/Resources/localize/battle/setparse_en.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_en.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.Core/Resources/localize/battle/setparse_es.json b/PKHeX.Core/Resources/localize/battle/setparse_es.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_es.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.Core/Resources/localize/battle/setparse_fr.json b/PKHeX.Core/Resources/localize/battle/setparse_fr.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_fr.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.Core/Resources/localize/battle/setparse_it.json b/PKHeX.Core/Resources/localize/battle/setparse_it.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_it.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.Core/Resources/localize/battle/setparse_ja.json b/PKHeX.Core/Resources/localize/battle/setparse_ja.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_ja.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.Core/Resources/localize/battle/setparse_ko.json b/PKHeX.Core/Resources/localize/battle/setparse_ko.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_ko.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.Core/Resources/localize/battle/setparse_zh-hans.json b/PKHeX.Core/Resources/localize/battle/setparse_zh-hans.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_zh-hans.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.Core/Resources/localize/battle/setparse_zh-hant.json b/PKHeX.Core/Resources/localize/battle/setparse_zh-hant.json new file mode 100644 index 000000000..b5779a489 --- /dev/null +++ b/PKHeX.Core/Resources/localize/battle/setparse_zh-hant.json @@ -0,0 +1,23 @@ +{ + "LineLength": "Line exceeded the maximum supported length: {0}", + "TokenUnknown": "Unrecognized: {0}", + "TokenFailParse": "Parse Failure: {0}", + "MoveCountTooMany": "Too many moves specified: {0}", + "MoveSlotAlreadyUsed": "Move slot already used: {0}", + "MoveDuplicate": "Duplicate move specified: {0}", + "MoveUnrecognized": "Move not recognized: {0}", + "ItemUnrecognized": "Held item not recognized: {0}", + "AbilityDeclaration": "Ability already declared: {0}", + "AbilityUnrecognized": "Ability not recognized: {0}", + "AbilityAlreadySpecified": "Ability already specified: {0}", + "NatureUnrecognized": "Nature not recognized: {0}", + "NatureAlreadySpecified": "Nature already specified: {0}", + "HiddenPowerUnknownType": "Hidden Power type not recognized: {0}", + "HiddenPowerIncompatibleIVs": "Hidden Power type incompatible with IVs: {0}", + "NatureEffortAmpDeclaration": "Nature / effort amp already declared: {0}", + "NatureEffortAmpUnknown": "Unknown nature effort amp: {0}", + "NatureEffortAmpAlreadySpecified": "Nature effort amp already specified: {0}", + "NatureEffortAmpConflictNature": "Declared effort amp conflicts with previously specified nature.", + "NatureAmpNoPlus": "Missing '+' nature amp.", + "NatureAmpNoMinus": "Missing '-' nature amp." +} diff --git a/PKHeX.WinForms/MainWindow/Main.cs b/PKHeX.WinForms/MainWindow/Main.cs index 54cf07ece..d46ea4def 100644 --- a/PKHeX.WinForms/MainWindow/Main.cs +++ b/PKHeX.WinForms/MainWindow/Main.cs @@ -439,8 +439,16 @@ private void ClickShowdownImportPKM(object? sender, EventArgs e) var invalid = set.InvalidLines; if (invalid.Count != 0) - WinFormsUtil.Alert(MsgSimulatorInvalid, string.Join(Environment.NewLine, invalid)); - + { + var localization = BattleTemplateParseErrorLocalization.Get(CurrentLanguage); + var sb = new System.Text.StringBuilder(); + foreach (var line in invalid) + { + var error = line.Humanize(localization); + sb.AppendLine(error); + } + WinFormsUtil.Alert(MsgSimulatorInvalid, sb.ToString()); + } PKME_Tabs.LoadShowdownSet(set); }