feat: 添加解析错误消息

This commit is contained in:
Xu 2026-03-26 09:33:30 +08:00
commit a7c3f766f7
20 changed files with 165 additions and 108 deletions

View file

@ -57,16 +57,13 @@ void LocalizationService::EarlyInitialize() {
}
}
_Language(bestLanguage);
_SetLanguage(bestLanguage);
}
void LocalizationService::Initialize(int language) {
if (language >= 0) {
_Language(SUPPORTED_LANGUAGES[language]);
_SetLanguage(SUPPORTED_LANGUAGES[language]);
}
_resourceLoader = winrt::ResourceLoader::GetForViewIndependentUse(
CommonSharedConstants::APP_RESOURCE_MAP_ID);
}
std::span<const wchar_t*> LocalizationService::GetSupportedLanguages() noexcept {
@ -74,10 +71,14 @@ std::span<const wchar_t*> LocalizationService::GetSupportedLanguages() noexcept
}
winrt::hstring LocalizationService::GetLocalizedString(std::wstring_view resName) const noexcept {
return _resourceLoader.GetString(resName);
assert(_language);
// 不确定 ResourceLoader 是否线程安全,为每个线程创建独立的实例
thread_local static winrt::ResourceLoader resourceLoader =
winrt::ResourceLoader::GetForViewIndependentUse(CommonSharedConstants::APP_RESOURCE_MAP_ID);
return resourceLoader.GetString(resName);
}
void LocalizationService::_Language(const wchar_t* tag) {
void LocalizationService::_SetLanguage(const wchar_t* tag) {
_language = tag;
winrt::ResourceContext::SetGlobalQualifierValue(L"Language", tag);
}

View file

@ -4,12 +4,15 @@
#include "StrHelper.h"
#include "Logger.h"
#include "ShaderEffectDesc.h"
#include "LocalizationService.h"
#include <bitset>
namespace Magpie {
// 当前 MagpieFX 版本
static constexpr uint32_t MAGPIE_FX_VERSION = 5;
// 向后兼容的最低版本
static constexpr uint32_t MAGPIE_FX_MIN_SUPPORTED_VERSION = 4;
// 必须出现在一行的开头才视为指令
static const char* META_INDICATOR = "//!";
@ -20,6 +23,37 @@ struct ParserState {
bool isNewLine;
};
static std::string DebugFormat(std::string_view str) noexcept {
return fmt::format("{:?s}", std::span<const char>(str.begin(), str.end()));
}
static void SetGeneralParseError(
ParserState& state,
std::string_view source,
std::string_view expected = {}
) noexcept {
// 限制打印的源代码字符数量
std::string sourceStart;
constexpr uint32_t SOURCE_PRINT_COUNT = 12;
if (source.size() <= SOURCE_PRINT_COUNT) {
sourceStart = DebugFormat(source);
} else {
sourceStart = StrHelper::Concat(source.substr(0, SOURCE_PRINT_COUNT), "...");
sourceStart = DebugFormat(sourceStart);
}
if (expected.empty()) {
std::string msgFmt = StrHelper::UTF16ToUTF8(LocalizationService::Get()
.GetLocalizedString(L"ShaderEffectParser_GeneralError"));
state.errorMsg = fmt::format(fmt::runtime(msgFmt), state.lineNumber, sourceStart);
} else {
std::string msgFmt = StrHelper::UTF16ToUTF8(LocalizationService::Get()
.GetLocalizedString(L"ShaderEffectParser_GeneralErrorWithExpected"));
state.errorMsg = fmt::format(fmt::runtime(msgFmt),
state.lineNumber, sourceStart, DebugFormat(expected));
}
}
static bool RemoveLeadingComment(
std::string_view& source,
ParserState& state,
@ -72,7 +106,8 @@ static bool RemoveLeadingComment(
// 提取换行符的后一个字符需检查文件结尾
if (i + 1 == source.size()) {
state.errorMsg = "块注释未闭合";
state.errorMsg = StrHelper::UTF16ToUTF8(LocalizationService::Get()
.GetLocalizedString(L"ShaderEffectParser_UnclosedBlockComment"));
return false;
}
}
@ -144,6 +179,7 @@ static bool GetNextToken(std::string_view& source, ParserState& state, std::stri
result = source;
return true;
} else {
SetGeneralParseError(state, source);
return false;
}
}
@ -152,7 +188,7 @@ static bool GetNextToken(std::string_view& source, ParserState& state, std::stri
// 必须以字母或下划线开头
if (!StrHelper::isalpha(c) && c != '_') {
state.errorMsg = fmt::format("Unexpected character \"{}\" in line {}.", c, state.lineNumber);
SetGeneralParseError(state, source);
return false;
}
@ -187,7 +223,7 @@ static bool CheckNextToken(std::string_view& source, ParserState& state, std::st
if (token == expectedToken) {
return true;
} else {
state.errorMsg = fmt::format("Unexpected token \"{}\" in line {}.", token, state.lineNumber);
SetGeneralParseError(state, source, expectedToken);
return false;
}
}
@ -206,32 +242,25 @@ static bool CheckMetaIndicator(std::string_view& source, ParserState& state, boo
return true;
}
static bool RequireMetaIndicator(std::string_view& source, ParserState& state) noexcept {
bool result = false;
if (!CheckMetaIndicator(source, state, result)) {
return false;
}
if (!result) {
state.errorMsg = fmt::format("Unexpected character \"{}\" in line {}.", source[0], state.lineNumber);
}
return result;
}
static bool RequireLineEnd(std::string_view& source, ParserState& state) noexcept {
RemoveLeadingSpaces(source, state);
if (source.empty() || source[0] == '\n') {
return true;
} else {
state.errorMsg = fmt::format("Unexpected character \"{}\" in line {}.", source[0], state.lineNumber);
SetGeneralParseError(state, source, "\n");
return false;
}
}
static bool CheckMagic(std::string_view& source, ParserState& state) noexcept {
if (!RequireMetaIndicator(source, state)) {
bool isMetaIndicator = false;
if (!CheckMetaIndicator(source, state, isMetaIndicator)) {
return false;
}
if (!isMetaIndicator) {
SetGeneralParseError(state, source, META_INDICATOR);
return false;
}
@ -268,6 +297,7 @@ static bool GetNextStringUntilLineEnd(
if constexpr (!AllowEmpty) {
if (value.empty()) {
SetGeneralParseError(state, source);
return false;
}
}
@ -288,6 +318,7 @@ static bool GetNextNumber(std::string_view& source, ParserState& state, T& value
const auto& result = std::from_chars(source.data(), source.data() + source.size(), value);
if ((int)result.ec) {
SetGeneralParseError(state, source);
return false;
}
@ -371,8 +402,9 @@ static bool ResolveHeaderVersion(
return false;
}
// 向后兼容到 5
if (version < 5 || version > MAGPIE_FX_VERSION) {
if (version < MAGPIE_FX_MIN_SUPPORTED_VERSION || version > MAGPIE_FX_VERSION) {
state.errorMsg = StrHelper::UTF16ToUTF8(LocalizationService::Get()
.GetLocalizedString(L"ShaderEffectParser_UnsupportedFXVersion"));
return false;
}
@ -467,7 +499,7 @@ static bool ResolveHeaderScaleFactor(
static bool ResolveHeader(
std::string_view source,
uint32_t startLineNumer,
ParserState& state,
EffectInfo& effectInfo
) noexcept {
static constexpr std::array COMMAND_INFOS = {
@ -478,11 +510,6 @@ static bool ResolveHeader(
CommandInfo{ "SCALE_FACTOR", ResolveHeaderScaleFactor, false },
};
ParserState state = {
.lineNumber = startLineNumer,
.isNewLine = false
};
if (!ResolveBlockCommon(COMMAND_INFOS, source, state, &effectInfo)) {
return false;
}
@ -497,6 +524,7 @@ static bool ResolveHeader(
// HEADER 只能有 #include
if (!source.starts_with("#include")) {
SetGeneralParseError(state, source, "\n");
return false;
}
@ -511,7 +539,12 @@ static bool ResolveHeader(
return false;
}
return source.empty();
if (!source.empty()) {
SetGeneralParseError(state, source, "\n");
return false;
}
return true;
}
static bool ResolveParameterDefault(
@ -594,7 +627,7 @@ static bool ResolveParameterLabel(
static bool ResolveParameter(
std::string_view source,
uint32_t startLineNumer,
ParserState& state,
EffectInfoParameter& effectInfoParameter
) noexcept {
static constexpr std::array COMMAND_INFOS = {
@ -605,11 +638,6 @@ static bool ResolveParameter(
CommandInfo{ "LABEL", ResolveParameterLabel, false }
};
ParserState state = {
.lineNumber = startLineNumer,
.isNewLine = false
};
if (!ResolveBlockCommon(COMMAND_INFOS, source, state, &effectInfoParameter)) {
return false;
}
@ -626,6 +654,7 @@ static bool ResolveParameter(
}
if (token != "float" && token != "int") {
SetGeneralParseError(state, source, "float|int");
return false;
}
@ -635,7 +664,12 @@ static bool ResolveParameter(
effectInfoParameter.name = token;
if (!RemoveLeadingBlanks(source, state) || !source.starts_with(';')) {
if (!RemoveLeadingBlanks(source, state)) {
return false;
}
if (!source.starts_with(';')) {
SetGeneralParseError(state, source, ";");
return false;
}
@ -774,14 +808,20 @@ std::string ShaderEffectParser::ParseForInfo(
// 结束最后一个区块。source 以换行符结尾,因此最后一个区块也以换行符结尾。
completeCurrentBlock(BlockType::Header, sourceView.size(), std::numeric_limits<size_t>::max());
if (!ResolveHeader(headerBlock.source, headerBlock.startLineNumer, effectInfo)) {
state.lineNumber = headerBlock.startLineNumer;
state.isNewLine = false;
if (!ResolveHeader(headerBlock.source, state, effectInfo)) {
Logger::Get().Error(StrHelper::Concat("ResolveHeader 失败\n\t错误消息: ", state.errorMsg));
return std::move(state.errorMsg);
}
effectInfo.params.resize(paramBlocks.size());
for (size_t i = 0; i < paramBlocks.size(); ++i) {
if (!ResolveParameter(paramBlocks[i].source, paramBlocks[i].startLineNumer, effectInfo.params[i])) {
state.lineNumber = paramBlocks[i].startLineNumer;
state.isNewLine = false;
if (!ResolveParameter(paramBlocks[i].source, state, effectInfo.params[i])) {
Logger::Get().Error(fmt::format("ResolveParameter#{} 失败\n\t错误消息: ", state.errorMsg));
return std::move(state.errorMsg);
}

View file

@ -30,10 +30,9 @@ public:
private:
LocalizationService() = default;
void _Language(const wchar_t* tag);
void _SetLanguage(const wchar_t* tag);
const wchar_t* _language = nullptr;
winrt::ResourceLoader _resourceLoader{ nullptr };
};
}

View file

@ -178,10 +178,9 @@ static HRESULT CALLBACK TaskDialogCallback(
}
static void ShowErrorMessage(const wchar_t* mainInstruction, const wchar_t* content) noexcept {
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
const hstring errorStr = resourceLoader.GetString(L"AppSettings_Dialog_Error");
const hstring exitStr = resourceLoader.GetString(L"AppSettings_Dialog_Exit");
LocalizationService& ls = LocalizationService::Get();
const hstring errorStr = ls.GetLocalizedString(L"AppSettings_Dialog_Error");
const hstring exitStr = ls.GetLocalizedString(L"AppSettings_Dialog_Exit");
TASKDIALOG_BUTTON button{ IDCANCEL, exitStr.c_str() };
TASKDIALOGCONFIG tdc{
@ -223,17 +222,18 @@ bool AppSettings::Initialize() noexcept {
return true;
}
// 此时 ResourceLoader 使用“首选语言”
// 此时 LocalizationService 使用“首选语言”
std::string configText;
if (!Win32Helper::ReadTextFile(existingConfigPath.c_str(), configText)) {
logger.Error("读取配置文件失败");
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
hstring title = resourceLoader.GetString(L"AppSettings_ErrorDialog_ReadFailed");
hstring content = resourceLoader.GetString(L"AppSettings_ErrorDialog_ConfigLocation");
LocalizationService& ls = LocalizationService::Get();
hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ReadFailed");
hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
ShowErrorMessage(title.c_str(),
fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath.native()).c_str());
return false;
}
@ -249,23 +249,25 @@ bool AppSettings::Initialize() noexcept {
doc.ParseInsitu(configText.data());
if (doc.HasParseError()) {
Logger::Get().Error(fmt::format("解析配置失败\n\t错误码: {}", (int)doc.GetParseError()));
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
hstring title = resourceLoader.GetString(L"AppSettings_ErrorDialog_NotValidJson");
hstring content = resourceLoader.GetString(L"AppSettings_ErrorDialog_ConfigLocation");
LocalizationService& ls = LocalizationService::Get();
hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_NotValidJson");
hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
ShowErrorMessage(title.c_str(),
fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath.native()).c_str());
return false;
}
if (!doc.IsObject()) {
Logger::Get().Error("配置文件根元素不是 Object");
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
hstring title = resourceLoader.GetString(L"AppSettings_ErrorDialog_ParseFailed");
hstring content = resourceLoader.GetString(L"AppSettings_ErrorDialog_ConfigLocation");
LocalizationService& ls = LocalizationService::Get();
hstring title = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ParseFailed");
hstring content = ls.GetLocalizedString(L"AppSettings_ErrorDialog_ConfigLocation");
ShowErrorMessage(title.c_str(),
fmt::format(fmt::runtime(std::wstring_view(content)), existingConfigPath.native()).c_str());
return false;
}

View file

@ -43,9 +43,8 @@ HomeViewModel::HomeViewModel() {
}
hstring HomeViewModel::TimerDescription() const noexcept {
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
hstring fmtStr = resourceLoader.GetString(L"Home_Activation_Timer_Description");
hstring fmtStr = LocalizationService::Get()
.GetLocalizedString(L"Home_Activation_Timer_Description");
return hstring(fmt::format(
fmt::runtime(std::wstring_view(fmtStr)),
AppSettings::Get().CountdownSeconds()
@ -71,12 +70,11 @@ bool HomeViewModel::IsNotRunning() const noexcept {
}
hstring HomeViewModel::TimerButtonText(bool windowedMode) const noexcept {
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
LocalizationService& ls = LocalizationService::Get();
if (ScalingService::Get().IsTimerOn(windowedMode)) {
return resourceLoader.GetString(L"Home_Activation_Timer_Cancel");
return ls.GetLocalizedString(L"Home_Activation_Timer_Cancel");
} else {
return resourceLoader.GetString(L"Home_Activation_Timer_Start");
return ls.GetLocalizedString(L"Home_Activation_Timer_Start");
}
}
@ -119,9 +117,8 @@ hstring HomeViewModel::UpdateCardTitle() const noexcept {
return {};
}
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
hstring titleFmt = resourceLoader.GetString(L"About_Version_UpdateCard_Title");
hstring titleFmt = LocalizationService::Get()
.GetLocalizedString(L"About_Version_UpdateCard_Title");
return hstring(fmt::format(fmt::runtime(std::wstring_view(titleFmt)), updateService.Tag()));
}
@ -162,15 +159,14 @@ hstring HomeViewModel::InitialToolbarStateDescription() const noexcept {
const ToolbarState windowedInitialState =
AppSettings::Get().WindowedInitialToolbarState();
const ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
LocalizationService& ls = LocalizationService::Get();
if (fullscreenInitialState == windowedInitialState) {
return resourceLoader.GetString(STATE_STRING_IDS[(uint32_t)fullscreenInitialState]);
return ls.GetLocalizedString(STATE_STRING_IDS[(uint32_t)fullscreenInitialState]);
} else {
return hstring(StrHelper::Concat(
resourceLoader.GetString(STATE_STRING_IDS[(uint32_t)fullscreenInitialState]),
ls.GetLocalizedString(STATE_STRING_IDS[(uint32_t)fullscreenInitialState]),
L" | ",
resourceLoader.GetString(STATE_STRING_IDS[(uint32_t)windowedInitialState]))
ls.GetLocalizedString(STATE_STRING_IDS[(uint32_t)windowedInitialState]))
);
}
}
@ -229,9 +225,8 @@ void HomeViewModel::OpenScreenshotSaveDirectory() const noexcept {
}
fire_and_forget HomeViewModel::ChangeScreenshotSaveDirectory() noexcept {
const ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
const hstring titleStr = resourceLoader.GetString(L"Dialog_SetlectScreenshotSaveDirectory_Title");
const hstring titleStr = LocalizationService::Get()
.GetLocalizedString(L"Dialog_SelectScreenshotSaveDirectory_Title");
const std::filesystem::path oldValue = AppSettings::Get().ScreenshotsDir();

View file

@ -916,7 +916,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>Change</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>Select a directory to save screenshots</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">
@ -1060,4 +1060,16 @@
<data name="Home_Advanced_DeveloperOptions_HighestShaderModel_NotLimited.Content" xml:space="preserve">
<value>Not limited</value>
</data>
<data name="ShaderEffectParser_UnclosedBlockComment" xml:space="preserve">
<value>Unclosed block comment.</value>
</data>
<data name="ShaderEffectParser_GeneralError" xml:space="preserve">
<value>Line {}: unable to parse {}.</value>
</data>
<data name="ShaderEffectParser_UnsupportedFXVersion" xml:space="preserve">
<value>Unsupported FX version.</value>
</data>
<data name="ShaderEffectParser_GeneralErrorWithExpected" xml:space="preserve">
<value>Line {}: unable to parse {}, expected: {}.</value>
</data>
</root>

View file

@ -895,7 +895,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>Cambiar</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>Selecciona una ruta para guardar capturas de pantalla</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -910,7 +910,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>Changer</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>Choisissez un répertoire pour sauvegarder vos captures</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -913,7 +913,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>Ubah</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>Pilih direktori untuk menyimpan tangkapan layar</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -910,7 +910,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>変更</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>スクリーンショットの保存先を選択する</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -949,7 +949,7 @@
<data name="Message_Windowed3DGameMode" xml:space="preserve">
<value>3D 게임 모드에서는 창 모드 스케일링이 지원되지 않습니다.</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>스크린샷을 저장할 경로를 선택하세요</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -854,7 +854,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>Zmień</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>Wybierz katalog, w którym chcesz zapisać zrzuty ekranu</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -910,7 +910,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>Изменить</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>Выбрать директорию сохранения скриншотов</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -913,7 +913,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>மாற்றம்</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>திரை சாட்களைச் சேமிக்க ஒரு கோப்பகத்தைத் தேர்ந்தெடுக்கவும்</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -835,7 +835,7 @@
<data name="Home_Advanced_DeveloperOptions_DisableTopmost.Content" xml:space="preserve">
<value>Tắt chế độ luôn ở trên cùng</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>Chọn thư mục để lưu ảnh chụp màn hình</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -916,7 +916,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>更改</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>选择截图保存目录</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">
@ -1060,4 +1060,16 @@
<data name="Home_Advanced_DeveloperOptions_HighestShaderModel_NotLimited.Content" xml:space="preserve">
<value>不限制</value>
</data>
<data name="ShaderEffectParser_UnclosedBlockComment" xml:space="preserve">
<value>块注释未闭合。</value>
</data>
<data name="ShaderEffectParser_GeneralErrorWithExpected" xml:space="preserve">
<value>第 {} 行: 无法解析 {},期望为:{}。</value>
</data>
<data name="ShaderEffectParser_UnsupportedFXVersion" xml:space="preserve">
<value>不支持的 FX 版本。</value>
</data>
<data name="ShaderEffectParser_GeneralError" xml:space="preserve">
<value>第 {} 行: 无法解析 {}。</value>
</data>
</root>

View file

@ -913,7 +913,7 @@
<data name="Home_Toolbar_ScreenshotSaveDirectory_Change.Content" xml:space="preserve">
<value>更改</value>
</data>
<data name="Dialog_SetlectScreenshotSaveDirectory_Title" xml:space="preserve">
<data name="Dialog_SelectScreenshotSaveDirectory_Title" xml:space="preserve">
<value>選擇截圖儲存目錄</value>
</data>
<data name="Message_ScreenshotSaved" xml:space="preserve">

View file

@ -283,15 +283,13 @@ void RootPage::NewProfileNameContextFlyout_Opening(IInspectable const&, IInspect
return;
}
// 惰性初始化
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
LocalizationService& ls = LocalizationService::Get();
// 填入进程名
MenuFlyoutItem item1;
FontIcon icon1;
icon1.Glyph(L"\xE9F5");
item1.Text(resourceLoader.GetString(L"Root_NewProfileFlyout_NameContextFlyout_ProcessName"));
item1.Text(ls.GetLocalizedString(L"Root_NewProfileFlyout_NameContextFlyout_ProcessName"));
item1.Icon(icon1);
RoutedEventHandler clickHandler([this](IInspectable const&, IInspectable const&) {
_UpdateNewProfileNameTextBox(false);
@ -304,7 +302,7 @@ void RootPage::NewProfileNameContextFlyout_Opening(IInspectable const&, IInspect
MenuFlyoutItem item2;
FontIcon icon2;
icon2.Glyph(L"\xECAA");
item2.Text(resourceLoader.GetString(L"Root_NewProfileFlyout_NameContextFlyout_AppName"));
item2.Text(ls.GetLocalizedString(L"Root_NewProfileFlyout_NameContextFlyout_AppName"));
item2.Icon(icon2);
item2.Click(clickHandler);
item2.Tag(box_value(2));
@ -321,7 +319,7 @@ void RootPage::NewProfileNameContextFlyout_Opening(IInspectable const&, IInspect
FontIcon icon3;
icon3.Glyph(L"\xE737");
item3.Icon(icon3);
item3.Text(resourceLoader.GetString(L"Root_NewProfileFlyout_NameContextFlyout_WindowTitle"));
item3.Text(ls.GetLocalizedString(L"Root_NewProfileFlyout_NameContextFlyout_WindowTitle"));
item3.Click([this](IInspectable const&, IInspectable const&) {
_UpdateNewProfileNameTextBox(true);
});

View file

@ -14,6 +14,7 @@
#include "ScalingModeEffectItem.h"
#include "Win32Helper.h"
#include "RootPage.h"
#include "LocalizationService.h"
using namespace ::Magpie;
@ -30,9 +31,8 @@ ScalingModeItem::ScalingModeItem(uint32_t index, bool isInitialExpanded)
std::vector<IInspectable> linkedProfiles;
const Profile& defaultProfile = AppSettings::Get().DefaultProfile();
if (defaultProfile.scalingMode == (int)index) {
hstring defaults = ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID)
.GetString(L"Root_Defaults/Content");
linkedProfiles.push_back(box_value(defaults));
linkedProfiles.push_back(box_value(LocalizationService::Get()
.GetLocalizedString(L"Root_Defaults/Content")));
}
for (const Profile& profile : AppSettings::Get().Profiles()) {
if (profile.scalingMode == (int)index) {
@ -267,10 +267,9 @@ hstring ScalingModeItem::Description() const noexcept {
if (EffectsService::Get().GetEffect(effect.name) != nullptr) {
result += EffectHelper::GetDisplayName(effect.name);
} else {
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
result += L'(';
result += resourceLoader.GetString(L"ScalingModes_Description_UnknownEffect");
result += LocalizationService::Get()
.GetLocalizedString(L"ScalingModes_Description_UnknownEffect");
result += L')';
}
}

View file

@ -15,14 +15,13 @@ using namespace Magpie;
namespace winrt::Magpie::implementation {
IVector<IInspectable> SettingsViewModel::Languages() const {
std::span<const wchar_t*> tags = LocalizationService::Get().GetSupportedLanguages();
LocalizationService& ls = LocalizationService::Get();
std::span<const wchar_t*> tags = ls.GetSupportedLanguages();
std::vector<IInspectable> languages;
languages.reserve(tags.size() + 1);
ResourceLoader resourceLoader =
ResourceLoader::GetForCurrentView(CommonSharedConstants::APP_RESOURCE_MAP_ID);
languages.push_back(box_value(resourceLoader.GetString(L"Settings_General_Language_System")));
languages.push_back(box_value(ls.GetLocalizedString(L"Settings_General_Language_System")));
for (const wchar_t* tag : tags) {
Windows::Globalization::Language language(tag);
languages.push_back(box_value(language.NativeName()));