mirror of
https://jihulab.com/DGP-Studio/Snap.Hutao.git
synced 2025-11-19 21:02:53 +08:00
fix #804
This commit is contained in:
@@ -150,7 +150,7 @@ internal sealed class Activation : IActivation
|
|||||||
// Increase launch times
|
// Increase launch times
|
||||||
LocalSetting.Set(SettingKeys.LaunchTimes, LocalSetting.Get(SettingKeys.LaunchTimes, 0) + 1);
|
LocalSetting.Set(SettingKeys.LaunchTimes, LocalSetting.Get(SettingKeys.LaunchTimes, 0) + 1);
|
||||||
|
|
||||||
if (LocalSetting.Get(SettingKeys.Major1Minor7Revision0GuideState, (uint)GuideState.None) < (uint)GuideState.Completed)
|
if (false && LocalSetting.Get(SettingKeys.Major1Minor7Revision0GuideState, (uint)GuideState.None) < (uint)GuideState.Completed)
|
||||||
{
|
{
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
serviceProvider.GetRequiredService<GuideWindow>();
|
serviceProvider.GetRequiredService<GuideWindow>();
|
||||||
|
|||||||
@@ -21,4 +21,20 @@ internal static class StringExtension
|
|||||||
{
|
{
|
||||||
return new(value);
|
return new(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 移除结尾可能存在的字符串
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="source">源</param>
|
||||||
|
/// <param name="value">值</param>
|
||||||
|
/// <returns>新的字符串</returns>
|
||||||
|
public static string TrimEnd(this string source, string value)
|
||||||
|
{
|
||||||
|
while (source.EndsWith(value))
|
||||||
|
{
|
||||||
|
source = source[..^value.Length];
|
||||||
|
}
|
||||||
|
|
||||||
|
return source;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1374,6 +1374,15 @@ namespace Snap.Hutao.Resource.Localization {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 查找类似 Url 中的语言:{0} 与胡桃的语言:{1} 不匹配,请切换到对应语言重试 的本地化字符串。
|
||||||
|
/// </summary>
|
||||||
|
internal static string ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 查找类似 不支持的 Item Id:{0} 的本地化字符串。
|
/// 查找类似 不支持的 Item Id:{0} 的本地化字符串。
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -2135,4 +2135,7 @@
|
|||||||
<data name="GuideWindowTitle" xml:space="preserve">
|
<data name="GuideWindowTitle" xml:space="preserve">
|
||||||
<value>欢迎使用胡桃</value>
|
<value>欢迎使用胡桃</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale" xml:space="preserve">
|
||||||
|
<value>Url 中的语言:{0} 与胡桃的语言:{1} 不匹配,请切换到对应语言重试</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.View.Dialog;
|
using Snap.Hutao.View.Dialog;
|
||||||
|
using Snap.Hutao.Web.Request.QueryString;
|
||||||
|
|
||||||
namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
||||||
|
|
||||||
@@ -14,6 +16,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
|||||||
internal sealed partial class GachaLogQueryManualInputProvider : IGachaLogQueryProvider
|
internal sealed partial class GachaLogQueryManualInputProvider : IGachaLogQueryProvider
|
||||||
{
|
{
|
||||||
private readonly IServiceProvider serviceProvider;
|
private readonly IServiceProvider serviceProvider;
|
||||||
|
private readonly MetadataOptions metadataOptions;
|
||||||
private readonly ITaskContext taskContext;
|
private readonly ITaskContext taskContext;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -25,13 +28,26 @@ internal sealed partial class GachaLogQueryManualInputProvider : IGachaLogQueryP
|
|||||||
// ContentDialog must be created by main thread.
|
// ContentDialog must be created by main thread.
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
GachaLogUrlDialog dialog = serviceProvider.CreateInstance<GachaLogUrlDialog>();
|
GachaLogUrlDialog dialog = serviceProvider.CreateInstance<GachaLogUrlDialog>();
|
||||||
(bool isOk, string query) = await dialog.GetInputUrlAsync().ConfigureAwait(false);
|
(bool isOk, string queryString) = await dialog.GetInputUrlAsync().ConfigureAwait(false);
|
||||||
|
|
||||||
if (isOk)
|
if (isOk)
|
||||||
{
|
{
|
||||||
if (query.Contains("&auth_appid=webview_gacha"))
|
QueryString query = QueryString.Parse(queryString);
|
||||||
|
string queryLanguageCode = query["lang"];
|
||||||
|
if (query["auth_appid"] == "webview_gacha")
|
||||||
{
|
{
|
||||||
return new(true, new(query));
|
if (metadataOptions.IsCurrentLocale(queryLanguageCode))
|
||||||
|
{
|
||||||
|
return new(true, new(queryString));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string message = string.Format(
|
||||||
|
SH.ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale,
|
||||||
|
queryLanguageCode,
|
||||||
|
metadataOptions.LocaleName);
|
||||||
|
return new(false, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) DGP Studio. All rights reserved.
|
// Copyright (c) DGP Studio. All rights reserved.
|
||||||
// Licensed under the MIT license.
|
// Licensed under the MIT license.
|
||||||
|
|
||||||
|
using Snap.Hutao.Service.Metadata;
|
||||||
using Snap.Hutao.Service.User;
|
using Snap.Hutao.Service.User;
|
||||||
using Snap.Hutao.ViewModel.User;
|
using Snap.Hutao.ViewModel.User;
|
||||||
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
using Snap.Hutao.Web.Hoyolab.Hk4e.Event.GachaInfo;
|
||||||
@@ -18,6 +19,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
|||||||
internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvider
|
internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvider
|
||||||
{
|
{
|
||||||
private readonly BindingClient2 bindingClient2;
|
private readonly BindingClient2 bindingClient2;
|
||||||
|
private readonly MetadataOptions metadataOptions;
|
||||||
private readonly IUserService userService;
|
private readonly IUserService userService;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
@@ -38,7 +40,7 @@ internal sealed partial class GachaLogQuerySTokenProvider : IGachaLogQueryProvid
|
|||||||
|
|
||||||
if (authkeyResponse.IsOk())
|
if (authkeyResponse.IsOk())
|
||||||
{
|
{
|
||||||
return new(true, new(GachaLogQueryOptions.AsQuery(data, authkeyResponse.Data)));
|
return new(true, new(GachaLogQueryOptions.AsQuery(data, authkeyResponse.Data, metadataOptions.LanguageCode)));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
using Snap.Hutao.Core.IO;
|
using Snap.Hutao.Core.IO;
|
||||||
using Snap.Hutao.Service.Game;
|
using Snap.Hutao.Service.Game;
|
||||||
|
using Snap.Hutao.Service.Metadata;
|
||||||
|
using Snap.Hutao.Web.Request.QueryString;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -18,6 +21,7 @@ namespace Snap.Hutao.Service.GachaLog.QueryProvider;
|
|||||||
internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProvider
|
internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProvider
|
||||||
{
|
{
|
||||||
private readonly IGameService gameService;
|
private readonly IGameService gameService;
|
||||||
|
private readonly MetadataOptions metadataOptions;
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public string Name { get => nameof(GachaLogQueryWebCacheProvider); }
|
public string Name { get => nameof(GachaLogQueryWebCacheProvider); }
|
||||||
@@ -63,7 +67,20 @@ internal sealed partial class GachaLogQueryWebCacheProvider : IGachaLogQueryProv
|
|||||||
|
|
||||||
if (!string.IsNullOrEmpty(result))
|
if (!string.IsNullOrEmpty(result))
|
||||||
{
|
{
|
||||||
return new(true, new(result));
|
QueryString query = QueryString.Parse(result.TrimEnd("#/log"));
|
||||||
|
string queryLanguageCode = query["lang"];
|
||||||
|
if (metadataOptions.IsCurrentLocale(queryLanguageCode))
|
||||||
|
{
|
||||||
|
return new(true, new(result));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
string message = string.Format(
|
||||||
|
SH.ServiceGachaLogUrlProviderUrlLanguageNotMatchCurrentLocale,
|
||||||
|
queryLanguageCode,
|
||||||
|
metadataOptions.LocaleName);
|
||||||
|
return new(false, message);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Snap.Hutao.Core;
|
using Snap.Hutao.Core;
|
||||||
|
using System.Collections.Immutable;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
|
||||||
@@ -15,6 +16,8 @@ namespace Snap.Hutao.Service.Metadata;
|
|||||||
[Injection(InjectAs.Singleton)]
|
[Injection(InjectAs.Singleton)]
|
||||||
internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
private readonly AppOptions appOptions;
|
private readonly AppOptions appOptions;
|
||||||
private readonly HutaoOptions hutaoOptions;
|
private readonly HutaoOptions hutaoOptions;
|
||||||
|
|
||||||
@@ -61,12 +64,51 @@ internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string LocaleName
|
public string LocaleName
|
||||||
{
|
{
|
||||||
get => localeName ??= GetLocaleName();
|
get => localeName ??= GetLocaleName(appOptions.CurrentCulture);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 当前语言代码
|
||||||
|
/// </summary>
|
||||||
|
public string LanguageCode
|
||||||
|
{
|
||||||
|
get => LocaleNames.LocaleNameLanguageCodeMap[LocaleName];
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public MetadataOptions Value { get => this; }
|
public MetadataOptions Value { get => this; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 获取语言名称
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="cultureInfo">语言信息</param>
|
||||||
|
/// <returns>元数据语言名称</returns>
|
||||||
|
public static string GetLocaleName(CultureInfo cultureInfo)
|
||||||
|
{
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
if (LocaleNames.LanguageNameLocaleNameMap.TryGetValue(cultureInfo.Name, out string? localeName))
|
||||||
|
{
|
||||||
|
return localeName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
cultureInfo = cultureInfo.Parent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 检查是否为当前语言名称
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="languageCode">语言代码</param>
|
||||||
|
/// <returns>是否为当前语言名称</returns>
|
||||||
|
public bool IsCurrentLocale(string languageCode)
|
||||||
|
{
|
||||||
|
CultureInfo cultureInfo = CultureInfo.GetCultureInfo(languageCode);
|
||||||
|
return GetLocaleName(cultureInfo) == LocaleName;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 获取本地的本地化元数据文件
|
/// 获取本地的本地化元数据文件
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -90,38 +132,65 @@ internal sealed partial class MetadataOptions : IOptions<MetadataOptions>
|
|||||||
return Web.HutaoEndpoints.HutaoMetadata2File(LocaleName, fileNameWithExtension);
|
return Web.HutaoEndpoints.HutaoMetadata2File(LocaleName, fileNameWithExtension);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private string GetLocaleName()
|
|
||||||
{
|
|
||||||
CultureInfo cultureInfo = appOptions.CurrentCulture;
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
if (Equals(cultureInfo, CultureInfo.InvariantCulture))
|
|
||||||
{
|
|
||||||
// Fallback to Chinese.
|
|
||||||
return "CHS";
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (cultureInfo.Name)
|
|
||||||
{
|
|
||||||
case "de": return "DE"; // German
|
|
||||||
case "en": return "EN"; // English
|
|
||||||
case "es": return "ES"; // Spanish
|
|
||||||
case "fr": return "FR"; // French
|
|
||||||
case "id": return "ID"; // Indonesian
|
|
||||||
case "it": return "IT"; // Italian
|
|
||||||
case "ja": return "JP"; // Japanese
|
|
||||||
case "ko": return "KR"; // Korean
|
|
||||||
case "pt": return "PT"; // Portuguese
|
|
||||||
case "ru": return "RU"; // Russian
|
|
||||||
case "th": return "TH"; // Thai
|
|
||||||
case "tr": return "TR"; // Turkish
|
|
||||||
case "vi": return "TR"; // Vietnamese
|
|
||||||
case "zh-Hans": return "CHS"; // Chinese (Simplified)
|
|
||||||
case "zh-Hant": return "CHT"; // Chinese (Traditional)
|
|
||||||
default: cultureInfo = cultureInfo.Parent; break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 本地化名称
|
||||||
|
/// </summary>
|
||||||
|
internal static class LocaleNames
|
||||||
|
{
|
||||||
|
public const string DE = "DE"; // German
|
||||||
|
public const string EN = "EN"; // English
|
||||||
|
public const string ES = "ES"; // Spanish
|
||||||
|
public const string FR = "FR"; // French
|
||||||
|
public const string ID = "ID"; // Indonesian
|
||||||
|
public const string IT = "IT"; // Italian
|
||||||
|
public const string JP = "JP"; // Japanese
|
||||||
|
public const string KR = "KR"; // Korean
|
||||||
|
public const string PT = "PT"; // Portuguese
|
||||||
|
public const string RU = "RU"; // Russian
|
||||||
|
public const string TH = "TH"; // Thai
|
||||||
|
public const string TR = "TR"; // Turkish
|
||||||
|
public const string VI = "VI"; // Vietnamese
|
||||||
|
public const string CHS = "CHS"; // Chinese (Simplified)
|
||||||
|
public const string CHT = "CHT"; // Chinese (Traditional)
|
||||||
|
|
||||||
|
public static readonly ImmutableDictionary<string, string> LanguageNameLocaleNameMap = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
["de"] = DE,
|
||||||
|
["en"] = EN,
|
||||||
|
["es"] = ES,
|
||||||
|
["fr"] = FR,
|
||||||
|
["id"] = ID,
|
||||||
|
["it"] = IT,
|
||||||
|
["ja"] = JP,
|
||||||
|
["ko"] = KR,
|
||||||
|
["pt"] = PT,
|
||||||
|
["ru"] = RU,
|
||||||
|
["th"] = TH,
|
||||||
|
["tr"] = TR,
|
||||||
|
["vi"] = VI,
|
||||||
|
["zh-Hans"] = CHS,
|
||||||
|
["zh-Hant"] = CHT,
|
||||||
|
[string.Empty] = CHS, // Fallback to Chinese.
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
|
||||||
|
public static readonly ImmutableDictionary<string, string> LocaleNameLanguageCodeMap = new Dictionary<string, string>()
|
||||||
|
{
|
||||||
|
[DE] = "de-de",
|
||||||
|
[EN] = "en-us",
|
||||||
|
[ES] = "es-es",
|
||||||
|
[FR] = "fr-fr",
|
||||||
|
[ID] = "id-id",
|
||||||
|
[IT] = "it-it",
|
||||||
|
[JP] = "ja-jp",
|
||||||
|
[KR] = "ko-kr",
|
||||||
|
[PT] = "pt-pt",
|
||||||
|
[RU] = "ru-ru",
|
||||||
|
[TH] = "th-th",
|
||||||
|
[TR] = "tr-tr",
|
||||||
|
[VI] = "vi-vn",
|
||||||
|
[CHS] = "zh-cn",
|
||||||
|
[CHT] = "zh-tw",
|
||||||
|
}.ToImmutableDictionary();
|
||||||
|
}
|
||||||
@@ -33,7 +33,7 @@ internal sealed partial class GachaLogUrlDialog : ContentDialog
|
|||||||
{
|
{
|
||||||
await taskContext.SwitchToMainThreadAsync();
|
await taskContext.SwitchToMainThreadAsync();
|
||||||
ContentDialogResult result = await ShowAsync();
|
ContentDialogResult result = await ShowAsync();
|
||||||
string url = InputText.Text;
|
string url = InputText.Text.TrimEnd("#/log");
|
||||||
|
|
||||||
return new(result == ContentDialogResult.Primary, url);
|
return new(result == ContentDialogResult.Primary, url);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ internal struct GachaLogQueryOptions
|
|||||||
IsOversea = query.IsOversea;
|
IsOversea = query.IsOversea;
|
||||||
innerQuery = QueryString.Parse(query.Query);
|
innerQuery = QueryString.Parse(query.Query);
|
||||||
|
|
||||||
innerQuery.Set("lang", "zh-cn");
|
// innerQuery.Set("lang", "zh-cn");
|
||||||
innerQuery.Set("gacha_type", (int)type);
|
innerQuery.Set("gacha_type", (int)type);
|
||||||
innerQuery.Set("size", Size);
|
innerQuery.Set("size", Size);
|
||||||
|
|
||||||
@@ -68,10 +68,12 @@ internal struct GachaLogQueryOptions
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="genAuthKeyData">生成信息</param>
|
/// <param name="genAuthKeyData">生成信息</param>
|
||||||
/// <param name="gameAuthKey">验证包装</param>
|
/// <param name="gameAuthKey">验证包装</param>
|
||||||
|
/// <param name="lang">语言</param>
|
||||||
/// <returns>查询</returns>
|
/// <returns>查询</returns>
|
||||||
public static string AsQuery(GenAuthKeyData genAuthKeyData, GameAuthKey gameAuthKey)
|
public static string AsQuery(GenAuthKeyData genAuthKeyData, GameAuthKey gameAuthKey, string lang)
|
||||||
{
|
{
|
||||||
QueryString queryString = new();
|
QueryString queryString = new();
|
||||||
|
queryString.Set("lang", lang);
|
||||||
queryString.Set("auth_appid", genAuthKeyData.AuthAppId);
|
queryString.Set("auth_appid", genAuthKeyData.AuthAppId);
|
||||||
queryString.Set("authkey", Uri.EscapeDataString(gameAuthKey.AuthKey));
|
queryString.Set("authkey", Uri.EscapeDataString(gameAuthKey.AuthKey));
|
||||||
queryString.Set("authkey_ver", gameAuthKey.AuthKeyVersion);
|
queryString.Set("authkey_ver", gameAuthKey.AuthKeyVersion);
|
||||||
|
|||||||
Reference in New Issue
Block a user