diff --git a/package.json b/package.json
index b4d948c..595af80 100644
--- a/package.json
+++ b/package.json
@@ -3,6 +3,9 @@
"version": "0.1.0",
"private": true,
"scripts": {
+ "i18n:check": "node scripts/check-localization.cjs",
+ "rank:i18n:check": "node scripts/check-rank-i18n.cjs",
+ "battle:display:check": "node scripts/check-battle-display.cjs",
"proto:generate": "node scripts/generate-match-schema.mjs",
"proto:check": "node scripts/generate-match-schema.mjs --check",
"proto:update": "npm run proto:generate && npm run build",
diff --git a/src/App.vue b/src/App.vue
index 5ccb912..68803e0 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,4 +1,6 @@
- 总成绩
- {{ arrows.reduce((last, next) => last + next.ring, 0) }}环
+ {{ t('final_score') }}
+ {{ arrows.reduce((last, next) => last + next.ring, 0) }}{{ t('pts') }}
{
完成{{ validArrows }}箭,获得{{ validArrows }}点经验{{ t('completed') }}{{ validArrows }}{{ t('arrows_earned') }}{{ validArrows }}{{ t('xp') }}
{
:style="{ transform: `translateY(${showPanel ? '0%' : '100%'})` }"
>
- 本局成绩(共{{ totalRing }}环):
+ {{ t('score_this_match_total') }}{{ totalRing }}{{ t('pts_194') }}
@@ -140,17 +142,16 @@ const openCoachComment = () => {
mode="tall"
>
diff --git a/src/pages/coin/components/OfflineExchangeNotice.vue b/src/pages/coin/components/OfflineExchangeNotice.vue
index 63f7383..32c0251 100644
--- a/src/pages/coin/components/OfflineExchangeNotice.vue
+++ b/src/pages/coin/components/OfflineExchangeNotice.vue
@@ -1,4 +1,6 @@
-
+
@@ -121,15 +123,13 @@ onBeforeUnmount(() => {
- 请完成以上步骤校准智能弓
+ {{ t('complete_the_steps_above_to_calibrate_your_smart_bow') }}
- 我已校准
-
+ >{{ t('i_ve_calibrated_it') }}
diff --git a/src/pages/device/composables/useDeviceBinding.js b/src/pages/device/composables/useDeviceBinding.js
index f9ba5ec..33c1fbe 100644
--- a/src/pages/device/composables/useDeviceBinding.js
+++ b/src/pages/device/composables/useDeviceBinding.js
@@ -1,3 +1,4 @@
+import { t } from "@/locales";
import { bindDeviceAPIV2 } from "@/apis";
export function useDeviceBinding({
@@ -13,7 +14,7 @@ export function useDeviceBinding({
url: "/pages/device/device-bind-failure",
fail: (error) => {
console.error("打开绑定失败页失败", error);
- uni.showToast({ title: "二维码不正确,请重新扫码", icon: "none" });
+ uni.showToast({ title: t('invalid_qr_code_please_scan_again'), icon: "none" });
},
});
};
@@ -23,7 +24,7 @@ export function useDeviceBinding({
url: "/pages/device/device-already-bound",
fail: (error) => {
console.error("打开设备已绑定页失败", error);
- uni.showToast({ title: "设备已绑定其他账号,请解绑后再绑定", icon: "none" });
+ uni.showToast({ title: t('this_device_is_bound_to_another_account_unbind_it_first'), icon: "none" });
},
});
};
@@ -77,7 +78,7 @@ export function useDeviceBinding({
fail: (navigationError) => {
applyBoundDevice();
console.error("打开绑定成功页失败", navigationError);
- uni.showToast({ title: "绑定成功,请返回查看设备", icon: "none" });
+ uni.showToast({ title: t('bound_successfully_go_back_to_view_your_device'), icon: "none" });
},
});
} catch (error) {
diff --git a/src/pages/device/composables/useDeviceStatus.js b/src/pages/device/composables/useDeviceStatus.js
index 57d5b44..90550be 100644
--- a/src/pages/device/composables/useDeviceStatus.js
+++ b/src/pages/device/composables/useDeviceStatus.js
@@ -1,3 +1,4 @@
+import { t, translateStatic } from "@/locales";
import { computed, ref } from "vue";
import {
getDeviceDetailAPI,
@@ -28,8 +29,8 @@ export function useDeviceStatus({
() => isDeviceOnline.value && deviceStatus.value.charging === true
);
const statusText = computed(() => {
- if (!isDeviceOnline.value) return "未连接";
- return isDeviceCharging.value ? "已连接(充电中)" : "已连接";
+ if (!isDeviceOnline.value) return t('disconnected');
+ return isDeviceCharging.value ? t('connected_charging') : t('connected');
});
const statusClass = computed(() =>
isDeviceOnline.value ? "device-status--online" : "device-status--offline"
@@ -68,7 +69,7 @@ export function useDeviceStatus({
const totalMinutes = Math.floor(seconds / 60);
const hours = Math.floor(totalMinutes / 60);
const minutes = totalMinutes % 60;
- return hours > 0 ? `${hours}小时${minutes}分钟` : `${minutes}分钟`;
+ return hours > 0 ? t('valueh_valuemin', { p0: hours, p1: minutes }) : t('valuemin', { p0: minutes });
});
const networkType = computed(() =>
String(deviceStatus.value.netType ?? "").trim().toLowerCase()
@@ -77,18 +78,18 @@ export function useDeviceStatus({
const netType = networkType.value;
if (netType === "wifi") return "WiFi";
if (netType === "4g") return "4G";
- return isDeviceOnline.value ? "在线" : "未连接";
+ return isDeviceOnline.value ? t('online') : t('disconnected');
});
const maskedDeviceId = computed(() => {
const id = String(device.value.deviceId || "");
- if (!id) return "暂无设备编号";
+ if (!id) return t('no_device_number');
return "*****";
});
const deviceRows = computed(() => [
- { label: "设备型号", value: deviceDetails.value.model || "射灵智能弓" },
- { label: "当前电量", value: batteryText.value },
- { label: "连接方式", value: networkText.value },
- { label: "设备编号", value: maskedDeviceId.value },
+ { label: t('model'), value: deviceDetails.value.model || t('sheling_smart_bow') },
+ { label: t('battery_434'), value: translateStatic(batteryText.value) },
+ { label: t('connection'), value: networkText.value },
+ { label: t('device_number'), value: maskedDeviceId.value },
]);
const getDeviceNameOverrides = () => {
@@ -204,7 +205,7 @@ export function useDeviceStatus({
deviceDetailRequestVersion += 1;
deviceDetails.value = {};
unbindDialogVisible.value = false;
- uni.showToast({ title: "解绑成功", icon: "success" });
+ uni.showToast({ title: t('device_unbound'), icon: "success" });
} catch (error) {
console.error("解绑设备失败", error);
if (error?.type === "DEVICE_BIND_INVALID") {
diff --git a/src/pages/device/device-already-bound.vue b/src/pages/device/device-already-bound.vue
index e929828..f847cbd 100644
--- a/src/pages/device/device-already-bound.vue
+++ b/src/pages/device/device-already-bound.vue
@@ -1,4 +1,6 @@
-
+
解绑
+ >{{ t('unbind_549') }}
diff --git a/src/pages/first-try.vue b/src/pages/first-try.vue
index f66dd2a..a9b8b69 100644
--- a/src/pages/first-try.vue
+++ b/src/pages/first-try.vue
@@ -1,4 +1,6 @@
-
+
- 约上朋友开几局,欢乐多,不寂寞
- 一起练升级更快,早日加入全国排位赛!
+ {{ t('invite_friends_for_a_few_matches_and_have_fun_together') }}
+ {{ t('practice_together_level_up_faster_and_join_national_ranked_match') }}
@@ -170,22 +172,22 @@ onLoad(async (options) => {
user.nickName
}}
- 我的战绩
+ {{ t('my_results') }}
{{ data.TotalBattle }}
- 局
+ {{ t('matches') }}
- 约战数量
+ {{ t('challenges') }}
{{ data.totalArrow }}
- 箭
+ {{ t('arrows') }}
- 射箭量
+ {{ t('arrows_shot') }}
@@ -196,15 +198,15 @@ onLoad(async (options) => {
- 挑战难度
+ {{ t('challenge_difficulty') }}
-
- enterRoom(roomNumber))">进入房间
+
+ enterRoom(roomNumber))">{{ t('join_room') }}
@@ -226,9 +228,7 @@ onLoad(async (options) => {
:rounded="30"
:disabled="createRoomLoading"
:onClick="() => { $clickSound(); return onCreateRoom(); }"
- >
- 创建约战房
-
+ >{{ t('create_challenge_room') }}
@@ -243,9 +243,9 @@ onLoad(async (options) => {
diff --git a/src/pages/grade-intro.vue b/src/pages/grade-intro.vue
index 145cbf5..d466dd6 100644
--- a/src/pages/grade-intro.vue
+++ b/src/pages/grade-intro.vue
@@ -1,4 +1,6 @@
-
+
{
-
- 在射灵世界中,等级是衡量您射箭技能的重要指标,而经验则是您提升等级的关键。具体的要求如下:
+ {{ t('in_the_sheling_world_your_level_is_an_important_measure_of_your_') }}
+
+
+ {{ t('1_earning_xp') }}
+ {{ t('every_arrow_you_shoot_earns_1_xp_regardless_of_whether_it_hits_t') }}
- 一、经验的获取规则
-
- 每射出一支箭,无论是否中靶、环数高低,您将获得1点经验。这是您提升射灵等级的基本方式,每一次射箭都是您向更高目标迈进的一步。
-
-
-
-
- 二、解锁特权与玩法
-
- 当您等级达到9级时,将解锁“约战模式”。在这个模式中,您可以邀请您的好友进行切磋,与他们展开一场精彩的射箭对决。通过与好友的对抗,您不仅可以收获友谊和欢乐,还能在交流中学习到更多的技巧和经验。
-
-
- 当您等级达到16级时,将解锁“对战模式”,每次对战都是一次难得的学习机会。您可以借此机会提升自己的水平,同时也为您的好友提供帮助和建议。此外,约战模式还为您提供了展示自己技艺的平台,让您在与好友的互动中感受到射箭的乐趣和成就感。
-
-
- 未来我们将推出“押豆模式”,敬请期待!当您等级达到22级时,您可以与相同段位的玩家进行对抗,赢家将收获所有的灵豆。这不仅增加了游戏的趣味性和挑战性,还为您提供了赢取更多灵豆的机会。通过与更多玩家的对战,您可以不断提升自己的技术水平。
-
+ {{ t('2_unlocking_features_and_game_modes') }}
+ {{ t('reach_level_9_to_unlock_challenge_mode_invite_friends_for_exciti') }}
+ {{ t('reach_level_16_to_unlock_battle_mode_every_match_is_a_valuable_l') }}
+ {{ t('bean_stakes_mode_is_coming_soon_at_level_22_you_will_be_able_to_') }}
diff --git a/src/pages/index.vue b/src/pages/index.vue
index 6e34ff2..9e0d5e4 100644
--- a/src/pages/index.vue
+++ b/src/pages/index.vue
@@ -1,4 +1,6 @@
-
+
- 赛况加载中...
+ {{ t('loading_match_details') }}
{
@click="requestBattle"
>
{{ loadError }}
- 点击重新加载
+ {{ t('tap_to_reload') }}
{
class="score-header"
:style="{ border: 'none', padding: '5px 15px' }"
>
- 大乱斗
+ {{ t('free_for_all_627') }}
- 查看靶纸
+ {{ t('view_target') }}
@@ -152,9 +154,9 @@ const checkBowData = (selected) => {
:style="{ marginBottom: '5px' }"
>
@@ -181,14 +183,13 @@ const checkBowData = (selected) => {
:key="index2"
:style="{ color: arrow.ringX ? '#fed847' : '#ccc' }"
>
- {{ arrow.ringX ? "X" : `${arrow.ring}环` }}
+ {{ arrow.ringX ? "X" : t('value_pts', { p0: arrow.ring }) }}
- {{ round.shoots[team].reduce((acc, cur) => acc + cur.ring, 0) }}环
-
- 得分 {{ round.scores[team].score }}
+ {{ round.shoots[team].reduce((acc, cur) => acc + cur.ring, 0) }}{{ t('pts_580') }}
+ {{ t('score_628') }}{{ round.scores[team].score }}
diff --git a/src/pages/match-page.vue b/src/pages/match-page.vue
index f4a0417..e5c5839 100644
--- a/src/pages/match-page.vue
+++ b/src/pages/match-page.vue
@@ -1,4 +1,6 @@
-
+
diff --git a/src/pages/melee-battle.vue b/src/pages/melee-battle.vue
index be0d9a9..2ab4908 100644
--- a/src/pages/melee-battle.vue
+++ b/src/pages/melee-battle.vue
@@ -1,4 +1,6 @@
-
+
{
>{{
currentUser.arrows.length
}}支箭,共{{
+ >{{ t('arrows_total') }}{{
getRingTotal(currentUser.arrows)
}}环{{ t('pts') }}
点击顶部的“Apple ID/机主姓名” -> 进入“订阅” -> 选择“射灵星球” -> 点击“取消订阅”;或打开“App Store” -> 点击右上角头像进入“账户” -> 点击“订阅”进行管理。",
- "微信支付自动续费用户:打开微信APP -> 点击“我” -> “服务” -> “钱包” -> “支付设置” -> “自动续费” -> 选择“射灵星球小程序会员” -> 点击“关闭服务”。",
- "支付宝自动续费用户:打开支付宝APP -> 点击“我的” -> “设置” -> “支付设置” -> “免密支付/自动扣款” -> 选择“射灵星球小程序会员” -> 点击“关闭服务”。",
+ t('ios_users_apple_id_subscriptions_open_settings_your_apple_id_nam'),
+ t('wechat_pay_users_open_wechat_me_services_wallet_payment_settings'),
+ t('alipay_users_open_alipay_me_settings_payment_settings_password_f'),
],
},
{
type: "paragraph",
- text: "3.4 公司有权根据市场情况、业务规划、运营策略变化等原因单方面决定停止向您提供自动续费服务,并通过公告或站内信等方式通知您,您的付费会员服务期限自当前服务期限届满之日起终止。",
+ text: t('3_4_the_company_may_unilaterally_discontinue_auto_renewal_due_to'),
},
- { type: "heading", text: "四、服务使用规范与限制" },
+ { type: "heading", text: t('4_usage_rules_and_restrictions') },
{
type: "paragraph",
- text: "4.1 本服务及会员权益仅限您本人使用。未经公司书面同意,禁止以任何形式赠与、借用、出租、转让、售卖或以其他方式许可他人使用该账号及账号项下的会员服务与权益。如发生泄漏、遗失、被盗等行为,而该等行为并非公司过错导致,损失将由您自行承担。",
+ text: t('4_1_the_service_and_membership_benefits_are_for_your_personal_us'),
},
{
type: "paragraph",
- text: "4.2 如您存在如下违法或不当使用本服务的情形,公司有权取消您的会员资格、作废会员权益且不予退还您所支付的会员服务费用,并有权向您追偿给公司造成的损失:",
+ text: t('4_2_if_you_use_the_service_unlawfully_or_improperly_in_any_of_th'),
},
{
type: "list",
items: [
- "以盗窃、利用系统漏洞、通过任何非公司官方或授权渠道获得本服务的行为;",
- "利用本服务进行盈利或非法获利,或以各种形式转让、借用您的会员权益;",
- "通过非法手段对本服务会员账户的服务期限、交易状态进行修改或篡改;",
- "主动对公司用于保护本服务会员权益的任何安全措施技术进行破解、更改、反操作或破坏;",
- "其他违反法律法规、诚实信用原则、服务协议及相关小程序运营规则的行为。",
+ t('obtaining_the_service_through_theft_system_vulnerabilities_or_an'),
+ t('using_the_service_for_profit_or_unlawful_gain_or_transferring_or'),
+ t('illegally_modifying_or_tampering_with_a_membership_account_s_ser'),
+ t('cracking_modifying_reverse_operating_or_damaging_security_measur'),
+ t('other_conduct_that_violates_laws_good_faith_service_agreements_o'),
],
},
- { type: "heading", text: "五、服务中止、终止及变更" },
+ { type: "heading", text: t('5_suspension_termination_and_changes') },
{
type: "paragraph",
- text: "5.1 因国家或相关政府监管部门要求、发生不可抗力事件、或由于用户违反本协议约定,公司有权中止或终止向用户提供服务。",
+ text: t('5_1_the_company_may_suspend_or_terminate_services_when_required_'),
},
{
type: "paragraph",
- text: "5.2 您知悉并确认,您开通本服务后,如您中途主动取消本服务、放弃会员权益或终止资格,您将无法退还部分或全部会员服务费用。本协议终止后,用户无权要求公司继续向其提供任何服务,且不影响终止前基于本协议已产生的权利义务。",
+ text: t('5_2_you_acknowledge_that_if_you_voluntarily_cancel_the_service_g'),
},
{
type: "paragraph",
- text: "5.3 公司可根据国家法律法规变化、业务实际变更需求、保护用户权益的需要等,不时修改本协议,并按照法律法规规定的程序及方式进行公告。如用户不同意变更后的内容,则用户有权主动停止使用本服务;如用户在变更内容生效后仍继续使用本服务,即视为用户同意该等内容的变更。",
+ text: t('5_3_the_company_may_amend_this_agreement_as_laws_business_needs_'),
},
- { type: "heading", text: "六、责任限制与免责条款" },
+ { type: "heading", text: t('6_limitation_of_liability_and_disclaimers') },
{
type: "paragraph",
- text: "6.1 您理解并同意,本服务是按照现有技术和条件所能达到的现状提供的。公司将尽最大努力确保服务的连贯性和安全性,但不能随时预见和防范技术以及其他风险,包括但不限于不可抗力、网络原因、第三方服务瑕疵等原因可能导致的服务中断、数据丢失以及其他的损失和风险。",
+ text: t('6_1_you_understand_and_agree_that_the_service_is_provided_as_ava'),
},
{
type: "paragraph",
- text: "6.2 基于收益与赔偿相一致及公平合理的原则,如因公司原因造成本服务不正常中断或服务不可用,您所可能获得的最高赔偿额不超过本协议项下公司就该计费周期已实际收取您的相关服务费用总额。",
+ text: t('6_2_under_the_principles_of_proportionality_and_fairness_if_the_'),
},
- { type: "heading", text: "七、法律适用与争议解决" },
+ { type: "heading", text: t('7_governing_law_and_dispute_resolution') },
{
type: "paragraph",
- text: "7.1 本协议的成立、生效、履行、解释及争议的解决均应适用中华人民共和国法律。",
+ text: t('7_1_the_formation_effectiveness_performance_interpretation_and_d'),
},
{
type: "paragraph",
- text: "7.2 本协议的签订地为广东省广州市南沙区。若您因本协议与公司发生任何争议,双方应尽量友好协商解决;如协商不成的,任何一方均同意应将相关争议提交至本协议签订地有管辖权的人民法院诉讼解决。",
+ text: t('7_2_this_agreement_is_entered_into_in_nansha_district_guangzhou_'),
},
{
type: "paragraph",
- text: "7.3 本协议任一条款被视为废止、无效或不可执行,该条应视为可分的且并不影响本协议其余条款的有效性及可执行性。",
+ text: t('7_3_if_any_provision_is_held_repealed_invalid_or_unenforceable_i'),
},
],
- company: "广州光点飞舞网络有限公司",
+ company: t('guangzhou_guangdian_feiwu_network_co_ltd'),
},
deduct: {
- navTitle: "扣款授权服务协议",
- title: "扣费授权服务协议",
- meta: "版本号:V1.0 生效日期:2026年6月22日",
+ navTitle: t('payment_authorization_agreement'),
+ title: t('payment_authorization_agreement_702'),
+ meta: t('version_v1_0_effective_date_june_22_2026'),
content: [
- { type: "heading", text: "一、授权声明" },
+ { type: "heading", text: t('1_authorization_statement') },
{
type: "paragraph",
- text: "本人(即授权人,以下简称“乙方”)作为射灵星球小程序的注册用户,在自愿、平等、知悉全部授权内容的基础上,同意向广州光点飞舞网络有限公司(以下简称“甲方”)及甲方委托的第三方支付机构(包含微信支付、支付宝、苹果支付等,以下简称“支付机构”)作出本扣费授权,双方就授权扣费相关事宜达成如下协议。",
+ text: t('as_a_registered_user_of_the_sheling_planet_mini_program_i_the_au'),
},
- { type: "heading", text: "二、授权主体" },
+ { type: "heading", text: t('2_parties_to_the_authorization') },
{
type: "paragraph",
- text: "授权人(乙方):射灵星球小程序注册用户,用户ID以平台系统记录为准。",
+ text: t('authorizing_party_party_b_a_registered_sheling_planet_mini_progr'),
},
{
type: "paragraph",
- text: "被授权人(甲方):广州光点飞舞网络有限公司,作为会员服务提供方及扣费指令发起方。",
+ text: t('authorized_party_party_a_guangzhou_guangdian_feiwu_network_co_lt'),
},
{
type: "paragraph",
- text: "支付执行方:乙方绑定的第三方支付机构,受甲方委托执行扣费操作。",
+ text: t('payment_processor_the_third_party_payment_provider_linked_by_par'),
},
- { type: "heading", text: "三、授权内容" },
+ { type: "heading", text: t('3_scope_of_authorization') },
{
type: "paragraph",
- text: "授权场景:乙方开通射灵星球会员自动续费服务后,授权甲方在每个会员周期届满前,向支付机构发起扣费指令,用于支付下一周期的会员服务费用。",
+ text: t('authorized_purpose_after_party_b_activates_sheling_planet_member'),
},
{
type: "paragraph",
- text: "授权金额:扣费金额以乙方开通时选择的自动续费套餐对应价格为准,具体以会员购买页面公示价格为准;若价格调整,甲方将提前通过公示或通知形式告知乙方,乙方继续使用服务视为认可并接受调整后的金额。",
+ text: t('authorized_amount_the_amount_is_the_price_of_the_auto_renewal_pl'),
},
{
type: "paragraph",
- text: "授权支付账户:乙方开通自动续费时绑定的微信支付、支付宝等第三方支付账户,账户信息以支付机构记录为准。",
+ text: t('authorized_account_the_third_party_payment_account_such_as_wecha'),
},
{
type: "paragraph",
- text: "授权扣费次数:本授权为周期性授权。在授权有效期内,甲方可按会员周期重复发起扣费指令,直至乙方依法撤销授权为止。",
+ text: t('authorized_frequency_this_is_a_recurring_authorization_during_it'),
},
- { type: "heading", text: "四、授权有效期" },
+ { type: "heading", text: t('4_authorization_period') },
{
type: "paragraph",
- text: "1. 本授权自乙方点击确认开通自动续费服务之日起生效,至乙方成功取消自动续费服务之日终止。",
+ text: t('1_this_authorization_takes_effect_when_party_b_confirms_activati'),
},
{
type: "paragraph",
- text: "2. 若乙方注销射灵星球小程序账号,本授权自账号注销完成之日自动终止。",
+ text: t('2_if_party_b_closes_their_sheling_planet_mini_program_account_th'),
},
{
type: "paragraph",
- text: "3. 若因国家政策调整、支付机构规则变更、乙方支付账户注销/冻结等非甲方主观原因导致授权无法履行的,本授权自动终止。",
+ text: t('3_this_authorization_ends_automatically_if_changes_in_national_p'),
},
- { type: "heading", text: "五、扣费与提醒规则" },
+ { type: "heading", text: t('5_payments_and_reminders') },
{
type: "paragraph",
- text: "1. 扣费提醒:甲方将在每个自动续费扣费日期前5日,通过微信服务通知、小程序系统消息或短信等显著方式提示乙方即将发生续期扣费的信息,以保障乙方的知情权与选择权。",
+ text: t('1_reminder_party_a_will_prominently_notify_party_b_of_upcoming_r'),
},
{
type: "paragraph",
- text: "2. 扣费时机:甲方将在乙方当前会员有效期届满前24小时内发起下一周期的扣费指令,支付机构根据指令从乙方授权账户中划扣对应费用。",
+ text: t('2_timing_party_a_will_issue_instructions_for_the_next_cycle_with'),
},
{
type: "paragraph",
- text: "3. 扣费失败处理:若因账户余额不足等原因导致首次扣费失败的,甲方及支付机构可在合规范围内依法尝试补扣;若补扣仍失败或账户处于异常状态的,本期自动续费暂停,乙方会员到期后自动失效。",
+ text: t('3_failed_payments_if_the_first_attempt_fails_due_to_insufficient'),
},
{
type: "paragraph",
- text: "4. 扣费凭证:支付机构的扣费记录作为扣费成功的有效凭证,乙方可在支付账户账单中查询明细;甲方同步为乙方提供电子扣费记录,可在会员中心查看。",
+ text: t('4_proof_the_payment_provider_s_debit_record_is_valid_proof_of_su'),
},
- { type: "heading", text: "六、授权的变更与撤销" },
+ { type: "heading", text: t('6_changes_and_revocation') },
{
type: "paragraph",
- text: "1. 授权变更:本授权内容如需变更(如更换支付账户、调整续费套餐),乙方需先取消原自动续费服务,再重新开通新套餐。新授权自重新开通成功之日起生效,原授权同步终止。",
+ text: t('1_changes_to_change_this_authorization_such_as_the_payment_accou'),
},
{
type: "paragraph",
- text: "2. 授权撤销:乙方可随时退订本自动续费服务,解约后不影响乙方已生效周期的会员服务。根据乙方开通时选择的支付执行方,具体撤销路径如下:",
+ text: t('2_revocation_party_b_may_cancel_auto_renewal_at_any_time_without'),
},
{
type: "list",
items: [
- "微信支付用户:可通过微信APP内(路径:我 -> 服务 -> 钱包 -> 支付设置 -> 自动续费)或在小程序会员中心页面撤销本授权。",
- "支付宝用户:可通过支付宝APP内(路径:我的 -> 设置 -> 支付设置 -> 免密支付/自动扣款)或在小程序会员中心页面撤销本授权。",
- "苹果支付(iOS/App Store订阅)用户:必须通过苹果系统自带的功能进行取消(路径:iOS设备“设置” -> 点击顶部的Apple ID -> 订阅 -> 选择“射灵星球” -> 取消订阅)。",
+ t('wechat_pay_revoke_authorization_in_wechat_me_services_wallet_pay'),
+ t('alipay_revoke_authorization_in_alipay_me_settings_payment_settin'),
+ t('apple_payments_ios_app_store_subscriptions_cancellation_must_be_'),
],
},
{
type: "paragraph",
- text: "3. 退订生效时效:",
+ text: t('3_when_cancellation_takes_effect'),
},
{
type: "list",
items: [
- "针对微信支付和支付宝:撤销操作成功后,本授权即时终止,甲方不得再发起新的扣费指令。因第三方支付平台系统结算延迟等客观原因,导致退订生效前系统已自动扣款成功的,该期会员权益将正常发放,已扣费用原则上不予退还。",
- "针对苹果支付:根据苹果公司政策,乙方需在当前计费周期届满前至少24小时手动取消订阅,否则苹果系统可能会自动续订并扣款。苹果渠道的扣费与退款均由苹果公司独立处理,甲方无权干涉,因乙方未及时取消导致扣费的,由乙方自行承担或向苹果公司申诉。",
+ t('wechat_pay_and_alipay_authorization_ends_immediately_after_succe'),
+ t('apple_payments_under_apple_s_policies_party_b_must_manually_canc'),
],
},
- { type: "heading", text: "七、免责条款" },
+ { type: "heading", text: t('7_disclaimers') },
{
type: "paragraph",
- text: "1. 因乙方支付账户余额不足、账户冻结、挂失、注销、限额等非甲方原因导致扣费失败的,甲方不承担任何责任,由此造成的会员权益中断等后果由乙方自行承担。",
+ text: t('1_party_a_is_not_liable_for_failed_payments_caused_by_insufficie'),
},
{
type: "paragraph",
- text: "2. 因支付机构系统故障、网络中断、政策调整等第三方不可抗力或外部原因导致扣费延迟、失败或错误的,甲方将协助乙方协调解决,但不承担相应的赔偿责任。",
+ text: t('2_for_delayed_failed_or_incorrect_payments_caused_by_payment_pro'),
},
{
type: "paragraph",
- text: "3. 因乙方泄露支付账户密码、账号被盗用等自身保管不当原因导致的异常扣费,甲方不承担责任,乙方应自行向支付机构或公安机关主张权利。",
+ text: t('3_party_a_is_not_liable_for_abnormal_payments_caused_by_party_b_'),
},
- { type: "heading", text: "八、信息保密" },
+ { type: "heading", text: t('8_confidentiality') },
{
type: "paragraph",
- text: "1. 甲方及支付机构应对乙方的授权信息、支付信息、个人身份信息严格保密,不得用于本授权以外的任何用途。",
+ text: t('1_party_a_and_the_payment_providers_must_keep_party_b_s_authoriz'),
},
{
type: "paragraph",
- text: "2. 除法律法规规定、司法机关或监管部门依法要求外,甲方不得向任何第三方泄露乙方的授权及支付相关信息。",
+ text: t('2_except_as_required_by_law_or_lawfully_requested_by_judicial_or'),
},
- { type: "heading", text: "九、争议解决" },
+ { type: "heading", text: t('9_dispute_resolution') },
{
type: "paragraph",
- text: "1. 本授权协议的订立、效力、履行及争议解决均适用中华人民共和国法律。",
+ text: t('1_the_formation_validity_performance_and_dispute_resolution_of_t'),
},
{
type: "paragraph",
- text: "2. 因本协议产生的任何争议,双方应尽量友好协商解决;协商不成的,任何一方均可向甲方住所地(广东省广州市天河区)有管辖权的人民法院提起诉讼。",
+ text: t('2_disputes_should_first_be_resolved_through_friendly_negotiation'),
},
- { type: "heading", text: "十、其他" },
+ { type: "heading", text: t('10_other_provisions') },
{
type: "paragraph",
- text: "1. 本协议为《射灵星球小程序会员服务协议》的配套协议,与该协议具有同等法律效力;本协议未约定事项,参照主协议执行。",
+ text: t('1_this_agreement_supplements_the_sheling_planet_mini_program_mem'),
},
{
type: "paragraph",
- text: "2. 甲方有权根据业务及监管要求调整本协议内容,调整后的协议将在平台公示,乙方继续使用自动续费服务视为接受调整后的内容。",
+ text: t('2_party_a_may_adjust_this_agreement_to_meet_business_and_regulat'),
},
{
type: "paragraph",
- text: "3. 甲方客服联系方式:请通过射灵星球小程序内【在线客服】或发送邮件至官方客服邮箱进行反馈。",
+ text: t('3_customer_support_contact_online_support_in_the_sheling_planet_'),
},
],
- company: "广州光点飞舞网络有限公司",
+ company: t('guangzhou_guangdian_feiwu_network_co_ltd'),
},
};
diff --git a/src/pages/member/be-vip.vue b/src/pages/member/be-vip.vue
index 7e1c758..9ebadc3 100644
--- a/src/pages/member/be-vip.vue
+++ b/src/pages/member/be-vip.vue
@@ -1,4 +1,6 @@
-
+
{
{{ data.vipName }}
- 订单号:{{ data.orderId }}
+ {{ t('order_no') }}{{ data.orderId }}
复制{{ t('copy') }}
- 创建时间:{{ data.orderCreateAt }}
- 支付时间:{{
+ {{ t('created') }}{{ data.orderCreateAt }}
+ {{ t('paid_788') }}{{
data.orderStatus === 4 ? data.paymentTime : ""
}}
- 金额:{{ data.total }} 元
- 支付方式:微信
+ {{ t('amount') }}{{ data.total }}{{ t('cny') }}
+ {{ t('payment_method_wechat_pay') }}
- 去支付
+ {{ t('pay_now') }}
- 取消订单
+ {{ t('cancel_order') }}
diff --git a/src/pages/member/orders.vue b/src/pages/member/orders.vue
index 5ddd8fe..33108a4 100644
--- a/src/pages/member/orders.vue
+++ b/src/pages/member/orders.vue
@@ -1,4 +1,6 @@
-
+
{
>{{ orderStatusNames[item.orderStatus] }}
{{ item.vipName }}
- 订单号:{{ item.orderId }}
- 创建时间:{{ item.orderCreateAt }}
+ {{ t('order_no') }}{{ item.orderId }}
+ {{ t('created') }}{{ item.orderCreateAt }}
- 金额:{{ item.total }} 元
+ {{ t('amount') }}{{ item.total }}{{ t('cny') }}
@@ -1463,9 +1465,9 @@ onShow(() => {
:onClose="() => (showOfflineModal = false)"
>
- 设备已离线
- 检测到设备已断开连接,请检查设备后继续比赛
- 我知道了
+ {{ t('device_is_offline') }}
+ {{ t('your_device_has_disconnected_check_it_before_continuing_the_matc') }}
+ {{ t('got_it') }}
diff --git a/src/pages/team-battle/team-bow-data.vue b/src/pages/team-battle/team-bow-data.vue
index 1a661cc..33f75c8 100644
--- a/src/pages/team-battle/team-bow-data.vue
+++ b/src/pages/team-battle/team-bow-data.vue
@@ -1,4 +1,6 @@
-
+
+import { t, translateStatic } from "@/locales";
+
import { ref } from "vue";
import { onLoad } from "@dcloudio/uni-app";
import Container from "@/components/Container.vue";
@@ -30,8 +32,8 @@ onLoad(async (options) => {
players.value.push(data.value.teams[2].players[index]);
});
Object.values(data.value.rounds).forEach((round, index) => {
- if (round.ifGold) tabs.value.push(`决金箭`);
- else tabs.value.push(`第${roundsName[index + 1]}轮`);
+ if (round.ifGold) tabs.value.push(t('golden_arrow', { }));
+ else tabs.value.push(t('round_value', { p0: translateStatic(roundsName[index + 1]) }));
});
selected.value = Number(options.selected || 0);
onClickTab(selected.value);
@@ -45,7 +47,7 @@ const onClickTab = (index) => {
-
+
+import { t } from "@/locales";
+
import { computed } from "vue";
import AppBackground from "@/components/AppBackground.vue";
import Avatar from "@/components/Avatar.vue";
@@ -67,9 +69,9 @@ const props = defineProps({
{{ arrows.length }}
- 支箭,共
+ {{ t('arrows_total') }}
{{ arrows.reduce((a, b) => a + (b.ring || 0), 0) }}
- 环
+ {{ t('pts') }}
+import { t } from "@/locales";
+
import {
computed,
getCurrentInstance,
@@ -558,7 +560,7 @@ onBeforeUnmount(() => {
- 中场休息
+ {{ t('halftime') }}
- 经验 +1
-
+ >{{ t('xp_1') }}
{{ latestOne.ringX ? "X" : latestOne.ring || "未上靶"
- }}环
+ >{{ latestOne.ringX ? "X" : latestOne.ring || t('miss')
+ }}{{ t('pts') }}
- 经验 +1
-
+ >{{ t('xp_1') }}
{{ bluelatestOne.ringX ? "X" : bluelatestOne.ring || "未上靶"
- }}环{{ bluelatestOne.ringX ? "X" : bluelatestOne.ring || t('miss')
+ }}{{ t('pts') }}
{
/>
-
-
-
-
+
+
+
+
diff --git a/src/pages/training/components/ScoreResult.vue b/src/pages/training/components/ScoreResult.vue
index 15c65e2..44f6556 100644
--- a/src/pages/training/components/ScoreResult.vue
+++ b/src/pages/training/components/ScoreResult.vue
@@ -1,4 +1,6 @@
-
+
+import { t } from "@/locales";
+
import { ref, onMounted, onBeforeUnmount } from "vue";
import Guide from "@/components/Guide.vue";
import BowPower from "@/components/BowPower.vue";
@@ -144,16 +146,14 @@ onBeforeUnmount(() => {
@click="simulShoot"
hover-class="none"
v-if="showsimul"
- >
- 模拟射箭
-
+ >{{ t('simulate_shot') }}
- 当前靶纸为{{ targetType }}cm全环靶
+ {{ t('current_target') }}{{ targetType }}cm{{ t('full_ring_target') }}
{{ statusText }}
- 请射箭,测试站距与靶纸
+ {{ t('shoot_to_check_distance_and_target_face') }}
@@ -164,11 +164,11 @@ onBeforeUnmount(() => {
- 距离正式比赛还有
+ {{ t('match_starts_in') }}
{{ count }}
- 秒
+ {{ t('s') }}
- 进入中...
+ {{ t('joining') }}
diff --git a/src/pages/training/components/TrainingDifficultyStartButton.vue b/src/pages/training/components/TrainingDifficultyStartButton.vue
index 164d9b4..0da8548 100644
--- a/src/pages/training/components/TrainingDifficultyStartButton.vue
+++ b/src/pages/training/components/TrainingDifficultyStartButton.vue
@@ -1,8 +1,10 @@
-
+
- {{ user.nickName }}
-
+ {{ user.nickName }}
+
- 已完成
- 未完成
+ {{ t('completed_260') }}
+ {{ t('incomplete') }}
{{ storeVipLabel }}
@@ -169,7 +171,7 @@ const buildVersion = typeof __BUILD_TIME__ !== 'undefined' ? __BUILD_TIME__ : ''
未开通
-->
-
+
Lv{{ user.lvl }}
{{ user.lvlPoints }}
- 经验
+ {{ t('xp_582') }}
- {{ user.rankName || "暂无段位" }}
+ {{ user.rankName || t('unranked_1010') }}
- 暂无段位
+ {{ t('unranked_1010') }}
-
+
{{ buildVersion }}
diff --git a/src/store.js b/src/store.js
index 3774d66..9b5ba8b 100644
--- a/src/store.js
+++ b/src/store.js
@@ -313,6 +313,16 @@ export default defineStore("store", {
// 仅持久化 user 和 device:身份凭证需在冷启动时恢复(如从分享链接进入)
// config、game 等运行时状态不持久化,每次联网后重新拉取
persist: {
+ // 固定英文版只淘汰旧中文段位显示名,保留身份、段位数值、成绩和图片。
+ // config / 榜单不持久化,仍由原有请求流程获取最新英文配置。
+ afterRestore: ({ store }) => {
+ for (const field of ["lvlName", "rankName", "nextRankName"]) {
+ const value = store.user?.[field];
+ if (typeof value === "string" && /[\u3400-\u9fff]/.test(value)) {
+ store.user[field] = "";
+ }
+ }
+ },
storage: {
getItem: (key) => uni.getStorageSync(key),
setItem: (key, value) => uni.setStorageSync(key, value),
diff --git a/src/util.js b/src/util.js
index 53f6f1b..a96a0b0 100644
--- a/src/util.js
+++ b/src/util.js
@@ -1,3 +1,4 @@
+import { t, translateStatic } from "@/locales";
export const formatTimestamp = (timestamp) => {
const date = new Date(timestamp);
const year = date.getFullYear();
@@ -32,7 +33,7 @@ export const getLimitCountText = (label, item = {}) => {
if (!item || isUnlimitedLimit(item)) return "";
const count = Number(item.count || 0);
const limit = Number(item.limit || 0);
- return `今日${label}次数:${count}/${limit}`;
+ return t('today_s_value_value_value', { p0: label, p1: count, p2: limit });
};
export const isLimitReached = (item = {}) => {
@@ -371,10 +372,10 @@ export const getDistanceCheckAudioKey = (shootData) => {
export const getDistanceCheckText = (shootData) => {
const result = getShootValidation(shootData);
- if (!result.targetDetected) return "未识别到靶纸,请瞄准靶纸射箭";
- if (result.rawDistance < 0) return "靶纸错误";
- return `${result.distanceOk ? "站距合格" : "站距过近"},${
- result.targetOk ? "靶纸正确" : "靶纸错误"
+ if (!result.targetDetected) return t('no_target_detected_aim_at_the_target_and_shoot');
+ if (result.rawDistance < 0) return t('incorrect_target_face');
+ return `${result.distanceOk ? t('distance_ok') : t('too_close')}; ${
+ result.targetOk ? t('target_face_ok') : t('incorrect_target_face')
}`;
};
@@ -391,7 +392,7 @@ export const getInvalidShotAudioKey = (shootData) => {
};
export const getInvalidShotText = (shootData) =>
- getInvalidShotAudioKey(shootData);
+ translateStatic(getInvalidShotAudioKey(shootData));
export const wxLogin = () => {
return new Promise((resolve, reject) => {
@@ -400,7 +401,7 @@ export const wxLogin = () => {
success: resolve,
fail: (err) => {
uni.showToast({
- title: "登录失败",
+ title: t('sign_in_failed'),
icon: "none",
});
console.error("登录失败:", err);
@@ -414,7 +415,7 @@ export const canEenter = (user, device, online, page = "") => {
const { miniProgram } = uni.getAccountInfoSync();
if (!device.deviceId) {
uni.showToast({
- title: "请先绑定设备",
+ title: t('please_bind_a_device_first'),
icon: "none",
});
return false;
@@ -422,14 +423,14 @@ export const canEenter = (user, device, online, page = "") => {
if (miniProgram.envVersion !== "release") return true;
if (!online) {
uni.showToast({
- title: "智能弓未连接",
+ title: t('smart_bow_disconnected'),
icon: "none",
});
return false;
}
if (!user.trio && page !== "/pages/first-try") {
uni.showToast({
- title: "请先完成新手试炼",
+ title: t('please_complete_the_beginner_challenge_first'),
icon: "none",
});
return false;
diff --git a/src/utils/matchReturn.js b/src/utils/matchReturn.js
index 242fd84..c089ce2 100644
--- a/src/utils/matchReturn.js
+++ b/src/utils/matchReturn.js
@@ -1,3 +1,4 @@
+import { t } from "@/locales";
export const MATCH_RETURN_SNAPSHOT_KEY = "match-return-snapshot";
function getMatchId(battleInfo) {
@@ -22,7 +23,7 @@ export async function returnToBattle(battleInfo, navigate) {
const matchId = getMatchId(battleInfo);
if (!battleInfo || !matchId || !battleInfo.serverAddr) {
uni.showToast({
- title: "比赛连接信息异常",
+ title: t('invalid_match_connection'),
icon: "none",
});
return false;