@jx3box/jx3box-ui 2.3.20 → 2.3.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/css/wiki/wiki-comments.less +244 -0
- package/assets/css/wiki/wiki-panel.less +291 -0
- package/assets/css/wiki/wiki-revisions.less +78 -0
- package/assets/img/common/jx3-origin.svg +138 -15
- package/assets/img/common/jx3-www.svg +75 -9
- package/i18n/messages/en-US.js +3 -1
- package/i18n/messages/vi.js +8 -1
- package/i18n/messages/zh-CN.js +3 -1
- package/i18n/messages/zh-TW.js +3 -1
- package/package.json +2 -1
- package/src/App.vue +53 -10
- package/src/header/client.vue +4 -4
- package/src/interact/QRcode.vue +21 -3
- package/src/wiki/GamePrice.vue +68 -11
- package/src/wiki/WikiComment.vue +46 -15
- package/src/wiki/WikiComments.vue +19 -4
- package/src/wiki/WikiPanel.vue +22 -4
- package/src/wiki/WikiRevisions.vue +6 -1
- package/tests/wiki-i18n-contract.test.js +113 -0
package/src/header/client.vue
CHANGED
|
@@ -305,15 +305,15 @@ export default {
|
|
|
305
305
|
.u-game__icon {
|
|
306
306
|
.flex(x);
|
|
307
307
|
flex: 0 0 auto;
|
|
308
|
-
width:
|
|
309
|
-
height:
|
|
308
|
+
width: 20px;
|
|
309
|
+
height: 20px;
|
|
310
310
|
margin-right: 12px;
|
|
311
311
|
|
|
312
312
|
&,
|
|
313
313
|
svg,
|
|
314
314
|
img {
|
|
315
|
-
width:
|
|
316
|
-
height:
|
|
315
|
+
width: 20px !important;
|
|
316
|
+
height: 20px !important;
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
svg,
|
package/src/interact/QRcode.vue
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div ref="trigger" class="w-qrcode" v-bind="$attrs" @click="togglePic" v-if="mode == 'cms'">
|
|
3
3
|
<img class="u-icon" svg-inline src="../../assets/img/widget/qr-code.svg" />
|
|
4
|
-
<span class="u-text"
|
|
4
|
+
<span class="u-text">{{ triggerText }}</span>
|
|
5
5
|
</div>
|
|
6
6
|
<teleport to="body">
|
|
7
|
-
<div
|
|
7
|
+
<div
|
|
8
|
+
v-if="mode == 'cms' && active"
|
|
9
|
+
class="u-qrcode u-qrcode-popup w-qrcode-static"
|
|
10
|
+
:class="popupClass"
|
|
11
|
+
:style="popupStyle"
|
|
12
|
+
@click.stop
|
|
13
|
+
>
|
|
8
14
|
<qrcode-vue class="u-pic" :value="value" :size="size" level="H"></qrcode-vue>
|
|
9
|
-
<span class="u-txt"
|
|
15
|
+
<span class="u-txt">{{ popupText }}</span>
|
|
10
16
|
</div>
|
|
11
17
|
</teleport>
|
|
12
18
|
<div class="w-qrcode-static" v-bind="$attrs" v-if="mode == 'static'">
|
|
@@ -38,6 +44,18 @@ export default {
|
|
|
38
44
|
type: Number,
|
|
39
45
|
default: 100,
|
|
40
46
|
},
|
|
47
|
+
triggerText: {
|
|
48
|
+
type: String,
|
|
49
|
+
default: "二维码",
|
|
50
|
+
},
|
|
51
|
+
popupText: {
|
|
52
|
+
type: String,
|
|
53
|
+
default: "扫一扫即可访问",
|
|
54
|
+
},
|
|
55
|
+
popupClass: {
|
|
56
|
+
type: [String, Array, Object],
|
|
57
|
+
default: "",
|
|
58
|
+
},
|
|
41
59
|
},
|
|
42
60
|
data: function () {
|
|
43
61
|
return {
|
package/src/wiki/GamePrice.vue
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<span class="c-game-price" :class="
|
|
2
|
+
<span class="c-game-price" :class="rootClasses">
|
|
3
3
|
<span class="u-neg" v-if="numericPrice < 0">- </span>
|
|
4
4
|
<span class="u-price">
|
|
5
5
|
<template v-for="part in priceParts" :key="part.unit">
|
|
6
6
|
<span class="u-part" :class="`u-${part.unit}`">
|
|
7
7
|
<span class="u-price-value">{{ part.value }}</span>
|
|
8
|
-
<img :src="part.icon" :alt="part.alt" />
|
|
8
|
+
<img :src="part.icon" :alt="$jx3boxT(`jx3boxUi.gamePrice.${part.unit}`, part.alt)" />
|
|
9
9
|
</span>
|
|
10
10
|
</template>
|
|
11
11
|
</span>
|
|
@@ -36,16 +36,38 @@ export default {
|
|
|
36
36
|
type: [Boolean, String],
|
|
37
37
|
default: false,
|
|
38
38
|
},
|
|
39
|
+
variant: {
|
|
40
|
+
type: String,
|
|
41
|
+
default: "default",
|
|
42
|
+
validator: (value) => ["default", "surface", "plain"].includes(value),
|
|
43
|
+
},
|
|
44
|
+
size: {
|
|
45
|
+
type: String,
|
|
46
|
+
default: "medium",
|
|
47
|
+
validator: (value) => ["small", "medium", "large"].includes(value),
|
|
48
|
+
},
|
|
49
|
+
layout: {
|
|
50
|
+
type: String,
|
|
51
|
+
default: "inline",
|
|
52
|
+
validator: (value) => ["inline", "block"].includes(value),
|
|
53
|
+
},
|
|
54
|
+
wrap: {
|
|
55
|
+
type: Boolean,
|
|
56
|
+
default: true,
|
|
57
|
+
},
|
|
39
58
|
},
|
|
40
59
|
computed: {
|
|
41
60
|
numericPrice() {
|
|
42
61
|
const value = Number(this.price);
|
|
43
62
|
return Number.isFinite(value) ? Math.trunc(value) : 0;
|
|
44
63
|
},
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
if (
|
|
48
|
-
|
|
64
|
+
rootClasses() {
|
|
65
|
+
const classes = [`is-${this.variant}`, `is-size-${this.size}`, `is-layout-${this.layout}`];
|
|
66
|
+
if (this.align === true) classes.push("is-align");
|
|
67
|
+
if (typeof this.align === "string" && this.align) classes.push(`is-${this.align}`);
|
|
68
|
+
if (!this.wrap) classes.push("is-nowrap");
|
|
69
|
+
if (this.numericPrice < 0) classes.push("is-negative");
|
|
70
|
+
return classes;
|
|
49
71
|
},
|
|
50
72
|
priceParts() {
|
|
51
73
|
const value = Math.abs(this.numericPrice);
|
|
@@ -75,21 +97,28 @@ export default {
|
|
|
75
97
|
|
|
76
98
|
<style lang="less">
|
|
77
99
|
.c-game-price {
|
|
100
|
+
--jx3box-ui-game-price-color: #333;
|
|
101
|
+
--jx3box-ui-game-price-icon-size: 18px;
|
|
102
|
+
--jx3box-ui-game-price-font-size: 12px;
|
|
103
|
+
--jx3box-ui-game-price-gap: 6px;
|
|
104
|
+
--jx3box-ui-game-price-negative-color: var(--jx3box-ui-game-price-color);
|
|
105
|
+
|
|
78
106
|
display: inline-flex;
|
|
79
107
|
align-items: center;
|
|
80
|
-
color:
|
|
108
|
+
color: var(--jx3box-ui-game-price-color);
|
|
81
109
|
font-weight: 500;
|
|
82
110
|
|
|
83
111
|
.u-price {
|
|
84
112
|
display: inline-flex;
|
|
85
113
|
align-items: center;
|
|
86
114
|
flex-wrap: wrap;
|
|
87
|
-
gap:
|
|
115
|
+
gap: var(--jx3box-ui-game-price-gap);
|
|
88
116
|
}
|
|
89
117
|
|
|
90
118
|
.u-neg {
|
|
91
119
|
display: inline-flex;
|
|
92
120
|
align-items: center;
|
|
121
|
+
color: var(--jx3box-ui-game-price-negative-color);
|
|
93
122
|
}
|
|
94
123
|
|
|
95
124
|
.u-part {
|
|
@@ -100,14 +129,15 @@ export default {
|
|
|
100
129
|
}
|
|
101
130
|
|
|
102
131
|
img {
|
|
103
|
-
width:
|
|
104
|
-
height:
|
|
132
|
+
width: var(--jx3box-ui-game-price-icon-size);
|
|
133
|
+
height: var(--jx3box-ui-game-price-icon-size);
|
|
105
134
|
object-fit: contain;
|
|
106
135
|
vertical-align: middle;
|
|
107
136
|
}
|
|
108
137
|
|
|
109
138
|
.u-price-value {
|
|
110
|
-
|
|
139
|
+
font-size: var(--jx3box-ui-game-price-font-size);
|
|
140
|
+
line-height: var(--jx3box-ui-game-price-icon-size);
|
|
111
141
|
}
|
|
112
142
|
|
|
113
143
|
&.is-align {
|
|
@@ -130,5 +160,32 @@ export default {
|
|
|
130
160
|
justify-content: flex-end;
|
|
131
161
|
width: 100%;
|
|
132
162
|
}
|
|
163
|
+
|
|
164
|
+
&.is-size-small {
|
|
165
|
+
--jx3box-ui-game-price-icon-size: 14px;
|
|
166
|
+
--jx3box-ui-game-price-font-size: 11px;
|
|
167
|
+
--jx3box-ui-game-price-gap: 4px;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
&.is-size-large {
|
|
171
|
+
--jx3box-ui-game-price-icon-size: 22px;
|
|
172
|
+
--jx3box-ui-game-price-font-size: 14px;
|
|
173
|
+
--jx3box-ui-game-price-gap: 8px;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
&.is-layout-block {
|
|
177
|
+
display: flex;
|
|
178
|
+
width: 100%;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
&.is-nowrap {
|
|
182
|
+
.u-price {
|
|
183
|
+
flex-wrap: nowrap;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
&.is-surface {
|
|
188
|
+
--jx3box-ui-game-price-color: #334155;
|
|
189
|
+
}
|
|
133
190
|
}
|
|
134
191
|
</style>
|
package/src/wiki/WikiComment.vue
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
v-text="comment.user_nickname"
|
|
12
12
|
></a>
|
|
13
13
|
<template v-if="comment.parent_id">
|
|
14
|
-
<span> 
|
|
14
|
+
<span> {{ $jx3boxT("jx3boxUi.wiki.reply", "回复") }} </span>
|
|
15
15
|
<a
|
|
16
16
|
class="u-nickname"
|
|
17
17
|
:href="comment.parent.user_id ? author_url(comment.parent.user_id) : null"
|
|
@@ -21,11 +21,11 @@
|
|
|
21
21
|
</template>
|
|
22
22
|
<span class="u-mark u-top" v-if="comment.is_top">
|
|
23
23
|
<i class="el-icon-download"></i>
|
|
24
|
-
置顶
|
|
24
|
+
{{ $jx3boxT("jx3boxUi.wikiComment.top", "置顶") }}
|
|
25
25
|
</span>
|
|
26
26
|
<span class="u-mark u-star" v-if="comment.is_star">
|
|
27
27
|
<i class="el-icon-star-on"></i>
|
|
28
|
-
精华
|
|
28
|
+
{{ $jx3boxT("jx3boxUi.wikiComment.star", "精华") }}
|
|
29
29
|
</span>
|
|
30
30
|
</div>
|
|
31
31
|
<p class="u-content" v-html="comment.content"></p>
|
|
@@ -38,9 +38,11 @@
|
|
|
38
38
|
class="u-reply"
|
|
39
39
|
@click="comment.reply_form.show = !comment.reply_form.show"
|
|
40
40
|
size="small"
|
|
41
|
+
:aria-expanded="true"
|
|
42
|
+
:aria-controls="`wiki-comment-reply-${comment.id}`"
|
|
41
43
|
>
|
|
42
44
|
<i class="el-icon-arrow-up"></i>
|
|
43
|
-
<span
|
|
45
|
+
<span>{{ $jx3boxT("jx3boxUi.wikiComment.collapse", "收起") }}</span>
|
|
44
46
|
</el-button>
|
|
45
47
|
<el-button
|
|
46
48
|
type="primary"
|
|
@@ -50,8 +52,10 @@
|
|
|
50
52
|
@click="comment.reply_form.show = !comment.reply_form.show"
|
|
51
53
|
icon="ChatDotRound"
|
|
52
54
|
size="small"
|
|
55
|
+
:aria-expanded="false"
|
|
56
|
+
:aria-controls="`wiki-comment-reply-${comment.id}`"
|
|
53
57
|
>
|
|
54
|
-
<span
|
|
58
|
+
<span>{{ $jx3boxT("jx3boxUi.wiki.reply", "回复") }}</span>
|
|
55
59
|
</el-button>
|
|
56
60
|
<template v-if="isEditor && !comment.parent_id">
|
|
57
61
|
<el-button
|
|
@@ -61,25 +65,43 @@
|
|
|
61
65
|
plain
|
|
62
66
|
:icon="comment.is_star ? 'StarFilled' : 'Star'"
|
|
63
67
|
size="small"
|
|
64
|
-
>{{
|
|
68
|
+
>{{
|
|
69
|
+
comment.is_star
|
|
70
|
+
? $jx3boxT("jx3boxUi.wikiComment.cancelStar", "取消加精")
|
|
71
|
+
: $jx3boxT("jx3boxUi.wikiComment.setStar", "加精")
|
|
72
|
+
}}</el-button
|
|
65
73
|
>
|
|
66
74
|
<el-button type="primary" class="u-reply" @click="onTop(comment)" plain icon="Top" size="small">{{
|
|
67
|
-
comment.is_top
|
|
75
|
+
comment.is_top
|
|
76
|
+
? $jx3boxT("jx3boxUi.wikiComment.cancelTop", "取消置顶")
|
|
77
|
+
: $jx3boxT("jx3boxUi.wikiComment.setTop", "置顶")
|
|
68
78
|
}}</el-button>
|
|
69
79
|
</template>
|
|
70
80
|
<!-- 更新时间 -->
|
|
71
81
|
<span class="u-time" v-text="ts2str(comment.updated)"></span>
|
|
72
82
|
</div>
|
|
73
83
|
<!-- 评论回复表单 -->
|
|
74
|
-
<div
|
|
75
|
-
|
|
84
|
+
<div
|
|
85
|
+
class="m-reply-form"
|
|
86
|
+
:id="`wiki-comment-reply-${comment.id}`"
|
|
87
|
+
v-if="comment.reply_form && comment.reply_form.show"
|
|
88
|
+
>
|
|
89
|
+
<textarea
|
|
90
|
+
class="u-reply-content"
|
|
91
|
+
v-model="comment.reply_form.content"
|
|
92
|
+
:aria-label="$jx3boxT('jx3boxUi.wiki.reply', '回复')"
|
|
93
|
+
></textarea>
|
|
76
94
|
<div class="u-author">
|
|
77
|
-
<span
|
|
78
|
-
<input
|
|
95
|
+
<span>{{ $jx3boxT("jx3boxUi.wiki.nickname", "昵称:") }}</span>
|
|
96
|
+
<input
|
|
97
|
+
v-model="comment.reply_form.user_nickname"
|
|
98
|
+
type="text"
|
|
99
|
+
:aria-label="$jx3boxT('jx3boxUi.wiki.nickname', '昵称:')"
|
|
100
|
+
/>
|
|
79
101
|
</div>
|
|
80
102
|
<el-button type="primary" class="u-submit" @click="create_comment(comment.reply_form, comment.id)">
|
|
81
103
|
<i class="el-icon-check"></i>
|
|
82
|
-
<span
|
|
104
|
+
<span>{{ $jx3boxT("jx3boxUi.common.submit", "提交") }}</span>
|
|
83
105
|
</el-button>
|
|
84
106
|
</div>
|
|
85
107
|
</div>
|
|
@@ -117,7 +139,10 @@ export default {
|
|
|
117
139
|
if (!app.create_comment) app = app.$parent;
|
|
118
140
|
if (!app.create_comment) {
|
|
119
141
|
this.$message({
|
|
120
|
-
message:
|
|
142
|
+
message: this.$jx3boxT(
|
|
143
|
+
"jx3boxUi.wikiComment.publishUnavailable",
|
|
144
|
+
"发布评论异常,请联系管理员"
|
|
145
|
+
),
|
|
121
146
|
type: "warning",
|
|
122
147
|
});
|
|
123
148
|
return;
|
|
@@ -132,7 +157,10 @@ export default {
|
|
|
132
157
|
if (!app.star_comment) app = app.$parent;
|
|
133
158
|
if (!app.star_comment) {
|
|
134
159
|
this.$message({
|
|
135
|
-
message:
|
|
160
|
+
message: this.$jx3boxT(
|
|
161
|
+
"jx3boxUi.wikiComment.actionUnavailable",
|
|
162
|
+
"操作异常,请联系管理员"
|
|
163
|
+
),
|
|
136
164
|
type: "warning",
|
|
137
165
|
});
|
|
138
166
|
return;
|
|
@@ -144,7 +172,10 @@ export default {
|
|
|
144
172
|
if (!app.top_comment) app = app.$parent;
|
|
145
173
|
if (!app.top_comment) {
|
|
146
174
|
this.$message({
|
|
147
|
-
message:
|
|
175
|
+
message: this.$jx3boxT(
|
|
176
|
+
"jx3boxUi.wikiComment.actionUnavailable",
|
|
177
|
+
"操作异常,请联系管理员"
|
|
178
|
+
),
|
|
148
179
|
type: "warning",
|
|
149
180
|
});
|
|
150
181
|
return;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<WikiPanel class="c-wiki-comments" scene="detail">
|
|
2
|
+
<WikiPanel class="c-wiki-comments" scene="detail" :variant="variant">
|
|
3
3
|
<template #head-title>
|
|
4
4
|
<i class="u-icon el-icon-chat-line-round"></i>
|
|
5
5
|
<span class="u-txt">{{ $jx3boxT('jx3boxUi.wikiComments.title', '百科评论') }}</span>
|
|
@@ -29,10 +29,18 @@
|
|
|
29
29
|
<i class="el-icon-chat-dot-round"></i>
|
|
30
30
|
<span>{{ $jx3boxT('jx3boxUi.wiki.reply', '回复') }}</span>
|
|
31
31
|
</h4>
|
|
32
|
-
<textarea
|
|
32
|
+
<textarea
|
|
33
|
+
class="u-reply-content"
|
|
34
|
+
v-model="reply_form.content"
|
|
35
|
+
:aria-label="$jx3boxT('jx3boxUi.wiki.reply', '回复')"
|
|
36
|
+
></textarea>
|
|
33
37
|
<div class="u-author">
|
|
34
38
|
<span>{{ $jx3boxT('jx3boxUi.wiki.nickname', '昵称:') }}</span>
|
|
35
|
-
<input
|
|
39
|
+
<input
|
|
40
|
+
v-model="reply_form.user_nickname"
|
|
41
|
+
type="text"
|
|
42
|
+
:aria-label="$jx3boxT('jx3boxUi.wiki.nickname', '昵称:')"
|
|
43
|
+
/>
|
|
36
44
|
</div>
|
|
37
45
|
<el-button type="primary" class="u-submit" @click="create_comment(reply_form)">
|
|
38
46
|
<i class="el-icon-check"></i>
|
|
@@ -61,6 +69,11 @@ export default {
|
|
|
61
69
|
type: [Number, String],
|
|
62
70
|
default: 0,
|
|
63
71
|
},
|
|
72
|
+
variant: {
|
|
73
|
+
type: String,
|
|
74
|
+
default: "default",
|
|
75
|
+
validator: (value) => ["default", "surface", "plain"].includes(value),
|
|
76
|
+
},
|
|
64
77
|
},
|
|
65
78
|
data() {
|
|
66
79
|
return {
|
|
@@ -163,7 +176,9 @@ export default {
|
|
|
163
176
|
});
|
|
164
177
|
},
|
|
165
178
|
getDefaultNickname() {
|
|
166
|
-
return User.isLogin()
|
|
179
|
+
return User.isLogin()
|
|
180
|
+
? User.getInfo().name
|
|
181
|
+
: this.$jx3boxT("jx3boxUi.wiki.mysterious", "神秘侠士");
|
|
167
182
|
},
|
|
168
183
|
handleCurrentChange(page) {
|
|
169
184
|
this.page = page;
|
package/src/wiki/WikiPanel.vue
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div
|
|
3
3
|
class="c-wiki-panel"
|
|
4
|
-
:class="
|
|
5
|
-
border: border,
|
|
6
|
-
}"
|
|
4
|
+
:class="rootClasses"
|
|
7
5
|
>
|
|
8
6
|
<div class="m-panel-head">
|
|
9
7
|
<slot name="head-before"></slot>
|
|
@@ -11,7 +9,13 @@
|
|
|
11
9
|
<slot name="head-title"></slot>
|
|
12
10
|
</div>
|
|
13
11
|
<div class="m-panel-actions">
|
|
14
|
-
<QRcode
|
|
12
|
+
<QRcode
|
|
13
|
+
v-if="wikiPost && showQR"
|
|
14
|
+
class="u-qr"
|
|
15
|
+
:trigger-text="$jx3boxT('jx3boxUi.wikiPanel.qrTrigger', '二维码')"
|
|
16
|
+
:popup-text="$jx3boxT('jx3boxUi.wikiPanel.qrScanToVisit', '扫一扫即可访问')"
|
|
17
|
+
popup-class="u-wiki-panel-qrcode-popup"
|
|
18
|
+
/>
|
|
15
19
|
<slot name="head-actions"></slot>
|
|
16
20
|
</div>
|
|
17
21
|
<slot name="head-after"></slot>
|
|
@@ -72,6 +76,11 @@ export default {
|
|
|
72
76
|
type: String,
|
|
73
77
|
default: "default",
|
|
74
78
|
},
|
|
79
|
+
variant: {
|
|
80
|
+
type: String,
|
|
81
|
+
default: "default",
|
|
82
|
+
validator: (value) => ["default", "surface", "plain"].includes(value),
|
|
83
|
+
},
|
|
75
84
|
border: {
|
|
76
85
|
type: Boolean,
|
|
77
86
|
default: true,
|
|
@@ -86,6 +95,15 @@ export default {
|
|
|
86
95
|
stat: null,
|
|
87
96
|
};
|
|
88
97
|
},
|
|
98
|
+
computed: {
|
|
99
|
+
rootClasses() {
|
|
100
|
+
return {
|
|
101
|
+
border: this.border,
|
|
102
|
+
[`is-${this.variant}`]: true,
|
|
103
|
+
[`is-scene-${this.scene}`]: true,
|
|
104
|
+
};
|
|
105
|
+
},
|
|
106
|
+
},
|
|
89
107
|
watch: {
|
|
90
108
|
wikiPost: {
|
|
91
109
|
immediate: true,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<template>
|
|
2
|
-
<WikiPanel class="c-wiki-revisions" scene="detail">
|
|
2
|
+
<WikiPanel class="c-wiki-revisions" scene="detail" :variant="variant">
|
|
3
3
|
<template #head-title>
|
|
4
4
|
<i class="u-icon el-icon-time"></i>
|
|
5
5
|
<span class="u-txt">{{ $jx3boxT('jx3boxUi.wikiRevisions.title', '历史版本') }}</span>
|
|
@@ -62,6 +62,11 @@ export default {
|
|
|
62
62
|
type: [Boolean, Number],
|
|
63
63
|
default: false,
|
|
64
64
|
},
|
|
65
|
+
variant: {
|
|
66
|
+
type: String,
|
|
67
|
+
default: "default",
|
|
68
|
+
validator: (value) => ["default", "surface", "plain"].includes(value),
|
|
69
|
+
},
|
|
65
70
|
},
|
|
66
71
|
data: function () {
|
|
67
72
|
return {
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
const assert = require("node:assert/strict");
|
|
2
|
+
const test = require("node:test");
|
|
3
|
+
|
|
4
|
+
require("@babel/register")({
|
|
5
|
+
babelrc: false,
|
|
6
|
+
configFile: false,
|
|
7
|
+
extensions: [".js"],
|
|
8
|
+
ignore: [/node_modules/],
|
|
9
|
+
plugins: ["@babel/plugin-transform-modules-commonjs"],
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const {
|
|
13
|
+
createJx3boxUiI18n,
|
|
14
|
+
getJx3boxUiMessages,
|
|
15
|
+
mergeJx3boxUiMessages,
|
|
16
|
+
setJx3boxUiI18n,
|
|
17
|
+
} = require("../i18n");
|
|
18
|
+
const i18nMixin = require("../i18n/mixin").default;
|
|
19
|
+
const { createI18n } = require("vue-i18n");
|
|
20
|
+
|
|
21
|
+
const TARGET_PREFIXES = [
|
|
22
|
+
"wiki.",
|
|
23
|
+
"wikiPanel.",
|
|
24
|
+
"wikiComments.",
|
|
25
|
+
"wikiComment.",
|
|
26
|
+
"wikiRevisions.",
|
|
27
|
+
"gamePrice.",
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
function flattenMessages(value, prefix = "", output = {}) {
|
|
31
|
+
Object.entries(value || {}).forEach(([key, child]) => {
|
|
32
|
+
const path = prefix ? `${prefix}.${key}` : key;
|
|
33
|
+
if (child && typeof child === "object" && !Array.isArray(child)) {
|
|
34
|
+
flattenMessages(child, path, output);
|
|
35
|
+
} else {
|
|
36
|
+
output[path] = child;
|
|
37
|
+
}
|
|
38
|
+
});
|
|
39
|
+
return output;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function placeholders(value) {
|
|
43
|
+
return [...String(value ?? "").matchAll(/\{(\w+)\}/g)].map((match) => match[1]).sort();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
test("loads the target component messages for each supported locale", () => {
|
|
47
|
+
const messages = getJx3boxUiMessages();
|
|
48
|
+
Object.entries(messages).forEach(([locale, message]) => {
|
|
49
|
+
const flattened = flattenMessages(message);
|
|
50
|
+
TARGET_PREFIXES.forEach((prefix) => {
|
|
51
|
+
assert.ok(
|
|
52
|
+
Object.keys(flattened).some((key) => key.startsWith(prefix)),
|
|
53
|
+
`${locale} is missing ${prefix}`
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const i18n = createJx3boxUiI18n({ locale: "en-US" });
|
|
59
|
+
assert.equal(i18n.global.t("jx3boxUi.wikiComment.setTop"), "Pin");
|
|
60
|
+
assert.equal(i18n.global.t("jx3boxUi.wikiPanel.qrTrigger"), "QR code");
|
|
61
|
+
assert.equal(i18n.global.t("jx3boxUi.wikiPanel.qrScanToVisit"), "Scan to open this page");
|
|
62
|
+
assert.equal(i18n.global.t("jx3boxUi.gamePrice.jin"), "gold");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
test("merges target messages into a host i18n instance", () => {
|
|
66
|
+
const hostI18n = createI18n({
|
|
67
|
+
legacy: false,
|
|
68
|
+
locale: "en-US",
|
|
69
|
+
fallbackLocale: "zh-CN",
|
|
70
|
+
messages: {
|
|
71
|
+
"en-US": {
|
|
72
|
+
host: {
|
|
73
|
+
title: "Host",
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
mergeJx3boxUiMessages(hostI18n);
|
|
80
|
+
setJx3boxUiI18n(hostI18n);
|
|
81
|
+
|
|
82
|
+
assert.equal(hostI18n.global.t("host.title"), "Host");
|
|
83
|
+
assert.equal(hostI18n.global.t("jx3boxUi.wikiComments.title"), "Wiki Comments");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
test("component mixin keeps the explicit fallback when the host misses a key", () => {
|
|
87
|
+
setJx3boxUiI18n(null);
|
|
88
|
+
const context = {
|
|
89
|
+
$t(key) {
|
|
90
|
+
return key;
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
assert.equal(
|
|
95
|
+
i18nMixin.methods.$jx3boxT.call(context, "jx3boxUi.missing.example", "欢迎 {name}", { name: "侠士" }),
|
|
96
|
+
"欢迎 侠士"
|
|
97
|
+
);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("keeps four locale message keys and placeholders aligned", () => {
|
|
101
|
+
const messages = getJx3boxUiMessages();
|
|
102
|
+
const locales = Object.keys(messages);
|
|
103
|
+
const baseline = flattenMessages(messages["zh-CN"]);
|
|
104
|
+
const baselineKeys = Object.keys(baseline).sort();
|
|
105
|
+
|
|
106
|
+
locales.forEach((locale) => {
|
|
107
|
+
const current = flattenMessages(messages[locale]);
|
|
108
|
+
assert.deepEqual(Object.keys(current).sort(), baselineKeys, `${locale} message keys differ from zh-CN`);
|
|
109
|
+
baselineKeys.forEach((key) => {
|
|
110
|
+
assert.deepEqual(placeholders(current[key]), placeholders(baseline[key]), `${locale}:${key} placeholders differ`);
|
|
111
|
+
});
|
|
112
|
+
});
|
|
113
|
+
});
|