diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp
index 5b263e45e6..7979038790 100644
--- a/Source/Core/Core/Boot/Boot.cpp
+++ b/Source/Core/Core/Boot/Boot.cpp
@@ -419,7 +419,7 @@ bool CBoot::BootUp()
 
     // Poor man's bootup
     if (_StartupPara.bWii)
-      SetupWiiMemory(DiscIO::Country::COUNTRY_UNKNOWN);
+      SetupWiiMemory(DiscIO::Region::UNKNOWN_REGION);
     else
       EmulatedBS2_GC(true);
 
diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h
index 5299d260da..aa952d1199 100644
--- a/Source/Core/Core/Boot/Boot.h
+++ b/Source/Core/Core/Boot/Boot.h
@@ -9,10 +9,10 @@
 
 namespace DiscIO
 {
-enum class Country;
+enum class Region;
 }
 
-struct CountrySetting
+struct RegionSetting
 {
   const std::string area;
   const std::string video;
@@ -57,5 +57,5 @@ private:
   static bool Load_BS2(const std::string& _rBootROMFilename);
   static void Load_FST(bool _bIsWii);
 
-  static bool SetupWiiMemory(DiscIO::Country country);
+  static bool SetupWiiMemory(DiscIO::Region region);
 };
diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp
index 817c5d4bcc..5b44b297b4 100644
--- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp
+++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp
@@ -181,28 +181,22 @@ bool CBoot::EmulatedBS2_GC(bool skipAppLoader)
   return true;
 }
 
-bool CBoot::SetupWiiMemory(DiscIO::Country country)
+bool CBoot::SetupWiiMemory(DiscIO::Region region)
 {
-  static const CountrySetting SETTING_EUROPE = {"EUR", "PAL", "EU", "LE"};
-  static const CountrySetting SETTING_USA = {"USA", "NTSC", "US", "LU"};
-  static const CountrySetting SETTING_JAPAN = {"JPN", "NTSC", "JP", "LJ"};
-  static const CountrySetting SETTING_KOREA = {"KOR", "NTSC", "KR", "LKH"};
-  static const std::map<DiscIO::Country, const CountrySetting> country_settings = {
-      {DiscIO::Country::COUNTRY_EUROPE, SETTING_EUROPE},
-      {DiscIO::Country::COUNTRY_USA, SETTING_USA},
-      {DiscIO::Country::COUNTRY_JAPAN, SETTING_JAPAN},
-      {DiscIO::Country::COUNTRY_KOREA, SETTING_KOREA},
-      // TODO: Determine if Taiwan have their own specific settings.
-      //      Also determine if there are other specific settings
-      //      for other countries.
-      {DiscIO::Country::COUNTRY_TAIWAN, SETTING_JAPAN}};
-  auto entryPos = country_settings.find(country);
-  const CountrySetting& country_setting =
-      (entryPos != country_settings.end()) ?
+  static const RegionSetting SETTING_NTSC_J = {"JPN", "NTSC", "JP", "LJ"};
+  static const RegionSetting SETTING_NTSC_U = {"USA", "NTSC", "US", "LU"};
+  static const RegionSetting SETTING_PAL = {"EUR", "PAL", "EU", "LE"};
+  static const RegionSetting SETTING_NTSC_K = {"KOR", "NTSC", "KR", "LKH"};
+  static const std::map<DiscIO::Region, const RegionSetting> region_settings = {
+      {DiscIO::Region::NTSC_J, SETTING_NTSC_J},
+      {DiscIO::Region::NTSC_U, SETTING_NTSC_U},
+      {DiscIO::Region::PAL, SETTING_PAL},
+      {DiscIO::Region::NTSC_K, SETTING_NTSC_K}};
+  auto entryPos = region_settings.find(region);
+  const RegionSetting& region_setting =
+      (entryPos != region_settings.end()) ?
           entryPos->second :
-          (SConfig::GetInstance().bNTSC ?
-               SETTING_USA :
-               SETTING_EUROPE);  // default to USA or EUR depending on game's video mode
+          (SConfig::GetInstance().bNTSC ? SETTING_NTSC_U : SETTING_PAL);
 
   SettingsHandler gen;
   std::string serno;
@@ -233,15 +227,15 @@ bool CBoot::SetupWiiMemory(DiscIO::Country country)
     INFO_LOG(BOOT, "Using serial number: %s", serno.c_str());
   }
 
-  std::string model = "RVL-001(" + country_setting.area + ")";
-  gen.AddSetting("AREA", country_setting.area);
+  std::string model = "RVL-001(" + region_setting.area + ")";
+  gen.AddSetting("AREA", region_setting.area);
   gen.AddSetting("MODEL", model);
   gen.AddSetting("DVD", "0");
   gen.AddSetting("MPCH", "0x7FFE");
-  gen.AddSetting("CODE", country_setting.code);
+  gen.AddSetting("CODE", region_setting.code);
   gen.AddSetting("SERNO", serno);
-  gen.AddSetting("VIDEO", country_setting.video);
-  gen.AddSetting("GAME", country_setting.game);
+  gen.AddSetting("VIDEO", region_setting.video);
+  gen.AddSetting("GAME", region_setting.game);
 
   File::CreateFullPath(settings_Filename);
   {
@@ -336,10 +330,10 @@ bool CBoot::EmulatedBS2_Wii()
   INFO_LOG(BOOT, "Faking Wii BS2...");
 
   // Setup Wii memory
-  DiscIO::Country country_code = DiscIO::Country::COUNTRY_UNKNOWN;
+  DiscIO::Region region_code = DiscIO::Region::UNKNOWN_REGION;
   if (DVDInterface::VolumeIsValid())
-    country_code = DVDInterface::GetVolume().GetCountry();
-  if (SetupWiiMemory(country_code) == false)
+    region_code = DVDInterface::GetVolume().GetRegion();
+  if (SetupWiiMemory(region_code) == false)
     return false;
 
   // Execute the apploader
diff --git a/Source/Core/Core/Boot/Boot_WiiWAD.cpp b/Source/Core/Core/Boot/Boot_WiiWAD.cpp
index 3a54ee03ed..f7cc276f48 100644
--- a/Source/Core/Core/Boot/Boot_WiiWAD.cpp
+++ b/Source/Core/Core/Boot/Boot_WiiWAD.cpp
@@ -89,10 +89,10 @@ bool CBoot::Boot_WiiWAD(const std::string& _pFilename)
   if (titleID == TITLEID_SYSMENU)
     HLE_IPC_CreateVirtualFATFilesystem();
   // setup Wii memory
-  if (!SetupWiiMemory(ContentLoader.GetCountry()))
+  if (!SetupWiiMemory(ContentLoader.GetRegion()))
     return false;
   // this sets a bit that is used to detect NTSC-J
-  if (ContentLoader.GetCountry() == DiscIO::Country::COUNTRY_JAPAN)
+  if (ContentLoader.GetRegion() == DiscIO::Region::NTSC_J)
   {
     VideoInterface::SetRegionReg('J');
   }
diff --git a/Source/Core/Core/ConfigManager.cpp b/Source/Core/Core/ConfigManager.cpp
index 40b4019676..9b1545d123 100644
--- a/Source/Core/Core/ConfigManager.cpp
+++ b/Source/Core/Core/ConfigManager.cpp
@@ -794,31 +794,28 @@ void SConfig::LoadDefaults()
   m_revision = 0;
 }
 
-static const char* GetRegionOfCountry(DiscIO::Country country)
+static const char* GetDirectoryForRegion(DiscIO::Region region)
 {
-  switch (country)
+  switch (region)
   {
-  case DiscIO::Country::COUNTRY_USA:
-    return USA_DIR;
-
-  case DiscIO::Country::COUNTRY_TAIWAN:
-  case DiscIO::Country::COUNTRY_KOREA:
-  // TODO: Should these have their own Region Dir?
-  case DiscIO::Country::COUNTRY_JAPAN:
+  case DiscIO::Region::NTSC_J:
     return JAP_DIR;
 
-  case DiscIO::Country::COUNTRY_AUSTRALIA:
-  case DiscIO::Country::COUNTRY_EUROPE:
-  case DiscIO::Country::COUNTRY_FRANCE:
-  case DiscIO::Country::COUNTRY_GERMANY:
-  case DiscIO::Country::COUNTRY_ITALY:
-  case DiscIO::Country::COUNTRY_NETHERLANDS:
-  case DiscIO::Country::COUNTRY_RUSSIA:
-  case DiscIO::Country::COUNTRY_SPAIN:
-  case DiscIO::Country::COUNTRY_WORLD:
+  case DiscIO::Region::NTSC_U:
+    return USA_DIR;
+
+  case DiscIO::Region::PAL:
     return EUR_DIR;
 
-  case DiscIO::Country::COUNTRY_UNKNOWN:
+  case DiscIO::Region::NTSC_K:
+    // This function can't return a Korean directory name, because this
+    // function is only used for GameCube things (memory cards, IPL), and
+    // GameCube has no NTSC-K region. Since NTSC-K doesn't correspond to any
+    // GameCube region, let's return an arbitrary pick. Returning nullptr like
+    // with unknown regions would be inappropriate, because Dolphin expects
+    // to get valid memory card paths even when running an NTSC-K Wii game.
+    return JAP_DIR;
+
   default:
     return nullptr;
   }
@@ -870,17 +867,19 @@ bool SConfig::AutoSetup(EBootBS2 _BootBS2)
       // Check if we have a Wii disc
       bWii = pVolume->GetVolumeType() == DiscIO::Platform::WII_DISC;
 
-      const char* retrieved_region_dir = GetRegionOfCountry(pVolume->GetCountry());
+      DiscIO::Region region = pVolume->GetRegion();
+      const char* retrieved_region_dir = GetDirectoryForRegion(region);
       if (!retrieved_region_dir)
       {
         if (!PanicYesNoT("Your GCM/ISO file seems to be invalid (invalid country)."
                          "\nContinue with PAL region?"))
           return false;
+        region = DiscIO::Region::PAL;
         retrieved_region_dir = EUR_DIR;
       }
 
       set_region_dir = retrieved_region_dir;
-      bNTSC = set_region_dir == USA_DIR || set_region_dir == JAP_DIR;
+      bNTSC = region != DiscIO::Region::PAL;
     }
     else if (!strcasecmp(Extension.c_str(), ".elf"))
     {
@@ -932,7 +931,7 @@ bool SConfig::AutoSetup(EBootBS2 _BootBS2)
         return false;  // do not boot
       }
 
-      const char* retrieved_region_dir = GetRegionOfCountry(ContentLoader.GetCountry());
+      const char* retrieved_region_dir = GetDirectoryForRegion(ContentLoader.GetRegion());
       set_region_dir = retrieved_region_dir ? retrieved_region_dir : EUR_DIR;
       bNTSC = set_region_dir == USA_DIR || set_region_dir == JAP_DIR;
 
diff --git a/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp
index 5eb49b5c5e..47d9efeb18 100644
--- a/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp
+++ b/Source/Core/Core/HW/EXI_DeviceMemoryCard.cpp
@@ -152,7 +152,7 @@ CEXIMemoryCard::CEXIMemoryCard(const int index, bool gciFolder) : card_index(ind
 
 void CEXIMemoryCard::SetupGciFolder(u16 sizeMb)
 {
-  DiscIO::Country country_code = DiscIO::Country::COUNTRY_UNKNOWN;
+  DiscIO::Region region = DiscIO::Region::UNKNOWN_REGION;
   std::string game_id = SConfig::GetInstance().m_strGameID;
 
   u32 CurrentGameId = 0;
@@ -163,26 +163,28 @@ void CEXIMemoryCard::SetupGciFolder(u16 sizeMb)
                                                             Common::FROM_SESSION_ROOT);
     if (SysMenu_Loader.IsValid())
     {
-      country_code = DiscIO::CountrySwitch(SysMenu_Loader.GetCountryChar());
+      region = DiscIO::RegionSwitchGC(SysMenu_Loader.GetCountryChar());
     }
   }
   else if (game_id.length() >= 4)
   {
-    country_code = DiscIO::CountrySwitch(game_id.at(3));
+    region = DiscIO::RegionSwitchGC(game_id.at(3));
     CurrentGameId = BE32((u8*)game_id.c_str());
   }
   bool shift_jis = false;
   std::string strDirectoryName = File::GetUserPath(D_GCUSER_IDX);
-  switch (country_code)
+  switch (region)
   {
-  case DiscIO::Country::COUNTRY_JAPAN:
+  case DiscIO::Region::NTSC_J:
     shift_jis = true;
     strDirectoryName += JAP_DIR DIR_SEP;
     break;
-  case DiscIO::Country::COUNTRY_USA:
+  case DiscIO::Region::NTSC_U:
     strDirectoryName += USA_DIR DIR_SEP;
     break;
-  case DiscIO::Country::COUNTRY_UNKNOWN:
+  case DiscIO::Region::PAL:
+    strDirectoryName += EUR_DIR DIR_SEP;
+  default:
   {
     // The current game's region is not passed down to the EXI device level.
     // Usually, we can retrieve the region from SConfig::GetInstance().m_strUniqueId.
@@ -199,24 +201,25 @@ void CEXIMemoryCard::SetupGciFolder(u16 sizeMb)
 
     std::string memcardFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA :
                                                       SConfig::GetInstance().m_strMemoryCardB;
-    std::string region = memcardFilename.substr(memcardFilename.size() - 7, 3);
-    if (region == JAP_DIR)
+    std::string region_string = memcardFilename.substr(memcardFilename.size() - 7, 3);
+    if (region_string == JAP_DIR)
     {
-      country_code = DiscIO::Country::COUNTRY_JAPAN;
+      region = DiscIO::Region::NTSC_J;
       shift_jis = true;
       strDirectoryName += JAP_DIR DIR_SEP;
-      break;
     }
-    else if (region == USA_DIR)
+    else if (region_string == USA_DIR)
     {
-      country_code = DiscIO::Country::COUNTRY_USA;
+      region = DiscIO::Region::NTSC_U;
       strDirectoryName += USA_DIR DIR_SEP;
-      break;
     }
+    else
+    {
+      region = DiscIO::Region::PAL;
+      strDirectoryName += EUR_DIR DIR_SEP;
+    }
+    break;
   }
-  default:
-    country_code = DiscIO::Country::COUNTRY_EUROPE;
-    strDirectoryName += EUR_DIR DIR_SEP;
   }
   strDirectoryName += StringFromFormat("Card %c", 'A' + card_index);
 
@@ -243,7 +246,7 @@ void CEXIMemoryCard::SetupGciFolder(u16 sizeMb)
   }
 
   memorycard = std::make_unique<GCMemcardDirectory>(strDirectoryName + DIR_SEP, card_index, sizeMb,
-                                                    shift_jis, country_code, CurrentGameId);
+                                                    shift_jis, region, CurrentGameId);
 }
 
 void CEXIMemoryCard::SetupRawMemcard(u16 sizeMb)
diff --git a/Source/Core/Core/HW/GCMemcard.h b/Source/Core/Core/HW/GCMemcard.h
index 69f6c5c85e..f77ba05a68 100644
--- a/Source/Core/Core/HW/GCMemcard.h
+++ b/Source/Core/Core/HW/GCMemcard.h
@@ -103,7 +103,7 @@ struct Header  // Offset    Size    Description
   // end Serial in libogc
   u8 deviceID[2];     // 0x0020    2       0 if formated in slot A 1 if formated in slot B
   u8 SizeMb[2];       // 0x0022    2       Size of memcard in Mbits
-  u16 Encoding;       // 0x0024    2       Encoding (ASCII or Japanese)
+  u16 Encoding;       // 0x0024    2       Encoding (Windows-1252 or Shift JIS)
   u8 Unused1[468];    // 0x0026    468     Unused (0xff)
   u16 UpdateCounter;  // 0x01fa    2       Update Counter (?, probably unused)
   u16 Checksum;       // 0x01fc    2       Additive Checksum
diff --git a/Source/Core/Core/HW/GCMemcardDirectory.cpp b/Source/Core/Core/HW/GCMemcardDirectory.cpp
index 8ef39e8649..69d177f052 100644
--- a/Source/Core/Core/HW/GCMemcardDirectory.cpp
+++ b/Source/Core/Core/HW/GCMemcardDirectory.cpp
@@ -24,7 +24,7 @@
 const int NO_INDEX = -1;
 static const char* MC_HDR = "MC_SYSTEM_AREA";
 
-int GCMemcardDirectory::LoadGCI(const std::string& fileName, DiscIO::Country card_region,
+int GCMemcardDirectory::LoadGCI(const std::string& fileName, DiscIO::Region card_region,
                                 bool currentGameOnly)
 {
   File::IOFile gcifile(fileName, "rb");
@@ -39,27 +39,12 @@ int GCMemcardDirectory::LoadGCI(const std::string& fileName, DiscIO::Country car
       return NO_INDEX;
     }
 
-    DiscIO::Country gci_region;
-    // check region
-    switch (gci.m_gci_header.Gamecode[3])
-    {
-    case 'J':
-      gci_region = DiscIO::Country::COUNTRY_JAPAN;
-      break;
-    case 'E':
-      gci_region = DiscIO::Country::COUNTRY_USA;
-      break;
-    case 'C':
-      // Used by Datel Action Replay Save
-      // can be on any regions card
-      gci_region = card_region;
-      break;
-    default:
-      gci_region = DiscIO::Country::COUNTRY_EUROPE;
-      break;
-    }
-
-    if (gci_region != card_region)
+    DiscIO::Region gci_region = DiscIO::RegionSwitchGC(gci.m_gci_header.Gamecode[3]);
+    // Some special save files have game IDs that we parse as UNKNOWN_REGION. For instance:
+    // - Datel Action Replay uses C as the fourth character. (Can be on any region's card.)
+    // - Homeland's network config file only uses null bytes. (Homeland is exclusive to Japan,
+    //   but maybe the network config file ID was intended to be used in other regions too.)
+    if (card_region != gci_region && gci_region != DiscIO::Region::UNKNOWN_REGION)
     {
       PanicAlertT(
           "GCI save file was not loaded because it is the wrong region for this memory card:\n%s",
@@ -146,7 +131,7 @@ int GCMemcardDirectory::LoadGCI(const std::string& fileName, DiscIO::Country car
 }
 
 GCMemcardDirectory::GCMemcardDirectory(const std::string& directory, int slot, u16 sizeMb,
-                                       bool shift_jis, DiscIO::Country card_region, int gameId)
+                                       bool shift_jis, DiscIO::Region card_region, int gameId)
     : MemoryCardBase(slot, sizeMb), m_GameId(gameId), m_LastBlock(-1),
       m_hdr(slot, sizeMb, shift_jis), m_bat1(sizeMb), m_saves(0), m_SaveDirectory(directory),
       m_exiting(false)
diff --git a/Source/Core/Core/HW/GCMemcardDirectory.h b/Source/Core/Core/HW/GCMemcardDirectory.h
index a291c3e095..711dfda026 100644
--- a/Source/Core/Core/HW/GCMemcardDirectory.h
+++ b/Source/Core/Core/HW/GCMemcardDirectory.h
@@ -22,9 +22,8 @@ void MigrateFromMemcardFile(const std::string& strDirectoryName, int card_index)
 class GCMemcardDirectory : public MemoryCardBase, NonCopyable
 {
 public:
-  GCMemcardDirectory(const std::string& directory, int slot = 0, u16 sizeMb = MemCard2043Mb,
-                     bool shift_jis = false,
-                     DiscIO::Country card_region = DiscIO::Country::COUNTRY_EUROPE, int gameId = 0);
+  GCMemcardDirectory(const std::string& directory, int slot, u16 sizeMb, bool shift_jis,
+                     DiscIO::Region card_region, int gameId);
   ~GCMemcardDirectory();
   void FlushToFile();
   void FlushThread();
@@ -35,7 +34,7 @@ public:
   void DoState(PointerWrap& p) override;
 
 private:
-  int LoadGCI(const std::string& fileName, DiscIO::Country card_region, bool currentGameOnly);
+  int LoadGCI(const std::string& fileName, DiscIO::Region card_region, bool currentGameOnly);
   inline s32 SaveAreaRW(u32 block, bool writing = false);
   // s32 DirectoryRead(u32 offset, u32 length, u8* destaddress);
   s32 DirectoryWrite(u32 destaddress, u32 length, u8* srcaddress);
diff --git a/Source/Core/DiscIO/Enums.cpp b/Source/Core/DiscIO/Enums.cpp
index 385fff1317..6689470f32 100644
--- a/Source/Core/DiscIO/Enums.cpp
+++ b/Source/Core/DiscIO/Enums.cpp
@@ -13,6 +13,50 @@ namespace DiscIO
 {
 // Increment CACHE_REVISION (ISOFile.cpp & GameFile.cpp) if the code below is modified
 
+Region RegionSwitchGC(u8 country_code)
+{
+  Region region = RegionSwitchWii(country_code);
+  return region == Region::NTSC_K ? Region::UNKNOWN_REGION : region;
+}
+
+Region RegionSwitchWii(u8 country_code)
+{
+  switch (country_code)
+  {
+  case 'J':
+  case 'W':
+    return Region::NTSC_J;
+
+  case 'B':
+  case 'E':
+  case 'N':
+  case 'Z':
+    return Region::NTSC_U;
+
+  case 'D':
+  case 'F':
+  case 'H':
+  case 'I':
+  case 'L':
+  case 'M':
+  case 'P':
+  case 'R':
+  case 'S':
+  case 'U':
+  case 'X':
+  case 'Y':
+    return Region::PAL;
+
+  case 'K':
+  case 'Q':
+  case 'T':
+    return Region::NTSC_K;
+
+  default:
+    return Region::UNKNOWN_REGION;
+  }
+}
+
 Country CountrySwitch(u8 country_code)
 {
   switch (country_code)
diff --git a/Source/Core/DiscIO/Enums.h b/Source/Core/DiscIO/Enums.h
index 59f61561de..01f7ddb529 100644
--- a/Source/Core/DiscIO/Enums.h
+++ b/Source/Core/DiscIO/Enums.h
@@ -38,6 +38,16 @@ enum class Country
   NUMBER_OF_COUNTRIES
 };
 
+// Regions 0 - 2 and 4 match Nintendo's Wii region numbering.
+enum class Region
+{
+  NTSC_J = 0,          // Japan and Taiwan
+  NTSC_U = 1,          // Mainly North America
+  PAL = 2,             // Mainly Europe and Oceania
+  UNKNOWN_REGION = 3,  // 3 seems to be unused? Anyway, we need an UNKNOWN_REGION. Let's put it here
+  NTSC_K = 4           // South Korea (Wii only)
+};
+
 // Languages 0 - 9 match Nintendo's Wii language numbering.
 // Languages 1 - 6 match Nintendo's PAL GameCube languages 0 - 5.
 // NTSC GameCubes only support one language and thus don't number languages.
@@ -56,6 +66,8 @@ enum class Language
   LANGUAGE_UNKNOWN
 };
 
+Region RegionSwitchGC(u8 country_code);
+Region RegionSwitchWii(u8 country_code);
 Country CountrySwitch(u8 country_code);
 u8 GetSysMenuRegion(u16 title_version);
 std::string GetCompanyFromID(const std::string& company_id);
diff --git a/Source/Core/DiscIO/NANDContentLoader.cpp b/Source/Core/DiscIO/NANDContentLoader.cpp
index 5b3057efbf..2c5e0e87e7 100644
--- a/Source/Core/DiscIO/NANDContentLoader.cpp
+++ b/Source/Core/DiscIO/NANDContentLoader.cpp
@@ -311,12 +311,12 @@ std::vector<u8> CNANDContentLoader::GetKeyFromTicket(const std::vector<u8>& tick
   return AESDecode(common_key, iv, &ticket[0x01BF], 16);
 }
 
-DiscIO::Country CNANDContentLoader::GetCountry() const
+DiscIO::Region CNANDContentLoader::GetRegion() const
 {
   if (!IsValid())
-    return DiscIO::Country::COUNTRY_UNKNOWN;
+    return DiscIO::Region::UNKNOWN_REGION;
 
-  return CountrySwitch(m_Country);
+  return RegionSwitchWii(m_Country);
 }
 
 CNANDContentManager::~CNANDContentManager()
diff --git a/Source/Core/DiscIO/NANDContentLoader.h b/Source/Core/DiscIO/NANDContentLoader.h
index 6643e2789c..f8d3bb6711 100644
--- a/Source/Core/DiscIO/NANDContentLoader.h
+++ b/Source/Core/DiscIO/NANDContentLoader.h
@@ -20,7 +20,7 @@ class IOFile;
 
 namespace DiscIO
 {
-enum class Country;
+enum class Region;
 
 bool AddTicket(u64 title_id, const std::vector<u8>& ticket);
 
@@ -94,7 +94,7 @@ public:
   const std::vector<SNANDContent>& GetContent() const { return m_Content; }
   u16 GetTitleVersion() const { return m_TitleVersion; }
   u16 GetNumEntries() const { return m_NumEntries; }
-  DiscIO::Country GetCountry() const;
+  DiscIO::Region GetRegion() const;
   u8 GetCountryChar() const { return m_Country; }
   enum
   {
diff --git a/Source/Core/DiscIO/Volume.h b/Source/Core/DiscIO/Volume.h
index 44af039cba..6f4a6defe4 100644
--- a/Source/Core/DiscIO/Volume.h
+++ b/Source/Core/DiscIO/Volume.h
@@ -55,6 +55,7 @@ public:
   virtual bool SupportsIntegrityCheck() const { return false; }
   virtual bool CheckIntegrity() const { return false; }
   virtual bool ChangePartition(u64 offset) { return false; }
+  virtual Region GetRegion() const = 0;
   virtual Country GetCountry() const = 0;
   virtual BlobType GetBlobType() const = 0;
   // Size of virtual disc (not always accurate)
@@ -71,12 +72,7 @@ protected:
     // strnlen to trim NULLs
     std::string string(data, strnlen(data, sizeof(data)));
 
-    // There doesn't seem to be any GC discs with the country set to Taiwan...
-    // But maybe they would use Shift_JIS if they existed? Not sure
-    bool use_shift_jis =
-        (Country::COUNTRY_JAPAN == GetCountry() || Country::COUNTRY_TAIWAN == GetCountry());
-
-    if (use_shift_jis)
+    if (GetRegion() == Region::NTSC_J)
       return SHIFTJISToUTF8(string);
     else
       return CP1252ToUTF8(string);
diff --git a/Source/Core/DiscIO/VolumeDirectory.cpp b/Source/Core/DiscIO/VolumeDirectory.cpp
index 504d17c20f..40dda01d0d 100644
--- a/Source/Core/DiscIO/VolumeDirectory.cpp
+++ b/Source/Core/DiscIO/VolumeDirectory.cpp
@@ -166,6 +166,14 @@ void CVolumeDirectory::SetGameID(const std::string& id)
   memcpy(m_disk_header.data(), id.c_str(), std::min(id.length(), MAX_ID_LENGTH));
 }
 
+Region CVolumeDirectory::GetRegion() const
+{
+  if (m_is_wii)
+    return RegionSwitchWii(m_disk_header[3]);
+
+  return RegionSwitchGC(m_disk_header[3]);
+}
+
 Country CVolumeDirectory::GetCountry() const
 {
   return CountrySwitch(m_disk_header[3]);
diff --git a/Source/Core/DiscIO/VolumeDirectory.h b/Source/Core/DiscIO/VolumeDirectory.h
index ab0a96400d..13a8799eda 100644
--- a/Source/Core/DiscIO/VolumeDirectory.h
+++ b/Source/Core/DiscIO/VolumeDirectory.h
@@ -26,6 +26,7 @@ namespace DiscIO
 enum class BlobType;
 enum class Country;
 enum class Language;
+enum class Region;
 enum class Platform;
 
 class CVolumeDirectory : public IVolume
@@ -56,6 +57,7 @@ public:
   std::string GetApploaderDate() const override;
   Platform GetVolumeType() const override;
 
+  Region GetRegion() const override;
   Country GetCountry() const override;
 
   BlobType GetBlobType() const override;
diff --git a/Source/Core/DiscIO/VolumeGC.cpp b/Source/Core/DiscIO/VolumeGC.cpp
index 58faed4fe8..fcba359931 100644
--- a/Source/Core/DiscIO/VolumeGC.cpp
+++ b/Source/Core/DiscIO/VolumeGC.cpp
@@ -61,13 +61,20 @@ std::string CVolumeGC::GetGameID() const
   return DecodeString(ID);
 }
 
+Region CVolumeGC::GetRegion() const
+{
+  u8 country_code;
+  if (!m_pReader->Read(3, 1, &country_code))
+    return Region::UNKNOWN_REGION;
+
+  return RegionSwitchGC(country_code);
+}
+
 Country CVolumeGC::GetCountry() const
 {
-  if (!m_pReader)
-    return Country::COUNTRY_UNKNOWN;
-
   u8 country_code;
-  m_pReader->Read(3, 1, &country_code);
+  if (!m_pReader->Read(3, 1, &country_code))
+    return Country::COUNTRY_UNKNOWN;
 
   return CountrySwitch(country_code);
 }
@@ -247,7 +254,7 @@ void CVolumeGC::ExtractBannerInformation(const GCBanner& banner_file, bool is_bn
 
   if (is_bnr1)  // NTSC
   {
-    bool is_japanese = GetCountry() == Country::COUNTRY_JAPAN;
+    bool is_japanese = GetRegion() == Region::NTSC_J;
     number_of_languages = 1;
     start_language = is_japanese ? Language::LANGUAGE_JAPANESE : Language::LANGUAGE_ENGLISH;
   }
diff --git a/Source/Core/DiscIO/VolumeGC.h b/Source/Core/DiscIO/VolumeGC.h
index ca461949e2..ab424c6c50 100644
--- a/Source/Core/DiscIO/VolumeGC.h
+++ b/Source/Core/DiscIO/VolumeGC.h
@@ -19,6 +19,7 @@ namespace DiscIO
 enum class BlobType;
 enum class Country;
 enum class Language;
+enum class Region;
 enum class Platform;
 
 class CVolumeGC : public IVolume
@@ -42,6 +43,7 @@ public:
   u8 GetDiscNumber() const override;
 
   Platform GetVolumeType() const override;
+  Region GetRegion() const override;
   Country GetCountry() const override;
   BlobType GetBlobType() const override;
   u64 GetSize() const override;
diff --git a/Source/Core/DiscIO/VolumeWad.cpp b/Source/Core/DiscIO/VolumeWad.cpp
index 3254190be9..7c089ad10a 100644
--- a/Source/Core/DiscIO/VolumeWad.cpp
+++ b/Source/Core/DiscIO/VolumeWad.cpp
@@ -57,14 +57,21 @@ bool CVolumeWAD::Read(u64 _Offset, u64 _Length, u8* _pBuffer, bool decrypt) cons
   return m_pReader->Read(_Offset, _Length, _pBuffer);
 }
 
+Region CVolumeWAD::GetRegion() const
+{
+  u8 country_code;
+  if (!Read(m_tmd_offset + 0x0193, 1, &country_code))
+    return Region::UNKNOWN_REGION;
+
+  return RegionSwitchWii(country_code);
+}
+
 Country CVolumeWAD::GetCountry() const
 {
-  if (!m_pReader)
-    return Country::COUNTRY_UNKNOWN;
-
   // read the last digit of the titleID in the ticket
   u8 country_code;
-  Read(m_tmd_offset + 0x0193, 1, &country_code);
+  if (!Read(m_tmd_offset + 0x0193, 1, &country_code))
+    return Country::COUNTRY_UNKNOWN;
 
   if (country_code == 2)  // SYSMENU
   {
diff --git a/Source/Core/DiscIO/VolumeWad.h b/Source/Core/DiscIO/VolumeWad.h
index 68fc6a7612..0f28064387 100644
--- a/Source/Core/DiscIO/VolumeWad.h
+++ b/Source/Core/DiscIO/VolumeWad.h
@@ -21,6 +21,7 @@ namespace DiscIO
 enum class BlobType;
 enum class Country;
 enum class Language;
+enum class Region;
 enum class Platform;
 
 class CVolumeWAD : public IVolume
@@ -39,6 +40,7 @@ public:
   u64 GetFSTSize() const override { return 0; }
   std::string GetApploaderDate() const override { return ""; }
   Platform GetVolumeType() const override;
+  Region GetRegion() const override;
   Country GetCountry() const override;
 
   BlobType GetBlobType() const override;
diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.cpp b/Source/Core/DiscIO/VolumeWiiCrypted.cpp
index 09224e04aa..7976e1d758 100644
--- a/Source/Core/DiscIO/VolumeWiiCrypted.cpp
+++ b/Source/Core/DiscIO/VolumeWiiCrypted.cpp
@@ -153,51 +153,38 @@ std::string CVolumeWiiCrypted::GetGameID() const
   return DecodeString(ID);
 }
 
+Region CVolumeWiiCrypted::GetRegion() const
+{
+  u32 region_code;
+  if (!ReadSwapped(0x4E000, &region_code, false))
+    return Region::UNKNOWN_REGION;
+
+  return static_cast<Region>(region_code);
+}
+
 Country CVolumeWiiCrypted::GetCountry() const
 {
-  if (!m_pReader)
-    return Country::COUNTRY_UNKNOWN;
-
   u8 country_byte;
   if (!m_pReader->Read(3, 1, &country_byte))
     return Country::COUNTRY_UNKNOWN;
 
-  Country country_value = CountrySwitch(country_byte);
+  const Region region = GetRegion();
 
-  u32 region_code;
-  if (!ReadSwapped(0x4E000, &region_code, false))
-    return country_value;
+  if (RegionSwitchWii(country_byte) == region)
+    return CountrySwitch(country_byte);
 
-  switch (region_code)
+  switch (region)
   {
-  case 0:
-    switch (country_value)
-    {
-    case Country::COUNTRY_TAIWAN:
-      return Country::COUNTRY_TAIWAN;
-    default:
-      return Country::COUNTRY_JAPAN;
-    }
-  case 1:
+  case Region::NTSC_J:
+    return Country::COUNTRY_JAPAN;
+  case Region::NTSC_U:
     return Country::COUNTRY_USA;
-  case 2:
-    switch (country_value)
-    {
-    case Country::COUNTRY_FRANCE:
-    case Country::COUNTRY_GERMANY:
-    case Country::COUNTRY_ITALY:
-    case Country::COUNTRY_NETHERLANDS:
-    case Country::COUNTRY_RUSSIA:
-    case Country::COUNTRY_SPAIN:
-    case Country::COUNTRY_AUSTRALIA:
-      return country_value;
-    default:
-      return Country::COUNTRY_EUROPE;
-    }
-  case 4:
+  case Region::PAL:
+    return Country::COUNTRY_EUROPE;
+  case Region::NTSC_K:
     return Country::COUNTRY_KOREA;
   default:
-    return country_value;
+    return Country::COUNTRY_UNKNOWN;
   }
 }
 
diff --git a/Source/Core/DiscIO/VolumeWiiCrypted.h b/Source/Core/DiscIO/VolumeWiiCrypted.h
index 9bb449980d..d578dd5ba0 100644
--- a/Source/Core/DiscIO/VolumeWiiCrypted.h
+++ b/Source/Core/DiscIO/VolumeWiiCrypted.h
@@ -20,6 +20,7 @@ namespace DiscIO
 enum class BlobType;
 enum class Country;
 enum class Language;
+enum class Region;
 enum class Platform;
 
 class CVolumeWiiCrypted : public IVolume
@@ -46,6 +47,7 @@ public:
   bool CheckIntegrity() const override;
   bool ChangePartition(u64 offset) override;
 
+  Region GetRegion() const override;
   Country GetCountry() const override;
   BlobType GetBlobType() const override;
   u64 GetSize() const override;
diff --git a/Source/Core/DolphinQt2/GameList/GameFile.cpp b/Source/Core/DolphinQt2/GameList/GameFile.cpp
index f27f3a6683..3f1d60d65f 100644
--- a/Source/Core/DolphinQt2/GameList/GameFile.cpp
+++ b/Source/Core/DolphinQt2/GameList/GameFile.cpp
@@ -155,6 +155,7 @@ bool GameFile::TryLoadVolume()
   m_descriptions = ConvertLanguageMap(volume->GetDescriptions());
   m_disc_number = volume->GetDiscNumber();
   m_platform = volume->GetVolumeType();
+  m_region = volume->GetRegion();
   m_country = volume->GetCountry();
   m_blob_type = volume->GetBlobType();
   m_raw_size = volume->GetRawSize();
@@ -174,6 +175,7 @@ bool GameFile::TryLoadElfDol()
   m_revision = 0;
   m_long_names[DiscIO::Language::LANGUAGE_ENGLISH] = m_file_name;
   m_platform = DiscIO::Platform::ELF_DOL;
+  m_region = DiscIO::Region::UNKNOWN_REGION;
   m_country = DiscIO::Country::COUNTRY_UNKNOWN;
   m_blob_type = DiscIO::BlobType::DIRECTORY;
   m_raw_size = m_size;
diff --git a/Source/Core/DolphinQt2/GameList/GameFile.h b/Source/Core/DolphinQt2/GameList/GameFile.h
index 99d9a143e2..9813a39054 100644
--- a/Source/Core/DolphinQt2/GameList/GameFile.h
+++ b/Source/Core/DolphinQt2/GameList/GameFile.h
@@ -16,6 +16,7 @@ namespace DiscIO
 enum class BlobType;
 enum class Country;
 enum class Language;
+enum class Region;
 enum class Platform;
 class IVolume;
 }
@@ -47,6 +48,7 @@ public:
   QString GetApploaderDate() const { return m_apploader_date; }
   DiscIO::Platform GetPlatformID() const { return m_platform; }
   QString GetPlatform() const;
+  DiscIO::Region GetRegion() const { return m_region; }
   DiscIO::Country GetCountryID() const { return m_country; }
   QString GetCountry() const;
   DiscIO::BlobType GetBlobType() const { return m_blob_type; }
@@ -96,6 +98,7 @@ private:
   QMap<DiscIO::Language, QString> m_descriptions;
   QString m_company;
   u8 m_disc_number = 0;
+  DiscIO::Region m_region;
   DiscIO::Platform m_platform;
   DiscIO::Country m_country;
   DiscIO::BlobType m_blob_type;
diff --git a/Source/Core/DolphinWX/ISOFile.cpp b/Source/Core/DolphinWX/ISOFile.cpp
index e1ee632406..5a46458d81 100644
--- a/Source/Core/DolphinWX/ISOFile.cpp
+++ b/Source/Core/DolphinWX/ISOFile.cpp
@@ -36,7 +36,7 @@
 #include "DolphinWX/ISOFile.h"
 #include "DolphinWX/WxUtils.h"
 
-static const u32 CACHE_REVISION = 0x127;  // Last changed in PR 3309
+static const u32 CACHE_REVISION = 0x128;  // Last changed in PR 4542
 
 static std::string GetLanguageString(DiscIO::Language language,
                                      std::map<DiscIO::Language, std::string> strings)
@@ -64,8 +64,9 @@ static std::string GetLanguageString(DiscIO::Language language,
 GameListItem::GameListItem(const std::string& _rFileName,
                            const std::unordered_map<std::string, std::string>& custom_titles)
     : m_FileName(_rFileName), m_title_id(0), m_emu_state(0), m_FileSize(0),
-      m_Country(DiscIO::Country::COUNTRY_UNKNOWN), m_Revision(0), m_Valid(false), m_ImageWidth(0),
-      m_ImageHeight(0), m_disc_number(0), m_has_custom_name(false)
+      m_region(DiscIO::Region::UNKNOWN_REGION), m_Country(DiscIO::Country::COUNTRY_UNKNOWN),
+      m_Revision(0), m_Valid(false), m_ImageWidth(0), m_ImageHeight(0), m_disc_number(0),
+      m_has_custom_name(false)
 {
   if (LoadFromCache())
   {
@@ -99,6 +100,7 @@ GameListItem::GameListItem(const std::string& _rFileName,
       if (m_company.empty())
         m_company = GetLanguageString(DiscIO::Language::LANGUAGE_ENGLISH, volume->GetShortMakers());
 
+      m_region = volume->GetRegion();
       m_Country = volume->GetCountry();
       m_blob_type = volume->GetBlobType();
       m_FileSize = volume->GetRawSize();
@@ -214,6 +216,7 @@ void GameListItem::DoState(PointerWrap& p)
   p.Do(m_title_id);
   p.Do(m_FileSize);
   p.Do(m_VolumeSize);
+  p.Do(m_region);
   p.Do(m_Country);
   p.Do(m_blob_type);
   p.Do(m_pImage);
diff --git a/Source/Core/DolphinWX/ISOFile.h b/Source/Core/DolphinWX/ISOFile.h
index 3893c01777..836b453714 100644
--- a/Source/Core/DolphinWX/ISOFile.h
+++ b/Source/Core/DolphinWX/ISOFile.h
@@ -21,6 +21,7 @@ namespace DiscIO
 enum class BlobType;
 enum class Country;
 enum class Language;
+enum class Region;
 enum class Platform;
 }
 
@@ -48,6 +49,7 @@ public:
   u16 GetRevision() const { return m_Revision; }
   const std::string& GetGameID() const { return m_game_id; }
   const std::string GetWiiFSPath() const;
+  DiscIO::Region GetRegion() const { return m_region; }
   DiscIO::Country GetCountry() const { return m_Country; }
   DiscIO::Platform GetPlatform() const { return m_Platform; }
   DiscIO::BlobType GetBlobType() const { return m_blob_type; }
@@ -82,6 +84,7 @@ private:
   u64 m_FileSize;
   u64 m_VolumeSize;
 
+  DiscIO::Region m_region;
   DiscIO::Country m_Country;
   DiscIO::Platform m_Platform;
   DiscIO::BlobType m_blob_type;