Standardize language codes and improve locale handling (#4353)

Use standard BCP 47 language codes
Move Culture utils into WinFormsUtil
Detect system language on first launch
This commit is contained in:
abcboy101 2024-09-04 19:51:35 -04:00 committed by GitHub
parent 42c1dee4e1
commit 3707ee5eb1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
269 changed files with 119 additions and 63 deletions

View file

@ -323,7 +323,7 @@ public sealed class ShowdownSet : IBattleTemplate
/// <summary> /// <summary>
/// Gets the localized Text representation of the set details. /// Gets the localized Text representation of the set details.
/// </summary> /// </summary>
/// <param name="lang">2 character language code</param> /// <param name="lang">Language code</param>
public string LocalizedText(string lang = DefaultLanguage) => LocalizedText(GameLanguage.GetLanguageIndex(lang)); public string LocalizedText(string lang = DefaultLanguage) => LocalizedText(GameLanguage.GetLanguageIndex(lang));
/// <summary> /// <summary>

View file

@ -22,7 +22,7 @@ public static class GameInfo
public static GameStrings GetStrings(int index) public static GameStrings GetStrings(int index)
{ {
return Languages[index] ??= new GameStrings(GameLanguage.Language2Char(index)); return Languages[index] ??= new GameStrings(GameLanguage.LanguageCode(index));
} }
public static GameStrings Strings public static GameStrings Strings

View file

@ -10,14 +10,13 @@ public static class GameLanguage
{ {
public const string DefaultLanguage = "en"; // English public const string DefaultLanguage = "en"; // English
public static int DefaultLanguageIndex => Array.IndexOf(LanguageCodes, DefaultLanguage); public static int DefaultLanguageIndex => Array.IndexOf(LanguageCodes, DefaultLanguage);
public static string Language2Char(int lang) => (uint)lang >= LanguageCodes.Length ? DefaultLanguage : LanguageCodes[lang]; public static string LanguageCode(int lang) => (uint)lang >= LanguageCodes.Length ? DefaultLanguage : LanguageCodes[lang];
public static int LanguageCount => LanguageCodes.Length; public static int LanguageCount => LanguageCodes.Length;
/// <summary> /// <summary>
/// Gets the language from the requested 2-char <see cref="lang"/> code. /// Gets the language from the requested language code.
/// </summary> /// </summary>
/// <param name="lang">2 character language code</param> /// <param name="lang">Language code</param>
/// <returns>Index of the language code; if not a valid language code, returns the <see cref="DefaultLanguageIndex"/>.</returns> /// <returns>Index of the language code; if not a valid language code, returns the <see cref="DefaultLanguageIndex"/>.</returns>
public static int GetLanguageIndex(string lang) public static int GetLanguageIndex(string lang)
{ {
@ -25,11 +24,18 @@ public static class GameLanguage
return l < 0 ? DefaultLanguageIndex : l; return l < 0 ? DefaultLanguageIndex : l;
} }
/// <summary>
/// Checks whether the language code is supported.
/// </summary>
/// <param name="lang">Language code</param>
/// <returns>True if valid, False otherwise</returns>
public static bool IsLanguageValid(string lang) => Array.IndexOf(LanguageCodes, lang) != -1;
/// <summary> /// <summary>
/// Language codes supported for loading string resources /// Language codes supported for loading string resources
/// </summary> /// </summary>
/// <see cref="ProgramLanguage"/> /// <see cref="ProgramLanguage"/>
private static readonly string[] LanguageCodes = ["ja", "en", "fr", "it", "de", "es", "ko", "zh", "zh2"]; private static readonly string[] LanguageCodes = ["ja", "en", "fr", "it", "de", "es", "ko", "zh-Hans", "zh-Hant"];
/// <summary> /// <summary>
/// Pokétransporter location names, ordered per index of <see cref="LanguageCodes"/> /// Pokétransporter location names, ordered per index of <see cref="LanguageCodes"/>

View file

@ -715,7 +715,7 @@ public sealed class GameStrings : IBasicStrings
// in Generation 9, TM #'s are padded to 3 digits; format them appropriately here // in Generation 9, TM #'s are padded to 3 digits; format them appropriately here
var clone = (string[])itemlist.Clone(); var clone = (string[])itemlist.Clone();
var span = clone.AsSpan(); var span = clone.AsSpan();
var zero = lang is "ja" or "zh" or "zh2" ? "" : "0"; var zero = lang is "ja" or "zh-Hans" or "zh-Hant" ? "" : "0";
InsertZero(span[328..420], zero); // 01-92 InsertZero(span[328..420], zero); // 01-92
InsertZero(span[618..621], zero); // 93-95 InsertZero(span[618..621], zero); // 93-95
InsertZero(span[690..694], zero); // 96-99 InsertZero(span[690..694], zero); // 96-99

View file

@ -8,14 +8,14 @@ namespace PKHeX.Core;
public static class GeoLocation public static class GeoLocation
{ {
private static readonly string[]?[] CountryList = GetCountryList(); private static readonly string[]?[] CountryList = GetCountryList();
private static readonly string[] lang_geo = ["ja", "en", "fr", "de", "it", "es", "zh", "ko", "zh2"]; private static readonly string[] lang_geo = ["ja", "en", "fr", "de", "it", "es", "zh-Hans", "ko", "zh-Hant"];
private static readonly string[]?[]?[] RegionList = new string[CountryList.Length][][]; private static readonly string[]?[]?[] RegionList = new string[CountryList.Length][][];
/// <summary> /// <summary>
/// Returns the index of which the <see cref="language"/> is in the country/region list. /// Returns the index of which the <see cref="language"/> is in the country/region list.
/// </summary> /// </summary>
public static int GetLanguageIndex(string language) => Array.IndexOf(lang_geo, language); public static int GetLanguageIndex(string language) => Array.IndexOf(lang_geo, language);
private static int GetLanguageIndex(LanguageID language) => GetLanguageIndex(language.GetLanguage2CharName()); private static int GetLanguageIndex(LanguageID language) => GetLanguageIndex(language.GetLanguageCode());
private const string INVALID = nameof(INVALID); private const string INVALID = nameof(INVALID);

View file

@ -13,7 +13,7 @@ internal static class Encounters7SM
internal static readonly EncounterArea7[] SlotsMN = EncounterArea7.GetAreas(Get("mn", "sm"u8), MN); internal static readonly EncounterArea7[] SlotsMN = EncounterArea7.GetAreas(Get("mn", "sm"u8), MN);
private const string tradeSM = "tradesm"; private const string tradeSM = "tradesm";
private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeSM); private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeSM, "zh");
public static readonly EncounterStatic7[] StaticSM = // @ a\1\5\5 public static readonly EncounterStatic7[] StaticSM = // @ a\1\5\5
[ [

View file

@ -13,7 +13,7 @@ internal static class Encounters7USUM
internal static readonly EncounterArea7[] SlotsUM = EncounterArea7.GetAreas(Get("um", "uu"u8), UM); internal static readonly EncounterArea7[] SlotsUM = EncounterArea7.GetAreas(Get("um", "uu"u8), UM);
private const string tradeUSUM = "tradeusum"; private const string tradeUSUM = "tradeusum";
private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeUSUM); private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeUSUM, "zh");
public static readonly EncounterStatic7[] StaticUSUM = public static readonly EncounterStatic7[] StaticUSUM =
[ [

View file

@ -758,7 +758,7 @@ internal static class Encounters8
]; ];
private const string tradeSWSH = "tradeswsh"; private const string tradeSWSH = "tradeswsh";
private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeSWSH, "zh2"); private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeSWSH);
private static readonly string[] TradeOT_R1 = [string.Empty, "チホコ", "Regina", "Régiona", "Regionalia", "Regine", string.Empty, "Tatiana", "지민", "易蒂", "易蒂"]; private static readonly string[] TradeOT_R1 = [string.Empty, "チホコ", "Regina", "Régiona", "Regionalia", "Regine", string.Empty, "Tatiana", "지민", "易蒂", "易蒂"];
private static readonly IndividualValueSet TradeIVs = new(15, 15, 15, 15, 15, 15); private static readonly IndividualValueSet TradeIVs = new(15, 15, 15, 15, 15, 15);

View file

@ -93,7 +93,7 @@ internal static class Encounters8b
]; ];
private const string tradeBDSP = "tradebdsp"; private const string tradeBDSP = "tradebdsp";
private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeBDSP, "zh2"); private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeBDSP);
internal static readonly EncounterTrade8b[] TradeGift_BDSP = internal static readonly EncounterTrade8b[] TradeGift_BDSP =
[ [

View file

@ -152,7 +152,7 @@ internal static class Encounters9
]; ];
private const string tradeSV = "tradesv"; private const string tradeSV = "tradesv";
private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeSV, "zh2"); private static readonly string[][] TradeNames = Util.GetLanguageStrings10(tradeSV);
internal static readonly EncounterTrade9[] TradeGift_SV = internal static readonly EncounterTrade9[] TradeGift_SV =
[ [

View file

@ -63,11 +63,11 @@ public static class Language
}; };
/// <summary> /// <summary>
/// Gets the 2-character language name for the given <see cref="LanguageID"/>. /// Gets the language code for the given <see cref="LanguageID"/>.
/// </summary> /// </summary>
/// <param name="language">Language ID to get the 2-character name for.</param> /// <param name="language">Language ID to get the language code for.</param>
/// <returns>2-character language name.</returns> /// <returns>Language code.</returns>
public static string GetLanguage2CharName(this LanguageID language) => language switch public static string GetLanguageCode(this LanguageID language) => language switch
{ {
Japanese => "ja", Japanese => "ja",
French => "fr", French => "fr",
@ -75,8 +75,8 @@ public static class Language
German => "de", German => "de",
Spanish => "es", Spanish => "es",
Korean => "ko", Korean => "ko",
ChineseS => "zh", ChineseS => "zh-Hans",
ChineseT => "zh2", ChineseT => "zh-Hant",
_ => GameLanguage.DefaultLanguage, _ => GameLanguage.DefaultLanguage,
}; };

View file

@ -24,8 +24,8 @@ public static class SpeciesName
Util.GetSpeciesList("es"), // 6 (reserved for Gen3 KO?, unused) Util.GetSpeciesList("es"), // 6 (reserved for Gen3 KO?, unused)
Util.GetSpeciesList("es"), // 7 Util.GetSpeciesList("es"), // 7
Util.GetSpeciesList("ko"), // 8 Util.GetSpeciesList("ko"), // 8
Util.GetSpeciesList("zh"), // 9 Simplified Util.GetSpeciesList("zh-Hans"), // 9 Simplified
Util.GetSpeciesList("zh2"), // 10 Traditional Util.GetSpeciesList("zh-Hant"), // 10 Traditional
]; ];
/// <summary> /// <summary>
@ -221,7 +221,7 @@ public static class SpeciesName
/// For a Gen7 species name request, return the old species name (hardcoded... yay). /// For a Gen7 species name request, return the old species name (hardcoded... yay).
/// In an updated Gen8 game, the species nickname will automatically reset to the correct localization (on save/load ?), fixing existing entries. /// In an updated Gen8 game, the species nickname will automatically reset to the correct localization (on save/load ?), fixing existing entries.
/// We don't differentiate patch revisions, just generation; Gen8 will return the latest localization. /// We don't differentiate patch revisions, just generation; Gen8 will return the latest localization.
/// Gen8 did revise CHT species names, but only for Barraskewda, Urshifu, and Zarude. These species are new (Gen8); we can just use the latest. /// Gen8 did revise CHS species names, but only for Barraskewda, Urshifu, and Zarude. These species are new (Gen8); we can just use the latest.
/// </remarks> /// </remarks>
private static string GetSpeciesName7ZH(ushort species, int language) => species switch private static string GetSpeciesName7ZH(ushort species, int language) => species switch
{ {

Some files were not shown because too many files have changed in this diff Show more